Python 一句话代码技巧(一)
文章目录
我还在学习 CTF 时,我接触到了一些 Python 的有趣特性,例如使用 NFKC 进行沙箱逃逸以及 Python 存储对象时的一些机制。最近我对 Python 的“一句话代码”产生了兴趣,具体来说就是使用一些特别的 Python 编程技巧以及语法糖将大段代码压缩到一行或少数几行中,用几行短短的代码(但是每一行都会很长)实现一个完整的功能。例如说下面这三行代码分别时冒泡排序、选择排序和插入排序算法的“一句话代码”形式。
1print((bubble_sort := lambda lst: ([(tmp := lst.__getitem__(i), lst.__setitem__(i, lst.__getitem__(j)), lst.__setitem__(j, tmp), None)[-1] for i in range(len(lst) - 1) for j in range(i, len(lst)) if lst[j] < lst[i]] + lst)[-len(lst):])([int(i) for i in input().split()]))
2# 冒泡排序
3
4print((selection_sort := lambda lst: ([(index := i, j := i + 1, index := (my_while := lambda index, lst, j: my_while(index := j if lst[j] < lst[index] else index, lst, j := j + 1) if j < len(lst) else index)(index, lst, j), tmp := lst.__getitem__(i), lst.__setitem__(i, lst.__getitem__(index)), lst.__setitem__(index, tmp), None) for i in range(len(lst) - 1)] + lst)[-len(lst):])([int(i) for i in input().split()]))
5# 选择排序
6
7print((insertion_sort := lambda lst: ([(key := lst.__getitem__(i), j := i - 1, j := (my_while := lambda j, key, lst: (lst.__setitem__(j + 1, lst.__getitem__(j)), j := j - 1, my_while(j, key, lst))[-1] if j >= 0 and lst[j] > key else j)(j, key, lst), lst.__setitem__(j + 1, key), None)[-1] for i in range(1, len(lst))] + lst)[-len(lst):])([int(i) for i in input().split()]))
8# 插入排序
下面这一段代码是我曾经的一次 OOP 编程作业,正常写出来的代码是这样的(以前知识储备不够,现在看上去这段代码有很多可以优化的部分):
1class Book:
2
3 def __init__(self, code, title, status=True):
4 self.__code = code
5 self.__title = title
6 self.__status = status
7
8 def get_book_code(self):
9 return self.__code
10
11 def get_book_title(self):
12 return self.__title
13
14 def is_available(self):
15 return self.__status
16
17 def borrow_book(self):
18 self.__status = False
19
20 def return_book(self):
21 self.__status = True
22
23 def __str__(self):
24 return f"{self.__title}, {self.__code} ({['Available' if self.is_available() else 'On Loan'][0]})"
25
26
27class Member:
28
29 def __init__(self, member_id, name, on_loan_books_list=None):
30 self.__member_id = member_id
31 self.__name = name
32 if on_loan_books_list is None:
33 self.__on_loan_books_list = list()
34 else:
35 self.__on_loan_books_list = on_loan_books_list
36
37 def get_name(self):
38 return self.__name
39
40 def get_member_id(self):
41 return self.__member_id
42
43 def get_on_loan_books(self):
44 return self.__on_loan_books_list
45
46 def borrow_book(self, book):
47 self.__on_loan_books_list.append(book.get_book_title())
48 book.borrow_book()
49
50 def return_book(self, book):
51 self.__on_loan_books_list.remove(book.get_book_title())
52 book.return_book()
53
54 def __str__(self):
55 return "{}\nOn loan book(s):\n{}".format(
56 self.__name,
57 [
58 (
59 "\n".join(self.__on_loan_books_list)
60 if len(self.__on_loan_books_list) > 0
61 else "-"
62 )
63 ][0],
64 )
65
66
67class Record:
68
69 def __init__(self, book, member, issue_date, is_on_loan=True):
70 self.__book = book
71 self.__member = member
72 self.__issue_date = issue_date
73 self.__is_on_loan = is_on_loan
74 self.__member.borrow_book(self.__book)
75
76 def get_member_id(self):
77 return self.__member.get_member_id()
78
79 def get_book_code(self):
80 return self.__book.get_book_code()
81
82 def get_issue_date(self):
83 return self.__issue_date
84
85 def is_on_loan(self):
86 return self.__is_on_loan
87
88 def return_book(self):
89 self.__member.return_book(self.__book)
90 self.__is_on_loan = False
91
92 def __str__(self):
93 member_name = self.__member.get_name()
94 book_title = self.__book.get_book_title()
95 book_code = self.__book.get_book_code()
96 book_status = ["Available" if self.__book.is_available() else "On Loan"][0]
97 issue_date = self.get_issue_date()
98 return f"{member_name}, {book_title}, {book_code} ({book_status}), issued date={issue_date}"
99
100 def get_member_name(self):
101 return self.__member.get_name()
102
103 def get_book_title(self):
104 return self.__book.get_book_title()
105
106
107class MyLibrary:
108
109 def __init__(self, books_list_file_path, on_loan_records_list=None):
110 try:
111 with open(books_list_file_path, "r") as books_list_file:
112 self.__books_list = books_list_file.readlines()
113 except FileNotFoundError:
114 print(f"ERROR: The file '{books_list_file_path}' does not exist.")
115 exit(-1)
116
117 self.__books_list_with_class = list()
118 for book_string in self.__books_list:
119 book_code = book_string.split(",")[0]
120 book_title = book_string.split(",")[1]
121 self.__books_list_with_class.append(
122 Book(book_code, "".join(book_title.split("\n")))
123 )
124 print(f"{len(self.__books_list_with_class)} books loaded.")
125
126 if on_loan_records_list is None:
127 self.__on_loan_records_list = list()
128 else:
129 self.__on_loan_records_list = on_loan_records_list
130
131 self.__all_records_list = list()
132
133 def show_all_books(self):
134 books_information = []
135 for book in self.__books_list_with_class:
136 book_title = book.get_book_title()
137 book_code = book.get_book_code()
138 book_status = ["Available" if book.is_available() else "On Loan"][0]
139 books_information.append(f"{book_title}, {book_code} ({book_status})")
140 print("\n".join(books_information))
141
142 def find_book(self, code):
143 find = False
144 for book in self.__books_list_with_class:
145 if code == book.get_book_code():
146 find = True
147 if book.is_available():
148 return book
149 else:
150 return None
151 if not find:
152 return None
153
154 def borrow_book(self, book: Book, member: Member, issue_date):
155 if book is None:
156 print("ERROR: could not issue the book.")
157 elif book.is_available():
158 self.__all_records_list.append(Record(book, member, issue_date))
159 self.__on_loan_records_list.append(self.__all_records_list[-1])
160 book_title = book.get_book_title()
161 member_name = member.get_name()
162 print(f"{book_title} is borrowed by {member_name}.")
163
164 def show_available_books(self):
165 for book in self.__books_list_with_class:
166 if book.get_book_code() not in [
167 record.get_book_code() for record in self.__on_loan_records_list
168 ]:
169 print(book)
170
171 def find_record(self, code):
172 for record in self.__on_loan_records_list:
173 if record.get_book_code() == code and record.is_on_loan():
174 return record
175 return None
176
177 def return_book(self, record: Record):
178 if record is None:
179 print("ERROR: could not return the book.")
180 elif record.is_on_loan():
181 record_index = self.__all_records_list.index(record)
182 self.__all_records_list[record_index].return_book()
183 self.__all_records_list[record_index] = record
184 self.__on_loan_records_list.remove(record)
185 print(f"{record.get_book_code()} is returned successfully.")
186
187 def show_on_loan_records(self):
188 for record in self.__on_loan_records_list:
189 member_name = record.get_member_name()
190 book_title = record.get_book_title()
191 book_code = record.get_book_code()
192 book_issue_date = record.get_issue_date()
193 print(
194 f"{member_name}, {book_title}, {book_code} (On Loan), issued date={book_issue_date}"
195 )
196
197 def show_all_records(self):
198 for record in self.__all_records_list:
199 member_name = record.get_member_name()
200 book_title = record.get_book_title()
201 book_code = record.get_book_code()
202 book_issue_date = record.get_issue_date()
203 book_status = ["On Loan" if record.is_on_loan() else "Available"][0]
204 print(
205 f"{member_name}, {book_title}, {book_code} ({book_status}), issued date={book_issue_date}"
206 )
这段代码实现了一个简易的图书管理系统,有增删改查的功能。下面是把这段代码以及测试样例压缩到一行的样子:
1(lambda Book, Member, Record, MyLibrary: (library := MyLibrary("simple_books.txt"), m1 := Member(1001, "Michael"), library.borrow_book(library.find_book("QS12.02.003"), m1, "2020-08-12"), library.borrow_book(library.find_book("QK12.04.002"), m1, "2020-08-15"), library.show_on_loan_records(), ))(Book := type("Book", (), {"__init__": lambda self, code, title, status=True: (setattr(self, "_Book__code", code), setattr(self, "_Book__title", title), setattr(self, "_Book__status", status), None, )[-1], "get_book_code": lambda self: getattr(self, "_Book__code"), "get_book_title": lambda self: getattr(self, "_Book__title"), "is_available": lambda self: getattr(self, "_Book__status"), "borrow_book": lambda self: (setattr(self, "_Book__status", False), None)[-1], "return_book": lambda self: (setattr(self, "_Book__status", True), None)[-1], "__str__": lambda self: "{}, {} ({})".format(self.get_book_title(), self.get_book_code(), "Available" if self.is_available() else "On Loan", ), }, ), type("Member", (), {"__init__": lambda self, member_id, name, on_loan_books_list=None: (setattr(self, "_Member__member_id", member_id), setattr(self, "_Member__name", name), setattr(self, "_Member__on_loan_books_list", on_loan_books_list if on_loan_books_list else list(), ), None, )[-1], "get_name": lambda self: getattr(self, "_Member__name"), "get_member_id": lambda self: getattr(self, "_Member__member_id"), "get_on_loan_books": lambda self: getattr(self, "_Member__on_loan_books_list"), "borrow_book": lambda self, book: (self._Member__on_loan_books_list.append(book.get_book_title()), book.borrow_book(), None, )[-1], "return_book": lambda self, book: (self._Member__on_loan_books_list.remove(book.get_book_title()), book.return_book(), None, )[-1], "__str__": lambda self: "{}\nOn loan book(s):\n{}".format(self.get_name(), ("\n".join(self.get_on_loan_books()) if len(self.get_on_loan_books()) > 0 else "-"), ), }, ), Record := type("Record", (), {"__init__": lambda self, book, member, issue_date, is_on_loan=True: (setattr(self, "_Record__book", book), setattr(self, "_Record__member", member), setattr(self, "_Record__issue_date", issue_date), setattr(self, "_Record__is_on_loan", is_on_loan), self._Record__member.borrow_book(self._Record__book), None, )[-1], "get_member_id": lambda self: self._Record__member.get_member_id(), "get_book_code": lambda self: self._Record__book.get_book_code(), "get_issue_date": lambda self: getattr(self, "_Record__issue_date"), "is_on_loan": lambda self: getattr(self, "_Record__is_on_loan"), "return_book": lambda self: (self._Record__member.return_book(self._Record__book), None, )[-1], "get_member_name": lambda self: self._Record__member.get_name(), "get_book_title": lambda self: self._Record__book.get_book_title(), "__str__": lambda self: "{}, {}, {} ({}), issued date={}".format(self._Record__member.get_name(), self._Record__book.get_book_title(), self._Record__book.get_book_code(), "Available" if self._Record__book.is_available() else "On Loan", self.get_issue_date(), ), }, ), type("MyLibrary", (), {"__init__": lambda self, books_list_file_path, on_loan_records_list=None: ((setattr(self, "_MyLibrary__books_list", open(books_list_file_path, "r").read().splitlines(), ) if __import__("os").path.exists(books_list_file_path) else (print(f"ERROR: The file '{books_list_file_path}' does not exist."), __import__("sys").exit(-1), )), setattr(self, "_MyLibrary__books_list_with_class", [Book(*book.split(",")) for book in self._MyLibrary__books_list], ), print(f"{len(self._MyLibrary__books_list_with_class)} books loaded."), setattr(self, "_MyLibrary__on_loan_records_list", on_loan_records_list if on_loan_records_list else list(), ), None, )[-1], "show_all_books": lambda self: (print("\n".join("{}, {} ({})".format(book.get_book_title(), book.get_book_code(), "Available" if book.is_available() else "On Loan", ) for book in self._MyLibrary__books_list_with_class)), None, )[-1], "find_book": lambda self, code: next((book for book in self._MyLibrary__books_list_with_class if code == book.get_book_code() and book.is_available()), (None if any(code == book.get_book_code() for book in self._MyLibrary__books_list_with_class) else None), ), "borrow_book": lambda self, book, member, issue_date: ((print("ERROR: could not issue the book.") if book is None else ((self._MyLibrary__on_loan_records_list.append(Record(book, member, issue_date)), print(f"{book.get_book_title()} is borrowed by {member.get_name()}"), ) if book.is_available() else None)), None, )[-1], "show_available_books": lambda self: ((list(map(lambda book: print(book), filter(lambda book: book.get_book_code() not in [record.get_book_code() for record in self._MyLibrary__on_loan_records_list], self._MyLibrary__books_list_with_class, ), ))), None, )[-1], "find_record": lambda self, code: next((record for record in self._MyLibrary__on_loan_records_list if record.get_book_code() == code and record.is_on_loan()), None, ), "return_book": lambda self, record: (((print("ERROR: could not return the book.") if record is None else None) if not record.is_on_loan() else (record.return_book(), self._MyLibrary__on_loan_records_list.remove(record), print(f"{record.get_book_code()} is returned successfully."), )), None, )[-1], "show_on_loan_records": lambda self: (list(map(lambda record: print("{}, {}, {} (On Loan), issued date={}".format(record.get_member_name(), record.get_book_title(), record.get_book_code(), record.get_issue_date(), ), ), self._MyLibrary__on_loan_records_list, )), None, )[-1], }, ), )
这行代码一共有 5526 个字符,下面是把它格式化后的样子:
1(
2 lambda Book, Member, Record, MyLibrary: (
3 library := MyLibrary("simple_books.txt"),
4 m1 := Member(1001, "Michael"),
5 library.borrow_book(library.find_book("QS12.02.003"), m1, "2020-08-12"),
6 library.borrow_book(library.find_book("QK12.04.002"), m1, "2020-08-15"),
7 library.show_on_loan_records(),
8 )
9)(
10 Book := type(
11 "Book",
12 (),
13 {
14 "__init__": lambda self, code, title, status=True: (
15 setattr(self, "_Book__code", code),
16 setattr(self, "_Book__title", title),
17 setattr(self, "_Book__status", status),
18 None,
19 )[-1],
20 "get_book_code": lambda self: getattr(self, "_Book__code"),
21 "get_book_title": lambda self: getattr(self, "_Book__title"),
22 "is_available": lambda self: getattr(self, "_Book__status"),
23 "borrow_book": lambda self: (setattr(self, "_Book__status", False), None)[
24 -1
25 ],
26 "return_book": lambda self: (setattr(self, "_Book__status", True), None)[
27 -1
28 ],
29 "__str__": lambda self: "{}, {} ({})".format(
30 self.get_book_title(),
31 self.get_book_code(),
32 "Available" if self.is_available() else "On Loan",
33 ),
34 },
35 ),
36 type(
37 "Member",
38 (),
39 {
40 "__init__": lambda self, member_id, name, on_loan_books_list=None: (
41 setattr(self, "_Member__member_id", member_id),
42 setattr(self, "_Member__name", name),
43 setattr(
44 self,
45 "_Member__on_loan_books_list",
46 on_loan_books_list if on_loan_books_list else list(),
47 ),
48 None,
49 )[-1],
50 "get_name": lambda self: getattr(self, "_Member__name"),
51 "get_member_id": lambda self: getattr(self, "_Member__member_id"),
52 "get_on_loan_books": lambda self: getattr(
53 self, "_Member__on_loan_books_list"
54 ),
55 "borrow_book": lambda self, book: (
56 self._Member__on_loan_books_list.append(book.get_book_title()),
57 book.borrow_book(),
58 None,
59 )[-1],
60 "return_book": lambda self, book: (
61 self._Member__on_loan_books_list.remove(book.get_book_title()),
62 book.return_book(),
63 None,
64 )[-1],
65 "__str__": lambda self: "{}\nOn loan book(s):\n{}".format(
66 self.get_name(),
67 (
68 "\n".join(self.get_on_loan_books())
69 if len(self.get_on_loan_books()) > 0
70 else "-"
71 ),
72 ),
73 },
74 ),
75 Record := type(
76 "Record",
77 (),
78 {
79 "__init__": lambda self, book, member, issue_date, is_on_loan=True: (
80 setattr(self, "_Record__book", book),
81 setattr(self, "_Record__member", member),
82 setattr(self, "_Record__issue_date", issue_date),
83 setattr(self, "_Record__is_on_loan", is_on_loan),
84 self._Record__member.borrow_book(self._Record__book),
85 None,
86 )[-1],
87 "get_member_id": lambda self: self._Record__member.get_member_id(),
88 "get_book_code": lambda self: self._Record__book.get_book_code(),
89 "get_issue_date": lambda self: getattr(self, "_Record__issue_date"),
90 "is_on_loan": lambda self: getattr(self, "_Record__is_on_loan"),
91 "return_book": lambda self: (
92 self._Record__member.return_book(self._Record__book),
93 None,
94 )[-1],
95 "get_member_name": lambda self: self._Record__member.get_name(),
96 "get_book_title": lambda self: self._Record__book.get_book_title(),
97 "__str__": lambda self: "{}, {}, {} ({}), issued date={}".format(
98 self._Record__member.get_name(),
99 self._Record__book.get_book_title(),
100 self._Record__book.get_book_code(),
101 "Available" if self._Record__book.is_available() else "On Loan",
102 self.get_issue_date(),
103 ),
104 },
105 ),
106 type(
107 "MyLibrary",
108 (),
109 {
110 "__init__": lambda self, books_list_file_path, on_loan_records_list=None: (
111 (
112 setattr(
113 self,
114 "_MyLibrary__books_list",
115 open(books_list_file_path, "r").read().splitlines(),
116 )
117 if __import__("os").path.exists(books_list_file_path)
118 else (
119 print(
120 f"ERROR: The file '{books_list_file_path}' does not exist."
121 ),
122 __import__("sys").exit(-1),
123 )
124 ),
125 setattr(
126 self,
127 "_MyLibrary__books_list_with_class",
128 [Book(*book.split(",")) for book in self._MyLibrary__books_list],
129 ),
130 print(f"{len(self._MyLibrary__books_list_with_class)} books loaded."),
131 setattr(
132 self,
133 "_MyLibrary__on_loan_records_list",
134 on_loan_records_list if on_loan_records_list else list(),
135 ),
136 None,
137 )[-1],
138 "show_all_books": lambda self: (
139 print(
140 "\n".join(
141 "{}, {} ({})".format(
142 book.get_book_title(),
143 book.get_book_code(),
144 "Available" if book.is_available() else "On Loan",
145 )
146 for book in self._MyLibrary__books_list_with_class
147 )
148 ),
149 None,
150 )[-1],
151 "find_book": lambda self, code: next(
152 (
153 book
154 for book in self._MyLibrary__books_list_with_class
155 if code == book.get_book_code() and book.is_available()
156 ),
157 (
158 None
159 if any(
160 code == book.get_book_code()
161 for book in self._MyLibrary__books_list_with_class
162 )
163 else None
164 ),
165 ),
166 "borrow_book": lambda self, book, member, issue_date: (
167 (
168 print("ERROR: could not issue the book.")
169 if book is None
170 else (
171 (
172 self._MyLibrary__on_loan_records_list.append(
173 Record(book, member, issue_date)
174 ),
175 print(
176 f"{book.get_book_title()} is borrowed by {member.get_name()}"
177 ),
178 )
179 if book.is_available()
180 else None
181 )
182 ),
183 None,
184 )[-1],
185 "show_available_books": lambda self: (
186 (
187 list(
188 map(
189 lambda book: print(book),
190 filter(
191 lambda book: book.get_book_code()
192 not in [
193 record.get_book_code()
194 for record in self._MyLibrary__on_loan_records_list
195 ],
196 self._MyLibrary__books_list_with_class,
197 ),
198 )
199 )
200 ),
201 None,
202 )[-1],
203 "find_record": lambda self, code: next(
204 (
205 record
206 for record in self._MyLibrary__on_loan_records_list
207 if record.get_book_code() == code and record.is_on_loan()
208 ),
209 None,
210 ),
211 "return_book": lambda self, record: (
212 (
213 (
214 print("ERROR: could not return the book.")
215 if record is None
216 else None
217 )
218 if not record.is_on_loan()
219 else (
220 record.return_book(),
221 self._MyLibrary__on_loan_records_list.remove(record),
222 print(f"{record.get_book_code()} is returned successfully."),
223 )
224 ),
225 None,
226 )[-1],
227 "show_on_loan_records": lambda self: (
228 list(
229 map(
230 lambda record: print(
231 "{}, {}, {} (On Loan), issued date={}".format(
232 record.get_member_name(),
233 record.get_book_title(),
234 record.get_book_code(),
235 record.get_issue_date(),
236 ),
237 ),
238 self._MyLibrary__on_loan_records_list,
239 )
240 ),
241 None,
242 )[-1],
243 },
244 ),
245)
作为一门缩进敏感的语言,试图将 Python 代码是颇具挑战性的。下面我介绍一些能够压缩 Python 代码行数(但是会拓宽列数)的技巧。
使用分号在同一行内写多个语句
例如对于下面两行代码:
1s = "Hello,"
2print(f"{s} World!")
3
4# output: Hello, World!
我们可以写成
1s = "Hello,"; print(f"{s} World!")
2
3# output: Hello, World!
上面两部分代码的功能完全一样。不过使用分号在一行内写多个语句也有局限性,诸如条件语句、循环语句等部分带有关键字的语句无法使用分号。例如下面这段代码:
1value = 7
2count = 0
3lst = [1, 1, 4, 5, 1, 4, 1, 9, 1, 9, 8, 10]
4for i in lst:
5 if i > value:
6 count += 1
7print(count)
8
9# output: 4
就不能直接写成
1value = 7; count = 0; lst = [1, 1, 4, 5, 1, 4, 1, 9, 1, 9, 8, 10]; for i in lst: if i > value: count += 1; print(count)
2
3# STDERR: SyntaxError: invalid syntax
当然,将上面代码压缩至一行的方法我们稍后会提。
使用 exec()
函数
作为一门解释性语言,Python 允许我们将代码写进一个字符串并且执行,例如说:
1exec("for i in range(13):\n\tprint(i)")
这一行代码一次输出 1 到 12。根据这个原理,我们可以将任何一大段脚本内所有的换行、缩进转换为转义字符,随后将这个字符串作为参数执行 exec()
函数即可。
前面提到的两种方法,单独使用时并没有很高的技术含量,只是将原来代码的格式略微改变一下,下面我将介绍几种更具有技术力的“一句话代码”技巧。
三元表达式(一句话 if-else
语句)
Python 中 if
语句的定义如下:
1if_stmt ::= "if" assignment_expression ":" suite
2 ("elif" assignment_expression ":" suite)*
3 ["else" ":" suite]
一般情况下使用方法如下:
1if assignment_expression_A:
2 suite_A
3elif assignment_expression_B:
4 suite_B
5elif assignment_expression_C:
6 suite_C
7else:
8 suite_D
将其写为一行后就是:
1siute_A if assignment_expression_A else suite_B if assignment_expression_B else suite_C if assignment_expression_C else suite_D
其中 elif 的部分可以无限叠加。但是一句话格式下必须有 else
关键字,如果原代码中没有 else
部分,则在一句话格式下在 else
后使用缺省值,一般是 None
或者任何具用于表示“无”的数据。
我们举几个例子:
1a = 13
2b = 33
3if a > b:
4 max_value = a
5else:
6 max_value = b
7print(max_value)
8
9# output: 33
改写条件语句的部分
1a = 13
2b = 33
3print(a if a > b else b)
4
5# output: 33
如果我们再给原代码加上判断是否相等的部分
1a = 13
2b = 33
3if a > b:
4 print(f"{a} is greater.")
5elif a < b:
6 print(f"{b} is greater.")
7else:
8 print(f"They are equal.")
9
10# output: 33 is greater.
这段代码则可以改写成
1a = 13; b = 33; print(f"{a} is greater.") if a > b else print(f"{b} is greater.") if a < b else print(f"They are equal.")
2
3# output: 33 is greater.
推导式 for
Python 中的推导式分为列表推导式、字典推导式、集合推导式和生成器表达式(亦称作元组推导式),他们的语法类似,最大的区别就是生成不同的对象。这四种推导式分别生成列表、字典、集合和生成器对象。
列表推导式基本语法为:
1[out_exp_res for out_exp in input_list]
2# 或者
3[out_exp_res for out_exp in input_list if condition]
4# if 语句要放在最后
集合推导式、生成器表达式只是分别将其中的中括号换为了大括号和小括号。而字典推导式的基本语法为:
1{key_expr: value_expr for value in collection}
2# 或者
3{key_expr: value_expr for value in collection if condition}
4# if 永远后置
例如说对于下面这段用于找出列表中大于指定值的数字的代码:
1value = 7
2result = []
3numbers = [1, 1, 4, 5, 1, 4, 1, 9, 1, 9, 8, 10]
4for i in numbers:
5 if i > value:
6 result.append(i)
7print(result)
8
9# output: [9, 9, 8, 10]
我们可以使用列表推导式完成这个任务:
1value = 7
2numbers = [1, 1, 4, 5, 1, 4, 1, 9, 1, 9, 8, 10]
3result = [i for i in number if i > value]
4print(result)
5
6# output: [9, 9, 8, 10]
推导式还支持循环嵌套。例如说下面这个集合推导式可以用于求两个集合的 Cartesian product:
1cartesian_product = {(x, y) for x in {1, 3, 5} for y in {0, 2, 4}}
2print(cartesian_product)
3
4# output: {(1, 2), (3, 4), (5, 4), (1, 4), (3, 0), (5, 0), (1, 0), (3, 2), (5, 2)}
我们还可以使用 Cantor pairing 将这些有序数对存储到字典里:
1cantor_pairing = {(x + y) * (x + y + 1) // 2 + y: (x, y) for (x, y) in {(x, y) for x in {1, 3, 5} for y in {0, 2, 4}}}
2print(cantor_pairing)
3
4# output: {8: (1, 2), 32: (3, 4), 49: (5, 4), 19: (1, 4), 6: (3, 0), 15: (5, 0), 1: (1, 0), 17: (3, 2), 30: (5, 2)}
这里在字典推导式中嵌套了集合推导式。