Tôi nhận được cảnh báo pep8 này bất cứ khi nào tôi sử dụng biểu thức lambda. Là biểu thức lambda không được khuyến khích? Nếu không tại sao?
Tôi nhận được cảnh báo pep8 này bất cứ khi nào tôi sử dụng biểu thức lambda. Là biểu thức lambda không được khuyến khích? Nếu không tại sao?
Câu trả lời:
Đề xuất trong PEP-8 bạn đang sử dụng là:
Luôn sử dụng câu lệnh def thay vì câu lệnh gán liên kết trực tiếp biểu thức lambda với tên.
Đúng:
def f(x): return 2*x
Không:
f = lambda x: 2*x
Biểu mẫu đầu tiên có nghĩa là tên của đối tượng hàm kết quả cụ thể là 'f' thay vì tên chung '<lambda>'. Điều này hữu ích hơn cho tracebacks và biểu diễn chuỗi nói chung. Việc sử dụng câu lệnh gán sẽ loại bỏ lợi ích duy nhất mà biểu thức lambda có thể cung cấp cho câu lệnh def rõ ràng (nghĩa là nó có thể được nhúng bên trong một biểu thức lớn hơn)
Việc gán lambdas cho các tên về cơ bản chỉ là sao chép chức năng của def
- và nói chung, tốt nhất là làm một cách duy nhất để tránh nhầm lẫn và tăng độ rõ ràng.
Trường hợp sử dụng hợp pháp cho lambda là nơi bạn muốn sử dụng hàm mà không gán nó, ví dụ:
sorted(players, key=lambda player: player.rank)
Nói chung, đối số chính chống lại việc này là các def
câu lệnh sẽ dẫn đến nhiều dòng mã hơn. Phản ứng chính của tôi cho điều đó sẽ là: có, và điều đó là tốt. Trừ khi bạn đang chơi golf, giảm thiểu số lượng dòng không phải là điều bạn nên làm: hãy giải thích rõ ràng.
def
qua trình kiểm tra PEP8, bạn sẽ nhận được E704 multiple statements on one line (def)
và nếu bạn chia nó thành hai dòng bạn nhận được E301 expected 1 blank line, found 0
: - /
Đây là câu chuyện, tôi có một chức năng lambda đơn giản mà tôi đã sử dụng hai lần.
a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
Đây chỉ là đại diện, tôi đã phải đối mặt với một vài phiên bản khác nhau của điều này.
Bây giờ, để giữ mọi thứ KHÔ, tôi bắt đầu sử dụng lại lambda thông thường này.
f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Tại thời điểm này, trình kiểm tra chất lượng mã của tôi phàn nàn về lambda là một hàm được đặt tên nên tôi chuyển đổi nó thành một hàm.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Bây giờ trình kiểm tra phàn nàn rằng một hàm phải được giới hạn bởi một dòng trống trước và sau.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Bây giờ chúng ta có 6 dòng mã thay vì 2 dòng ban đầu mà không tăng khả năng đọc và không tăng pythonic. Tại thời điểm này, trình kiểm tra mã phàn nàn về chức năng không có tài liệu.
Theo tôi quy tắc này tốt hơn nên tránh và phá vỡ khi nó có ý nghĩa, sử dụng phán đoán của bạn.
a = [x + offset for x in simple_list]
. Không cần sử dụng map
và lambda
ở đây.
x + offset
phần đến một vị trí trừu tượng có thể được cập nhật mà không thay đổi nhiều hơn một dòng mã. Với việc hiểu danh sách như bạn đã đề cập, bạn vẫn sẽ cần hai dòng mã chứa x + offset
chúng bây giờ sẽ nằm trong danh sách hiểu. Để kéo chúng ra như tác giả muốn, bạn sẽ cần một def
hoặc lambda
.
def
và lambda
người ta cũng có thể sử dụng funcools.partial : f = partial(operator.add, offset)
và sau đó a = list(map(f, simple_list))
.
def f(x): return x + offset
(nghĩa là một hàm đơn giản được xác định trên một dòng)? Ít nhất với flake8 tôi không nhận được khiếu nại về các dòng trống.
a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
Lattyware hoàn toàn đúng: Về cơ bản PEP-8 muốn bạn tránh những thứ như
f = lambda x: 2 * x
và thay vào đó sử dụng
def f(x):
return 2 * x
Tuy nhiên, như được đề cập trong một bugreport gần đây (tháng 8 năm 2014), các câu lệnh như sau đây hiện tuân thủ:
a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x
Vì trình kiểm tra PEP-8 của tôi chưa thực hiện chính xác điều này, tôi đã tắt E731 trong thời gian này.
def
, trình kiểm tra PEP8 vẫn phàn nàn E301 expected 1 blank line, found 0
, do đó bạn phải thêm một dòng trống xấu xí trước nó.
Tôi cũng gặp phải một tình huống trong đó thậm chí không thể sử dụng hàm def (ined).
class SomeClass(object):
# pep-8 does not allow this
f = lambda x: x + 1 # NOQA
def not_reachable(self, x):
return x + 1
@staticmethod
def also_not_reachable(x):
return x + 1
@classmethod
def also_not_reachable(cls, x):
return x + 1
some_mapping = {
'object1': {'name': "Object 1", 'func': f},
'object2': {'name': "Object 2", 'func': some_other_func},
}
Trong trường hợp này, tôi thực sự muốn tạo một bản đồ thuộc về lớp. Một số đối tượng trong ánh xạ cần chức năng tương tự. Sẽ là phi logic khi đặt một hàm được đặt tên bên ngoài lớp. Tôi chưa tìm thấy cách nào để tham khảo một phương thức (staticmethod, classmethod hoặc normal) từ bên trong thân lớp. Một sốClass chưa tồn tại khi mã được chạy. Vì vậy, đề cập đến nó từ lớp học là không thể.
also_not_reachable
trong định nghĩa ánh xạ làSomeClass.also_not_reachable
f
trong cả 2.7 và 3.5 đối với tôi
@staticmethod
và @classmethod
không cần một đối tượng, chỉ SomeClass.also_not_reachable
(mặc dù họ cần tên đặc biệt). Nếu bạn cần truy cập chúng từ các phương thức lớp, chỉ cần sử dụngself.also_not_reachable
*not_reachable
phương thức của mình thành not_as_easily_reachable_from_class_definition_as_a_lambda
xD
flake8
( flake8.pycqa.org )