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)}

这里在字典推导式中嵌套了集合推导式。

相关系列文章