Cái nào được ưu tiên sử dụng hơn: hàm lambda hay hàm lồng nhau ('def')?


101

Tôi chủ yếu sử dụng các hàm lambda nhưng đôi khi sử dụng các hàm lồng nhau dường như cung cấp cùng một hành vi.

Dưới đây là một số ví dụ đơn giản trong đó chúng có chức năng hoạt động tương tự nếu một trong hai được tìm thấy trong một hàm khác:

Hàm lambda

>>> a = lambda x : 1 + x
>>> a(5)
6

Hàm lồng nhau

>>> def b(x): return 1 + x

>>> b(5)
6

Có lợi thế khi sử dụng cái này hơn cái kia không? (Hiệu suất? Khả năng đọc? Hạn chế? Tính nhất quán? V.v.)

Nó thậm chí không quan trọng? Nếu không thì điều đó có vi phạm nguyên tắc Pythonic:

Nên có một — và tốt nhất là chỉ một — cách rõ ràng để làm điều đó .

Câu trả lời:


105

Nếu bạn cần gán tên lambdacho một tên, hãy sử dụng defthay thế. defs chỉ là đường cú pháp cho một phép gán, vì vậy kết quả là giống nhau, và chúng linh hoạt và dễ đọc hơn rất nhiều.

lambdas có thể được sử dụng để sử dụng một lần, loại bỏ các chức năng sẽ không có tên.

Tuy nhiên, trường hợp sử dụng này là rất hiếm. Bạn hiếm khi cần chuyển xung quanh các đối tượng hàm không tên.

Nội trang map()filter()các đối tượng hàm cần thiết, nhưng phần hiểu danh sáchbiểu thức trình tạo thường dễ đọc hơn các hàm đó và có thể bao gồm tất cả các trường hợp sử dụng mà không cần lambdas.

Đối với trường hợp bạn thực sự cần một đối tượng hàm nhỏ, bạn nên sử dụng các operatorhàm mô-đun, như operator.addthay vìlambda x, y: x + y

Nếu bạn vẫn cần một số lambdachưa được đề cập, bạn có thể cân nhắc viết a def, chỉ để dễ đọc hơn. Nếu hàm phức tạp hơn các hàm tại operatormô-đun, a defcó lẽ tốt hơn.

Vì vậy, lambdatrường hợp sử dụng tốt trong thế giới thực là rất hiếm.


9
Tôi đồng ý với câu trả lời cho khi sử dụng lambda, nhưng tôi không đồng ý rằng đây là "rất hiếm", người ta thường cho các chức năng chìa khóa để sortedhoặc itertools.groupbyvv, ví dụsorted(['a1', 'b0'], key= lambda x: int(x[1]))
Chris_Rands

30

Thực tế mà nói, với tôi có hai điểm khác biệt:

Đầu tiên là về những gì họ làm và những gì họ trở lại:

  • def là một từ khóa không trả về bất kỳ thứ gì và tạo ra một 'tên' trong không gian tên cục bộ.

  • lambda là một từ khóa trả về một đối tượng hàm và không tạo 'tên' trong không gian tên cục bộ.

Do đó, nếu bạn cần gọi một hàm lấy một đối tượng hàm, thì cách duy nhất để thực hiện điều đó trong một dòng mã python là sử dụng lambda. Không có tương đương với def.

Trong một số khuôn khổ, điều này thực sự khá phổ biến; ví dụ, tôi sử dụng Twisted rất nhiều, và vì vậy, làm một số việc như

d.addCallback(lambda result: setattr(self, _someVariable, result))

khá phổ biến và ngắn gọn hơn với lambdas.

Sự khác biệt thứ hai là về những gì chức năng thực tế được phép làm.

  • Một hàm được xác định bằng 'def' có thể chứa bất kỳ mã python nào
  • Một hàm được định nghĩa bằng 'lambda' phải đánh giá thành một biểu thức và do đó không thể chứa các câu lệnh như print, import, raise, ...

Ví dụ,

def p(x): print x

hoạt động như mong đợi, trong khi

lambda x: print x

là một SyntaxError.

Tất nhiên, có những giải pháp thay thế - thay thế printbằng sys.stdout.writehoặc importbằng __import__. Nhưng thông thường bạn nên sử dụng một hàm trong trường hợp đó.


22

Trong cuộc phỏng vấn này, Guido van Rossum nói rằng anh ấy ước anh ấy đã không để 'lambda' vào Python:

" Q. Bạn không hài lòng với tính năng nào của Python nhất?

Đôi khi tôi đã quá nhanh trong việc chấp nhận đóng góp và sau đó nhận ra rằng đó là một sai lầm. Một ví dụ sẽ là một số tính năng lập trình hàm, chẳng hạn như hàm lambda. Lambda là một từ khóa cho phép bạn tạo một hàm ẩn danh nhỏ; các hàm tích hợp sẵn như bản đồ, bộ lọc và rút gọn chạy một hàm trên loại trình tự, chẳng hạn như danh sách.

Trong thực tế, nó không diễn ra tốt như vậy. Python chỉ có hai phạm vi: cục bộ và toàn cầu. Điều này làm cho việc viết các hàm lambda trở nên khó khăn, vì bạn thường muốn truy cập các biến trong phạm vi mà lambda đã được xác định, nhưng bạn không thể vì hai phạm vi đó. Có một cách để giải quyết vấn đề này, nhưng đó là một thứ gì đó khó hiểu. Thường thì trong Python có vẻ dễ dàng hơn nhiều khi chỉ sử dụng vòng lặp for thay vì làm rối tung các hàm lambda. bản đồ và bạn bè chỉ hoạt động tốt khi đã có một chức năng tích hợp sẵn để thực hiện những gì bạn muốn.

IMHO, Iambdas đôi khi có thể thuận tiện, nhưng thường là thuận tiện với chi phí dễ đọc. Bạn có thể cho tôi biết điều này có tác dụng gì:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

Tôi đã viết nó, và tôi mất một phút để tìm ra nó. Đây là từ Project Euler - tôi sẽ không nói vấn đề nào vì tôi ghét những kẻ phá hoại, nhưng nó chạy trong 0,124 giây :)


20
Xin lưu ý rằng cuộc phỏng vấn đã khá cũ và Python từ lâu đã thêm phạm vi lồng nhau, điều này làm cho lập luận mà anh ta đưa ra chống lại lambda không còn phù hợp nữa. Tôi chắc chắn rằng anh ấy vẫn tiếc lambda, nhưng không đủ để xóa nó trong Python 3.0.
Thomas Wouters

10
Thực sự ví dụ của bạn nên là một lập luận chống lại một lớp lót, không phải lambdas. Ngoài ra, bạn nên sử dụng hàm sum có sẵn thay vì giảm bằng lambda: str (sum (map (lambda x: x ** x, range (1001)))) [: - 10]
Triptych

2
@ThomasWouters: Tôi hiểu rằng việc lambdakhông bị xóa trong phiên bản 3.0 là một điều gần như đã xảy ra và Guido đã không chiến đấu để giữ nó.
Ethan Furman

11

Đối với n = 1000, đây là một số thời gian gọi một hàm so với lambda:

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop

3
Thật thú vị khi thấy rằng lambda và các phiên bản được định nghĩa gần như tương đương. Lần kiểm tra cuối cùng mất nhiều thời gian hơn vì python có lẽ cần cấp phát không gian mỗi khi nó xác định hàm lambda đó.
hlin117

Tôi đoán điều này có ý nghĩa vì định nghĩa có thể tham chiếu đến các biến cục bộ (có thể đã thay đổi) ... mặc dù trong trường hợp không, như ở đây, cpython có thể làm tốt hơn.
Andy Hayden

Sử dụng đĩa đệm; (Lambda x, y: x * y) của bạn tạo hàm mỗi vòng lặp. Nếu bạn tạo lambda trước vòng lặp (còn gọi là f = lambda x, y: x * y), mã bytecode để gọi hàm sẽ giống hệt như g / f trong ví dụ trước của bạn, do đó hiệu suất lambda giống nhau như một hàm def. Vì vậy, lambda hoặc def như không có tác động nếu bạn sử dụng nó như nhau. Làm nghịch đảo, khai báo hàm f () trong vòng lặp, sau đó gọi nó là ...
tito

@tito Tôi tin rằng đó là chính xác những gì mà 3 ví dụ theo thời gian chứng minh ...
Andy Hayden

@tito oh, bạn đang nói việc xác định hàm trong vòng lặp, chắc chắn rồi, nhưng tôi cho rằng đó là một mẫu bất thường. Không chắc tại sao điều này lại cần sự phản đối về nhận xét đó ...
Andy Hayden

7

Hiệu suất:

Tạo một hàm với lambdahơi nhanh hơn so với việc tạo ra nó với def. Sự khác biệt là do deftạo mục nhập tên trong bảng địa phương. Hàm kết quả có cùng tốc độ thực thi.


Khả năng đọc:

Các hàm Lambda hơi khó đọc đối với hầu hết người dùng Python, nhưng cũng ngắn gọn hơn nhiều trong một số trường hợp. Cân nhắc chuyển đổi từ sử dụng thói quen không chức năng sang chức năng:

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

Như bạn thấy, lambdaphiên bản ngắn hơn và "dễ dàng hơn" theo nghĩa là bạn chỉ cần thêm lambda v:vào phiên bản không chức năng ban đầu để chuyển đổi sang phiên bản chức năng. Nó cũng ngắn gọn hơn rất nhiều. Nhưng hãy nhớ rằng, rất nhiều người dùng Python sẽ bị nhầm lẫn bởi cú pháp lambda, vì vậy những gì bạn mất về độ dài và độ phức tạp thực sự có thể nhận lại do sự nhầm lẫn từ các lập trình viên.


Hạn chế:

  • lambda các hàm chỉ có thể được sử dụng một lần, trừ khi được gán cho một tên biến.
  • lambdacác hàm được gán cho tên biến không có lợi thế hơn các defhàm.
  • lambda các chức năng có thể khó hoặc không thể thực hiện được.
  • def tên của các hàm phải được chọn cẩn thận để mô tả hợp lý và duy nhất hoặc ít nhất là không được sử dụng trong phạm vi.

Tính nhất quán:

Python chủ yếu tránh các quy ước lập trình chức năng để ủng hộ các ngữ nghĩa khách quan thủ tục và đơn giản hơn. Nhà lambdađiều hành trái ngược trực tiếp với sự thiên vị này. Hơn nữa, như một sự thay thế cho hàm đã phổ biến def, lambdahàm bổ sung thêm tính đa dạng cho cú pháp của bạn. Một số sẽ cho rằng ít nhất quán.


Các chức năng đã có từ trước:

Như những người khác đã lưu ý, nhiều cách sử dụng lambdatrong lĩnh vực này có thể được thay thế bởi các thành viên của operatormô-đun hoặc các mô-đun khác. Ví dụ:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

Sử dụng hàm có sẵn có thể làm cho mã dễ đọc hơn trong nhiều trường hợp.


Nguyên tắc Pythonic: "Nên có một - và tốt nhất là chỉ một - cách rõ ràng để làm điều đó"

Điều đó tương tự với nguồn duy nhất của học thuyết chân lý. Thật không may, nguyên tắc duy nhất-rõ-ràng-để-làm-nó luôn là một khát vọng sâu sắc đối với Python, hơn là một nguyên tắc hướng dẫn thực sự. Hãy xem xét khả năng hiểu mảng rất mạnh mẽ trong Python. Họ có chức năng tương đương với mapfilterchức năng:

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambdadefgiống nhau.

Đó là một vấn đề về quan điểm, nhưng tôi sẽ nói rằng bất kỳ thứ gì bằng ngôn ngữ Python dành cho mục đích sử dụng chung mà rõ ràng không phá vỡ bất cứ điều gì là đủ "Pythonic".


7

Thích hợp hơn: hàm lambda hay hàm lồng nhau ( def)?

Có một lợi thế khi sử dụng lambda thay vì một hàm thông thường: chúng được tạo trong một biểu thức.

Có một số nhược điểm:

  • không tên (chỉ '<lambda>')
  • không có docstrings
  • không có chú thích
  • không có câu lệnh phức tạp

Chúng cũng là cùng một loại đối tượng. Vì những lý do đó, tôi thường thích tạo các hàm bằng deftừ khóa thay vì bằng lambdas.

Điểm đầu tiên - chúng là cùng một loại đối tượng

Một lambda dẫn đến cùng một loại đối tượng như một hàm thông thường

>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
... 
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True

Vì lambdas là các hàm nên chúng là các đối tượng hạng nhất.

Cả lambdas và hàm:

  • có thể được chuyển xung quanh như một đối số (giống như một hàm thông thường)
  • khi được tạo bên trong một chức năng bên ngoài, trở thành một lớp đóng trên các địa phương của chức năng bên ngoài đó

Nhưng lambdas, theo mặc định, thiếu một số thứ mà các hàm nhận được thông qua cú pháp định nghĩa hàm đầy đủ.

Của một lamba __name__'<lambda>'

Lambdas xét cho cùng là các hàm ẩn danh, vì vậy chúng không biết tên của chính mình.

>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'

Do đó, lambda không thể được lập trình tra cứu trong không gian tên của chúng.

Điều này hạn chế một số điều. Ví dụ: foocó thể được tra cứu bằng mã số tuần tự, trong khi lkhông thể:

>>> import pickle
>>> pickle.loads(pickle.dumps(l))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fbbc0464e18>: 
attribute lookup <lambda> on __main__ failed

Chúng tôi có thể tra cứu footốt - vì nó biết tên riêng của nó:

>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>

Lambdas không có chú thích và không có chuỗi tài liệu

Về cơ bản, lambdas không được ghi lại. Hãy viết lại foođể được tài liệu tốt hơn:

def foo() -> int:
    """a nullary function, returns 0 every time"""
    return 0

Bây giờ, foo có tài liệu:

>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:

foo() -> int
    a nullary function, returns 0 every time

Trong khi đó, chúng tôi không có cơ chế giống nhau để cung cấp cùng một thông tin cho lambdas:

>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda (...)

Nhưng chúng ta có thể hack chúng trên:

>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda ) -> in
    nullary -> 0

Nhưng có thể có một số lỗi làm xáo trộn đầu ra của trợ giúp.

Lambdas chỉ có thể trả về một biểu thức

Lambdas không thể trả về các câu lệnh phức tạp, chỉ có các biểu thức.

>>> lambda: if True: 0
  File "<stdin>", line 1
    lambda: if True: 0
             ^
SyntaxError: invalid syntax

Các biểu thức có thể khá phức tạp và nếu bạn cố gắng rất nhiều, bạn có thể hoàn thành điều tương tự với lambda, nhưng sự phức tạp thêm vào sẽ gây hại nhiều hơn cho việc viết mã rõ ràng.

Chúng tôi sử dụng Python để rõ ràng và dễ bảo trì. Việc lạm dụng lambdas có thể chống lại điều đó.

Ưu điểm duy nhất cho lambdas: có thể được tạo trong một biểu thức duy nhất

Đây là điều duy nhất có thể xảy ra. Vì bạn có thể tạo lambda với một biểu thức, bạn có thể tạo nó bên trong một lời gọi hàm.

Việc tạo một hàm bên trong một lệnh gọi hàm tránh được việc tra cứu tên (rẻ tiền) so với việc tra cứu tên được tạo ở nơi khác.

Tuy nhiên, vì Python được đánh giá nghiêm ngặt, không có lợi ích hiệu suất nào khác để làm như vậy ngoài việc tránh tra cứu tên.

Đối với một biểu thức rất đơn giản, tôi có thể chọn lambda.

Tôi cũng có xu hướng sử dụng lambdas khi thực hiện Python tương tác, để tránh nhiều dòng khi một dòng sẽ làm. Tôi sử dụng loại định dạng mã sau khi tôi muốn chuyển đối số vào một phương thức khởi tạo khi gọi timeit.repeat:

import timeit

def return_nullary_lambda(return_value=0):
    return lambda: return_value

def return_nullary_function(return_value=0):
    def nullary_fn():
        return return_value
    return nullary_fn

Và bây giờ:

>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304

Tôi tin rằng sự khác biệt nhỏ về thời gian ở trên có thể là do việc tra cứu tên trong return_nullary_function- lưu ý rằng nó rất không đáng kể.

Phần kết luận

Lambdas rất phù hợp cho các tình huống không chính thức, nơi bạn muốn giảm thiểu các dòng mã để tạo ra một điểm độc đáo.

Lambdas là không tốt cho các tình huống chính thức hơn, nơi bạn cần sự rõ ràng cho những người chỉnh sửa mã, những người sẽ đến sau, đặc biệt là trong những trường hợp chúng không tầm thường.

Chúng ta biết rằng chúng ta phải đặt cho các đối tượng của mình những cái tên hay. Làm thế nào chúng ta có thể làm như vậy khi đối tượng không có tên?

Vì tất cả những lý do này, tôi thường thích tạo các hàm với defthay vì với lambda.


6

Tôi đồng ý với lời khuyên của nosklo: nếu bạn cần đặt tên cho hàm, hãy sử dụng def. Tôi dành các lambdahàm cho các trường hợp tôi chỉ chuyển một đoạn mã ngắn gọn sang một hàm khác, ví dụ:

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )

3
Trong hầu hết các kết hợp giữa map / lambda, bạn có thể thay thế nó bằng một chức năng hiểu danh sách hoặc thích hợp hơn. Ví dụ: "map (sum, a)" hoặc "[x [0] + x [1] for x in a]"
John Millikin 25/09/08

Vâng đó là sự thật. Đôi khi tôi thích map () hơn. Đây hầu hết chỉ là một ví dụ giả định về việc sử dụng một hàm trong dòng.
Dan Lenski

chính xác ... Hầu hết các ví dụ đều là giả thiết, bởi vì nó không tự nhiên khi sử dụng và có những cách thực tế tốt hơn trong hầu hết các trường hợp.
nosklo

5

Trong khi đồng ý với các câu trả lời khác, đôi khi nó dễ đọc hơn. Đây là một ví dụ lambdahữu ích, trong một trường hợp sử dụng, tôi tiếp tục gặp N chiều defaultdict.
Đây là một ví dụ:

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

Tôi thấy nó dễ đọc hơn là tạo một defchiều thứ hai. Điều này càng có ý nghĩa đối với các kích thước cao hơn.


from functools import partial; defaultdict(partial(defaultdict, list)). Gán một phần cho một tên nếu bạn muốn sử dụng nó nhiều lần. Nhưng, nếu bạn tiếp tục gặp phải cấu trúc này, điều đó có nghĩa là bạn không KHÔ. Đưa nó vào một thư viện tiện ích. Bạn có thể sử dụng cấu trúc này để tạo một lệnh mặc định n-chiều trọng tài bằng cách sử dụng các hàm khác (hoặc một vòng lặp hoặc đệ quy).
DylanYoung

3

Việc sử dụng chính của lambda luôn dành cho các hàm gọi lại đơn giản và bản đồ, thu gọn, bộ lọc yêu cầu hàm làm đối số. Với khả năng hiểu danh sách trở thành tiêu chuẩn và được phép thêm vào nếu như trong:

x = [f for f in range(1, 40) if f % 2]

Thật khó để tưởng tượng một trường hợp thực tế cho việc sử dụng lambda trong sử dụng hàng ngày. Kết quả là, tôi muốn nói, tránh lambda và tạo các hàm lồng nhau.


3

Một hạn chế quan trọng của lambdas là chúng không thể chứa bất cứ thứ gì ngoài một biểu thức. Gần như không thể để một biểu thức lambda tạo ra bất cứ thứ gì ngoài các tác dụng phụ tầm thường, vì nó không thể có bất kỳ vị trí nào gần như một phần thân giàu có như một defhàm 'ed.

Điều đó đang được nói, Lua đã ảnh hưởng đến phong cách lập trình của tôi đối với việc sử dụng rộng rãi các hàm ẩn danh, và tôi đã vứt bỏ mã của mình với chúng. Trên hết, tôi có xu hướng nghĩ về ánh xạ / rút gọn như các toán tử trừu tượng theo những cách mà tôi không coi là hiểu danh sách hoặc trình tạo, gần như là Nếu tôi đang trì hoãn quyết định triển khai một cách rõ ràng bằng cách sử dụng các toán tử đó.

Biên tập: Đây là một câu hỏi khá cũ và ý kiến ​​của tôi về vấn đề này đã thay đổi phần nào.

Trước hết, tôi rất thiên vị đối với việc gán một lambdabiểu thức cho một biến; vì python có một cú pháp đặc biệt chỉ dành cho điều đó (gợi ý, def). Thêm vào đó, nhiều cách sử dụng lambda, ngay cả khi chúng không có tên, đã xác định trước (và hiệu quả hơn) triển khai. Ví dụ, ví dụ được đề cập có thể được viết tắt thành just (1).__add__, mà không cần phải đặt nó trong dấu lambdahoặc def. Nhiều cách sử dụng phổ biến khác có thể được thỏa mãn với một số kết hợp của operator, itertoolsfunctoolscác mô-đun.


1
(1).__add__- việc gọi các phương thức dunder trực tiếp hầu như không bao giờ xảy ra. Một nghìn lambdagiây cho mỗi cuộc gọi dunder trực tiếp.
Ethan Furman

1
@EthanFurman: Chà, theo kinh nghiệm của tôi, các lệnh gọi về bản chất (1).__add__hơi không phổ biến, nhưng tôi sẽ không đi đâu gần với "nên". không nghi ngờ gì nữa, tôi thấy trước đây dễ đọc hơn rất nhiều lambda x: 1 + x. Nếu chúng ta có một cái gì đó giống với ký hiệu lát cắt haskells hơn, thì (1+)điều đó thật tuyệt, nhưng chúng ta phải làm với những gì chính xác về mặt ngữ nghĩa của thứ đó, tên phương thức dunder.
SingleNegationElimination

2
  • Thời gian tính toán.
  • Chức năng không có tên.
  • Để đạt được Một chức năng và nhiều chức năng sử dụng.

Xem xét một ví dụ đơn giản,

# CREATE ONE FUNCTION AND USE IT TO PERFORM MANY OPERATIONS ON SAME TYPE OF DATA STRUCTURE.
def variousUse(a,b=lambda x:x[0]):
    return [b(i) for i in a]

dummyList = [(0,1,2,3),(4,5,6,7),(78,45,23,43)]
variousUse(dummyList)                           # extract first element
variousUse(dummyList,lambda x:[x[0],x[2],x[3]]) # extract specific indexed element
variousUse(dummyList,lambda x:x[0]+x[2])        # add specific elements
variousUse(dummyList,lambda x:x[0]*x[2])        # multiply specific elements

1

Nếu bạn chỉ định gán lambda cho một biến trong phạm vi cục bộ, bạn cũng có thể sử dụng def vì nó dễ đọc hơn và có thể được mở rộng dễ dàng hơn trong tương lai:

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

hoặc là

def fun(a, b): return a ** b # more readable
map(fun, someList)

Cả hai from operator import pow;map(pow, someList)(a**b for a,b in someList)thậm chí còn dễ đọc hơn.
InQβ

1

Một công dụng cho lambdas mà tôi đã tìm thấy ... là trong thông báo gỡ lỗi.

Vì lambdas có thể được đánh giá một cách lười biếng, bạn có thể có mã như thế này:

log.debug(lambda: "this is my message: %r" % (some_data,))

thay vì có thể đắt:

log.debug("this is my message: %r" % (some_data,))

xử lý chuỗi định dạng ngay cả khi lệnh gọi gỡ lỗi không tạo ra đầu ra do mức ghi nhật ký hiện tại.

Tất nhiên để nó hoạt động như mô tả, mô-đun ghi nhật ký đang sử dụng phải hỗ trợ lambdas là "tham số lười biếng" (như mô-đun ghi nhật ký của tôi).

Ý tưởng tương tự có thể được áp dụng cho bất kỳ trường hợp lười đánh giá nào khác để tạo giá trị nội dung theo yêu cầu.

Ví dụ: toán tử bậc ba tùy chỉnh này:

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

thay vì:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

với lambdas chỉ biểu thức được chọn theo điều kiện mới được đánh giá, không có lambdas thì cả hai sẽ được đánh giá.

Tất nhiên bạn có thể đơn giản sử dụng các hàm thay vì lambdas, nhưng đối với các biểu thức ngắn gọn, lambdas là (c) gọn gàng hơn.


1
NB loggingđã có định dạng lười biếng: log.debug("this is my message: %r", some_data)sẽ chỉ định dạng khi / nếu thư được yêu cầu.
j08lue

@ j08lue phương thức lambda bỏ qua đánh giá mọi thứ trong trường hợp đầu ra gỡ lỗi không được tạo, trong trường hợp bạn hiển thị some_datacó thể là một biểu thức đắt tiền hoặc lệnh gọi hàm / phương thức.
Glushiator

0

Tôi đồng ý với nosklo. Nhân tiện, ngay cả khi sử dụng một lần, hãy vứt bỏ chức năng, hầu hết thời gian bạn chỉ muốn sử dụng một cái gì đó từ mô-đun điều hành.

VÍ DỤ :

Bạn có một hàm với chữ ký này: myFunction (dữ liệu, hàm gọi lại).

Bạn muốn truyền một hàm thêm 2 phần tử.

Sử dụng lambda:

myFunction(data, (lambda x, y : x + y))

Cách con trăn:

import operator
myFunction(data, operator.add)

Hoặc tất nhiên đây là một ví dụ đơn giản, nhưng có rất nhiều thứ mà mô-đun điều hành cung cấp, bao gồm các mục setters / getters cho danh sách và dict. Thật là tuyệt.


-1

Một sự khác biệt chính là bạn không thể sử dụng các defhàm nội tuyến, theo tôi đây là trường hợp sử dụng thuận tiện nhất cho một lambdahàm. Ví dụ khi sắp xếp danh sách các đối tượng:

my_list.sort(key=lambda o: o.x)

Do đó, tôi sẽ đề nghị giữ việc sử dụng lambdas cho loại hoạt động tầm thường này, điều này cũng không thực sự có lợi từ tài liệu tự động được cung cấp bằng cách đặt tên cho hàm.


-2

lambda rất hữu ích để tạo các hàm mới:

>>> def somefunc(x): return lambda y: x+y
>>> f = somefunc(10)
>>> f(2)
12
>>> f(4)
14
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.