เป็นที่ต้องการมากกว่า: ฟังก์ชันแลมบ์ดาหรือฟังก์ชันซ้อนกัน ( def
)?
มีข้อดีอย่างหนึ่งในการใช้แลมบ์ดากับฟังก์ชันปกตินั่นคือสร้างขึ้นในนิพจน์
มีข้อบกพร่องหลายประการ:
- ไม่มีชื่อ (เฉยๆ
'<lambda>'
)
- ไม่มี docstrings
- ไม่มีคำอธิบายประกอบ
- ไม่มีข้อความที่ซับซ้อน
ทั้งคู่ยังเป็นวัตถุประเภทเดียวกัน ด้วยเหตุผลดังกล่าวโดยทั่วไปฉันชอบสร้างฟังก์ชันด้วยdef
คีย์เวิร์ดแทนที่จะใช้ lambdas
จุดแรก - เป็นวัตถุประเภทเดียวกัน
แลมบ์ดาส่งผลให้อ็อบเจ็กต์ประเภทเดียวกันกับฟังก์ชันปกติ
>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
...
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True
เนื่องจาก lambdas เป็นฟังก์ชันจึงเป็นวัตถุชั้นหนึ่ง
ทั้ง lambdas และฟังก์ชั่น:
- สามารถส่งผ่านไปรอบ ๆ เป็นอาร์กิวเมนต์ (เช่นเดียวกับฟังก์ชันทั่วไป)
- เมื่อสร้างขึ้นภายในฟังก์ชันภายนอกจะกลายเป็นการปิดทับท้องถิ่นของฟังก์ชันภายนอกนั้น
แต่โดยค่าเริ่มต้น lambdas ขาดบางสิ่งที่ฟังก์ชันได้รับผ่านไวยากรณ์นิยามฟังก์ชันแบบสมบูรณ์
lamba ของ __name__
คือ'<lambda>'
Lambdas เป็นฟังก์ชันที่ไม่ระบุชื่อดังนั้นพวกเขาจึงไม่รู้ชื่อของตัวเอง
>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'
ดังนั้นแลมบ์ดาจึงไม่สามารถค้นหาด้วยโปรแกรมในเนมสเปซได้
สิ่งนี้ จำกัด บางสิ่ง ตัวอย่างเช่นfoo
สามารถค้นหาได้ด้วยรหัสซีเรียลในขณะที่l
ไม่สามารถ:
>>> 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
เราสามารถค้นหาได้foo
ดี - เพราะรู้จักชื่อของตัวเอง:
>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>
Lambdas ไม่มีคำอธิบายประกอบและไม่มี docstring
โดยทั่วไปแลมบ์ดาไม่ได้รับการจัดทำเป็นเอกสาร มาเขียนใหม่foo
ให้เป็นเอกสารกันดีกว่า:
def foo() -> int:
"""a nullary function, returns 0 every time"""
return 0
ตอนนี้ foo มีเอกสารประกอบ:
>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:
foo() -> int
a nullary function, returns 0 every time
ในขณะที่เราไม่มีกลไกเดียวกันในการให้ข้อมูลเดียวกันกับ lambdas:
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda (...)
แต่เราสามารถแฮ็คได้ที่:
>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda ) -> in
nullary -> 0
แต่อาจมีข้อผิดพลาดบางอย่างที่ทำให้ผลลัพธ์ของความช่วยเหลือยุ่งเหยิง
Lambdas สามารถส่งคืนนิพจน์เท่านั้น
Lambdas ไม่สามารถส่งคืนคำสั่งที่ซับซ้อนได้มีเพียงนิพจน์เท่านั้น
>>> lambda: if True: 0
File "<stdin>", line 1
lambda: if True: 0
^
SyntaxError: invalid syntax
นิพจน์อาจค่อนข้างซับซ้อนและถ้าคุณพยายามอย่างหนักคุณก็สามารถทำได้เช่นเดียวกันกับแลมด้า แต่ความซับซ้อนที่เพิ่มเข้ามานั้นเป็นอันตรายต่อการเขียนโค้ดที่ชัดเจนมากกว่า
เราใช้ Python เพื่อความชัดเจนและการบำรุงรักษา การใช้แลมบ์ดามากเกินไปสามารถต่อต้านสิ่งนั้นได้
อัพไซด์เดียวสำหรับ lambdas: สามารถสร้างได้ในนิพจน์เดียว
นี่เป็นเพียงกลับหัวเท่านั้นที่เป็นไปได้ เนื่องจากคุณสามารถสร้างแลมบ์ดาด้วยนิพจน์คุณจึงสามารถสร้างได้ภายในการเรียกใช้ฟังก์ชัน
การสร้างฟังก์ชันภายในการเรียกใช้ฟังก์ชันหลีกเลี่ยงการค้นหาชื่อ (ราคาไม่แพง) เมื่อเทียบกับฟังก์ชันที่สร้างขึ้นจากที่อื่น
อย่างไรก็ตามเนื่องจาก Python ได้รับการประเมินอย่างเคร่งครัดจึงไม่มีการเพิ่มประสิทธิภาพอื่น ๆ นอกเหนือจากการหลีกเลี่ยงการค้นหาชื่อ
เพื่อการแสดงออกที่เรียบง่ายฉันอาจเลือกแลมด้า
ฉันมักจะใช้ lambdas เมื่อทำ Python แบบโต้ตอบเพื่อหลีกเลี่ยงหลายบรรทัดเมื่อจะทำ ฉันใช้รูปแบบรหัสต่อไปนี้เมื่อฉันต้องการส่งผ่านอาร์กิวเมนต์ไปยังตัวสร้างเมื่อเรียก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
และตอนนี้:
>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304
ผมเชื่อว่าแตกต่างเวลาเล็กน้อยข้างต้นสามารถนำมาประกอบกับการค้นหาชื่อreturn_nullary_function
- ทราบว่ามันเป็นมากเล็กน้อย
สรุป
Lambdas เหมาะสำหรับสถานการณ์ที่ไม่เป็นทางการที่คุณต้องการย่อบรรทัดของโค้ดเพื่อให้เกิดจุดเอกพจน์
Lambdas ไม่ดีสำหรับสถานการณ์ที่เป็นทางการมากขึ้นซึ่งคุณต้องการความชัดเจนสำหรับผู้แก้ไขโค้ดที่จะมาในภายหลังโดยเฉพาะอย่างยิ่งในกรณีที่ไม่เป็นเรื่องเล็กน้อย
เรารู้ว่าเราควรจะให้ชื่อที่ดีแก่วัตถุของเรา เราจะทำได้อย่างไรเมื่อวัตถุไม่มีชื่อ
ด้วยเหตุผลทั้งหมดนี้ฉันมักชอบสร้างฟังก์ชันด้วยdef
แทนที่จะสร้างด้วยlambda
.
lambda
แต่ฉันไม่เห็นด้วยว่านี่เป็น "หายากมาก" ซึ่งเป็นเรื่องปกติสำหรับฟังก์ชันหลักsorted
หรือitertools.groupby
อื่น ๆ เช่นsorted(['a1', 'b0'], key= lambda x: int(x[1]))