ทำไม Lambdas ของ Python จึงมีประโยชน์ [ปิด]


929

ฉันพยายามที่จะเข้าใจลูกแกะงูหลาม แลมบ์ดาเป็นหนึ่งในรายการภาษาที่ "น่าสนใจ" ที่ควรลืมในชีวิตจริงหรือไม่?

ฉันแน่ใจว่ามีบางกรณีที่อาจจำเป็นต้องใช้ขอบ แต่เนื่องจากความคลุมเครือของมันศักยภาพของมันถูกนิยามใหม่ในรุ่นอนาคต (สมมติฐานของฉันขึ้นอยู่กับคำจำกัดความต่าง ๆ ของมัน) และลดความชัดเจนของการเข้ารหัส ต้องหลีกเลี่ยง?

สิ่งนี้ทำให้ฉันนึกถึงการโอเวอร์โฟลว์ (บัฟเฟอร์โอเวอร์โฟลว์) ของชนิด C - ชี้ไปที่ตัวแปรด้านบนและการโหลดมากเกินไปเพื่อตั้งค่าฟิลด์อื่น มันให้ความรู้สึกเหมือนเป็นนักแสดงที่มีความเชี่ยวชาญ แต่เป็นฝันร้ายของผู้ดูแลรหัส


261
+1 คำถามที่ดี - สมมติฐานที่ไม่ดี (ความสับสนของแลมบ์ดา) =) พยายามอย่าตัดสินเทคนิคการเขียนโปรแกรม ประเมินพวกเขาและเพิ่มไปยังชุดเครื่องมือทางจิตของคุณ หากคุณไม่ชอบพวกเขาอย่าใช้พวกเขาและเตรียมพร้อมที่จะพูดคุยกับพวกเขาอย่างมีเหตุผลโดยไม่ต้องกลายเป็นคนเคร่งศาสนา
Kieveli

41
กฎ Haskell! ฟังก์ชั่นของแลมบ์ดาช่วยให้คุณแสดงออกและมีพลังที่เป็นนามธรรม
Jonathan Barbero

11
@JAL ไม่ต้องพูดถึง LISP ...
ApproachDarknessFish

8
@ApproachingDarknessFish "อ้านั่นคือวงเล็บของพ่อคุณอาวุธที่อารยะมากขึ้นจากยุคที่มีอารยธรรมมากกว่า" - Obi Lisp Kenobi
ฟิลด์

คำตอบ:


1009

คุณกำลังพูดถึงฟังก์ชั่นแลมบ์ดา ? ชอบ

lambda x: x**2 + 2*x - 5

สิ่งเหล่านั้นมีประโยชน์มากทีเดียว Python สนับสนุนรูปแบบการเขียนโปรแกรมที่เรียกว่าfunctional programmingซึ่งคุณสามารถส่งผ่านฟังก์ชั่นไปยังฟังก์ชั่นอื่น ๆ เพื่อทำสิ่งต่างๆ ตัวอย่าง:

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

กำหนดmult3ให้[3, 6, 9]องค์ประกอบเหล่านั้นของรายการต้นฉบับที่เป็นทวีคูณของ 3 นี้จะสั้นกว่า (และหนึ่งสามารถโต้เถียงชัดเจนกว่า)

def filterfunc(x):
    return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

แน่นอนในกรณีนี้คุณสามารถทำสิ่งเดียวกันกับรายการความเข้าใจ:

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(หรือแม้กระทั่งrange(3,10,3)) แต่มีอีกหลายกรณีการใช้ที่ซับซ้อนกว่าซึ่งคุณไม่สามารถใช้ความเข้าใจในรายการและฟังก์ชั่นแลมบ์ดาอาจเป็นวิธีที่สั้นที่สุดในการเขียนบางสิ่งออกมา

  • การคืนค่าฟังก์ชันจากฟังก์ชันอื่น

    >>> def transform(n):
    ...     return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    สิ่งนี้มักถูกใช้เพื่อสร้างฟังก์ชั่นห่อหุ้มเช่นตัวตกแต่งของงูหลาม

  • การรวมองค์ประกอบของลำดับที่ซ้ำได้ด้วย reduce()

    >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
  • จัดเรียงตามคีย์สำรอง

    >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]

ฉันใช้ฟังก์ชั่นแลมบ์ดาเป็นประจำ ฉันใช้เวลาสักครู่เพื่อทำความคุ้นเคยกับพวกเขา แต่ในที่สุดฉันก็เข้าใจว่าพวกเขาเป็นส่วนที่มีค่ามากของภาษา


26
รักตัวอย่างเข้าใจง่ายมาก แต่สำหรับส่วนลด ถ้าฉันต้องใช้คุณลักษณะนี้ ฉันจะทำ','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds

3
BTW ถ้าคุณเรียกใช้งานบน Python3 คุณจะต้องเรียกรายการผลการกรองเพื่อดูค่าจริงนอกจากนี้คุณต้องนำเข้าลดจาก functools
เจอราร์ด

เราแน่ใจเกี่ยวกับคำจำกัดความของ "ฟังก์ชั่นการเขียนโปรแกรม" ข้างต้นหรือไม่? มันทำให้ฉันสับสนเล็กน้อย
stdout

3
ฉันคิดว่าประเด็นสำคัญคือlambdaฟังก์ชั่นสามารถไม่ระบุชื่อได้ (เหมือนในตัวอย่างทั้งหมดของคุณ) หากคุณกำลังกำหนดlambdaฟังก์ชั่นให้กับทุกสิ่งคุณควรทำสิ่งที่ผิดและควรใช้defแทน
Chris_Rands

1
@zgulser มันไม่ได้เป็นคำจำกัดความมันเป็นเพียงคำสั่งเกี่ยวกับสิ่งที่การเขียนโปรแกรมการทำงานช่วยให้คุณทำ
David Z

377

lambdafunctionเป็นเพียงวิธีที่จินตนาการของบอก นอกเหนือจากชื่อของมันแล้วไม่มีอะไรคลุมเครือข่มขู่หรือซ่อนเร้นเกี่ยวกับมัน เมื่อคุณอ่านบรรทัดต่อไปนี้แทนที่lambdaด้วยfunctionในใจของคุณ:

>>> f = lambda x: x + 1
>>> f(3)
4

xมันก็กำหนดหน้าที่ของ บางภาษาRพูดว่าอย่างชัดเจน:

> f = function(x) { x + 1 }
> f(3)
4

เห็นไหม เป็นหนึ่งในสิ่งที่เป็นธรรมชาติที่สุดในการเขียนโปรแกรม


36
นี่คือคำอธิบายที่ดีสำหรับผู้ที่มาจากภูมิหลังที่ไม่ได้เขียนโปรแกรม (เช่น: วิทยาศาสตร์ที่แน่นอน) ซึ่งทำให้ความหมายของlambda การเข้าใจง่ายมาก ขอบคุณ!
Gabriel

10
Raymond Hettinger คร่ำครวญถึงชื่อในการพูดคุยของเขาและกล่าวว่าความสับสนทั้งหมดสามารถหลีกเลี่ยงได้โดยการตั้งชื่อมันว่า 'ทำหน้าที่' แทน 'แลมบ์ดา' :-)
ankush981

10
แทนที่lambdaด้วยfunctionความคิดของคุณและเพิ่มreturnก่อนการแสดงออกครั้งสุดท้าย
Ciprian Tomoiagă

4
type(lambda x: 3)ลอง @AaronMcMillin lambdaการแสดงออกและdefงบทั้งสองสร้างfunctionวัตถุ; มันเป็นเพียงไวยากรณ์ของการlambdaแสดงออกที่ จำกัดซึ่งอินสแตนซ์ที่มันสามารถผลิตได้
chepner

6
@AaronMcMillin คุณไม่มีจุดของฉัน เพียงเพราะคุณไม่สามารถกำหนดทุกฟังก์ชั่นด้วยการlambdaแสดงออกไม่ได้หมายความว่าผลลัพธ์ของการlambdaแสดงออกไม่ใช่ฟังก์ชั่น
chepner

107

สรุปสองบรรทัด:

  1. การปิด : มีประโยชน์มาก เรียนรู้พวกเขาใช้พวกเขารักพวกเขา
  2. lambdaคำสำคัญของ Python : ไม่จำเป็นและมีประโยชน์ในบางครั้ง หากคุณพบว่าตัวเองกำลังทำสิ่งที่ซับซ้อนจากระยะไกลให้นำไปทิ้งและกำหนดฟังก์ชั่นจริง

72

แลมบ์ดาเป็นส่วนหนึ่งของกลไกนามธรรมที่สำคัญซึ่งเกี่ยวข้องกับฟังก์ชั่นการสั่งซื้อที่สูงขึ้น เพื่อให้เข้าใจถึงคุณค่าของมันอย่างเหมาะสมโปรดดูบทเรียนคุณภาพสูงจากAbelson และ Sussmanและอ่านหนังสือSICP

เหล่านี้เป็นประเด็นที่เกี่ยวข้องในธุรกิจซอฟต์แวร์สมัยใหม่และเป็นที่นิยมมากขึ้นเรื่อย ๆ


1
การแสดงออกของแลมบ์ดากำลังเป็นที่นิยมในภาษาอื่น (เช่น C #) เช่นกัน พวกเขาจะไม่ไปไหน การอ่านข้อมูลเกี่ยวกับการปิดจะเป็นแบบฝึกหัดที่มีประโยชน์เพื่อทำความเข้าใจกับแลมบ์ดา การปิดประตูทำให้เกิดการเข้ารหัสเวทย์มนตร์ได้มากมายในเฟรมเวิร์กเช่น jQuery
Dan Esparza

3
อย่าสับสนกับlambdaฟังก์ชั่นชั้นหนึ่ง Python มีlambdaคำสั่งที่จำกัด อย่างมากแต่ฟังก์ชั่นชั้นหนึ่งอย่างเต็มที่ ข้อแตกต่างเพียงอย่างเดียวคือคุณต้องตั้งชื่อฟังก์ชั่นที่คุณต้องการผ่าน
Gareth Latty

59

lambdas นั้นมีประโยชน์อย่างมากในการเขียนโปรแกรม GUI ตัวอย่างเช่นสมมติว่าคุณกำลังสร้างกลุ่มของปุ่มและคุณต้องการใช้การติดต่อกลับแบบพารามิเตอร์เดียวแทนที่จะโทรกลับที่ไม่ซ้ำกันต่อปุ่ม แลมบ์ดาช่วยให้คุณทำสิ่งนั้นได้อย่างง่ายดาย:

for value in ["one","two","three"]:
    b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
    b.pack()

(หมายเหตุ: แม้ว่าคำถามนี้มีการถามเป็นพิเศษเกี่ยวกับlambdaคุณยังสามารถใช้functool. บางส่วนเพื่อให้ได้ผลลัพธ์ประเภทเดียวกัน)

ทางเลือกคือการสร้างการโทรกลับแยกกันสำหรับแต่ละปุ่มซึ่งอาจนำไปสู่การทำซ้ำรหัส


1
นี่คือสาเหตุที่ฉันค้นหาว่าแลมบ์ดาเป็นอะไร แต่ทำไมงานนี้ถึงฉันมันเหมือนกันทุกประการเหมือนกับการเรียกฟังก์ชันตรง ( stackoverflow.com/questions/3704568/ ...... ) อาจจะสายมันใช้งานได้ แต่ทำไมถึงใช้งานได้
Rqomey

5
@Rqomey: ความแตกต่างคือในตัวอย่างนี้valueมีการกำหนดไว้ในวง; ในตัวอย่างอื่นพารามิเตอร์จะมีเพียงค่าเดียวเสมอ เมื่อคุณเพิ่มสิ่งที่ชอบarg=valueคุณกำลังแนบค่าปัจจุบันในการติดต่อกลับ หากไม่มีคุณจะผูกการอ้างอิงกับตัวแปรในการติดต่อกลับ การอ้างอิงจะมีค่าสุดท้ายของตัวแปรเสมอเนื่องจากการโทรกลับเกิดขึ้นหลังจากที่ลูปทำงานเสร็จแล้ว
ไบรอัน Oakley

1
ฉันเพิ่งใช้งานได้เมื่อวานนี้ฉันไม่อยากเชื่อเลยว่ามีประโยชน์มากแค่ไหน ... ฉันสามารถสร้างเมนูจากหนึ่งสำหรับลูปและไฟล์ csv สำหรับการตั้งค่า สิ่งที่มีประโยชน์จริงๆ
Rqomey

1
สังเกตการมีอยู่ของfunctools.partial()สิ่งที่ทำให้คุณสามารถทำสิ่งนี้ด้วย cruft น้อยลง (และไม่มีlambda)
Gareth Latty

2
partial(my_callback, value)vs lambda arg=value: my_callback(arg)- แลมบ์ดามี cruft มากกว่า (มอบหมายให้หาเรื่องแล้วใช้) และมันก็ชัดเจนน้อยกว่าความตั้งใจ (คุณอาจทำบางสิ่งที่แตกต่างอย่างละเอียดในแลมบ์ดา) การนำเข้าไม่ใช่ปัญหาจริง ๆ (คุณมีกองอยู่แล้วและหนึ่งครั้งต่อหนึ่งไฟล์) รหัสถูกตัดสินว่าอ่านได้ดีเพียงใดและอ่านpartial()ได้ง่ายกว่าแลมบ์ดา
Gareth Latty

58

ฉันสงสัยแลมบ์ดาจะหายไป ดูโพสต์ของ Guidoในที่สุดก็เลิกพยายามลบออก ดูโครงร่างของความขัดแย้งด้วย

คุณอาจตรวจสอบโพสต์นี้เพื่อดูประวัติที่มากขึ้นเกี่ยวกับข้อตกลงเบื้องหลังฟีเจอร์การทำงานของ Python: http://python-history.blogspot.com/2009/04/origins-of-pythons-features.html

อยากรู้อยากเห็นแผนที่ตัวกรองและลดฟังก์ชั่นที่กระตุ้นแรงบันดาลใจจากการแนะนำแลมบ์ดาและฟังก์ชั่นการทำงานอื่น ๆ นั้นถูกแทนที่ด้วยรายการความเข้าใจและการแสดงออกของเครื่องกำเนิด ในความเป็นจริงฟังก์ชั่นลดถูกลบออกจากรายการฟังก์ชั่นบิวอินใน Python 3.0 (อย่างไรก็ตามไม่จำเป็นต้องส่งเรื่องร้องเรียนเกี่ยวกับการลบแลมบ์ดาแผนที่หรือตัวกรองออก: พวกเขาอยู่ :-)

เซ็นต์สองตัวของฉันเอง: แลมบ์ดาแทบจะคุ้มค่าเท่าที่ชัดเจน โดยทั่วไปมีวิธีแก้ปัญหาที่ชัดเจนมากกว่าซึ่งไม่รวมแลมบ์ดา


2
โปรดทราบว่าการลดยังคงนำเข้าได้ใน Python 3.0 ถ้าคุณต้องการมันจริงๆคุณก็ยังสามารถรับมันได้
Paweł Polewicz

ฉันคิดว่าความพยายามของกุยโด้เป็นเรื่องเกี่ยวกับไวยากรณ์มากกว่า คนนี้ยังคิดว่า: cackhanded.com/blog/post/2008/01/24/…
leewz

38

ใน Python lambdaเป็นเพียงวิธีการกำหนดฟังก์ชั่นแบบอินไลน์

a = lambda x: x + 1
print a(1)

และ..

def a(x): return x + 1
print a(1)

.. เป็นที่แน่นอนแบบเดียวกัน

ไม่มีสิ่งใดที่คุณสามารถทำได้ด้วยแลมบ์ดาซึ่งคุณไม่สามารถทำกับฟังก์ชั่นปกติได้ในฟังก์ชั่นของ Python นั้นเป็นวัตถุที่เหมือนกับสิ่งอื่นใดแลมบ์ดาสก็กำหนดฟังก์ชั่น

>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>

ฉันคิดอย่างสุจริต lambdaคำหลักนั้นซ้ำซ้อนใน Python ฉันไม่เคยต้องการใช้มัน (หรือเห็นสิ่งที่ใช้ในที่ที่ฟังก์ชั่นปกติ, list-comprehension หรือหนึ่งในหลาย ๆ ฟังก์ชั่นบิวอินอาจจะดีกว่าแทน)

สำหรับตัวอย่างแบบสุ่มโดยสมบูรณ์จากบทความ"แลมบ์ดาของ Python เสีย!" :

เพื่อดูว่าแลมบ์ดาเสียลองสร้างรายชื่อของฟังก์ชั่นที่fs=[f0,...,f9] fi(n)=i+nความพยายามครั้งแรก:

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13

ฉันจะเถียงว่าแม้ว่ามันจะได้ผลมันก็น่ากลัวและ "unpythonic" ฟังก์ชั่นเดียวกันสามารถเขียนได้หลายวิธีเช่น:

>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

ใช่มันไม่เหมือนกัน แต่ฉันไม่เคยเห็นสาเหตุที่ต้องการสร้างฟังก์ชั่นแลมบ์ดาในรายการ มันอาจสมเหตุสมผลในภาษาอื่น ๆ แต่ Python ไม่ใช่ Haskell (หรือ Lisp หรือ ... )

โปรดทราบว่าเราสามารถใช้แลมบ์ดาและยังคงได้ผลลัพธ์ที่ต้องการในวิธีนี้:

>>> fs = [(lambda n,i=i: i + n) for i in range(10)]
>>> fs[3](4)
7

แก้ไข:

มีบางกรณีที่แลมบ์ดามีประโยชน์เช่นมักจะสะดวกเมื่อเชื่อมต่อสัญญาณในแอพพลิเคชั่น PyQt ดังนี้:

w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())

เพียงแค่ทำw.textChanged.connect(dothing)จะเรียกdothingวิธีการที่มีeventข้อโต้แย้งพิเศษและทำให้เกิดข้อผิดพลาด การใช้แลมบ์ดาหมายความว่าเราสามารถวางอาร์กิวเมนต์อย่างเป็นระเบียบโดยไม่จำเป็นต้องกำหนดฟังก์ชันการตัดคำ


2
อาร์กิวเมนต์ "lambda is broken" ของคุณใช้งานไม่ได้เนื่องจากกฎการกำหนดขอบเขตตัวแปร python ทำงานในลักษณะนั้นเป็นระยะเวลา คุณจะถูกกัดในลักษณะเดียวกันถ้าคุณสร้างการปิดด้านในแบบ for-loop
Antti Haapala

1
แลมบ์ดาเป็นเพียงวิธีการในการจัดหาฟังก์ชั่น "ไม่ระบุตัวตน" ให้แก่ผู้ใช้เหมือนกับภาษาอื่น ๆ ที่มี (เช่นจาวาสคริปต์)
Stefan Gruenwald

1
แลมบ์ดาและฟังก์ชันaที่คุณกำหนดไม่เหมือนกันทุกประการ :) พวกเขาแตกต่างกันตาม__name__สนามอย่างน้อย ...
nperson325681

1
มันใช้งานได้มากกว่าฟังก์ชั่นอินไลน์
kta

ข้อโต้แย้งของคุณเกี่ยวกับ "อาจเข้าท่าในภาษาอื่น" นั้นแปลก ไม่ว่าจะมีคุณสมบัติของเนื้อแกะหรือเนื้อแกะก็ตาม
Titou

31

ฉันพบแลมบ์ดามีประโยชน์สำหรับรายการฟังก์ชั่นที่ทำเช่นเดียวกัน แต่สำหรับสถานการณ์ต่าง ๆ

ชอบกฎพหูพจน์ Mozilla :

plural_rules = [
    lambda n: 'all',
    lambda n: 'singular' if n == 1 else 'plural',
    lambda n: 'singular' if 0 <= n <= 1 else 'plural',
    ...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'

หากคุณต้องกำหนดฟังก์ชั่นสำหรับทุกคนที่คุณคลั่งไคล้ในตอนท้าย
นอกจากนี้มันจะไม่ดีกับชื่อฟังก์ชันเหมือนplural_rule_1, plural_rule_2ฯลฯ และคุณจะต้องeval()มันเมื่อคุณขึ้นอยู่กับตัวแปร id ของฟังก์ชั่น


1
สิ่งนี้ดูคล้ายกับการเผชิญหน้าสั้น ๆ ที่ฉันเคยมีใน F # ด้วยการจับคู่รูปแบบและตัวเลือกต่างๆ คุณมีข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ไวยากรณ์นี้หรือไม่
Ken

26

คุณสามารถทำอะไรกับlambdaคุณได้ดีกว่าด้วยฟังก์ชั่นที่ตั้งชื่อไว้หรือรายการและตัวสร้างนิพจน์

ดังนั้นส่วนใหญ่คุณควรจะเป็นหนึ่งในนั้นในสถานการณ์ใด ๆ (ยกเว้นสำหรับรหัสรอยขีดข่วนที่เขียนในล่ามแบบโต้ตอบ)


3
"ส่วนใหญ่คุณควรจะเป็นหนึ่งในผู้ที่อยู่ในสถานการณ์ใด ๆ " ระยะเวลา การพิมพ์แลมบ์ดาในล่ามไม่ได้ช่วยอะไรมาก
S.Lott

11
@Javier ฉันเห็นด้วยกับคุณถ้าคุณกำลังพูดถึง "แลมบ์ดา" แนวคิด; อย่างไรก็ตามถ้าเรากำลังพูดถึง "lambda" คำสำคัญของ python ก็คือ: 1) ฟังก์ชั่นที่ตั้งชื่อนั้นเร็วกว่าและสามารถทำได้มากกว่า (statement + expression) เกือบทุกที่ที่คุณจะใช้ lambdas (map + filter) คุณสามารถสร้าง expressions หรือรายการ comprehensions ซึ่งมีประสิทธิภาพและรัดกุมมากขึ้น ฉันไม่ได้บอกว่าฟังก์ชั่นชั้นหนึ่งไม่เจ๋งแค่ว่าคำหลัก "แลมบ์ดา" ในไพ ธ อนนั้นไม่ดีเท่ากับการใช้ฟังก์ชั่นที่ตั้งชื่อนั่นคือทั้งหมด
Aaron Maenpaa

3
แลมบ์ดาเป็นสิ่งที่ขาดไม่ได้สำหรับฉันสำหรับการใช้งานกับฟังก์ชั่นที่รับอาร์กิวเมนต์โทรกลับเช่น key = อาร์กิวเมนต์เพื่อเรียงลำดับ () และเรียง ()
Rick Copeland

19
@Rick ฉันไม่สงสัยเลยว่า แต่ความจริงคือถ้าคุณเห็น "แลมบ์ดา" และคุณคิดว่า "zohmygod lambda" และเริ่มเขียนรหัสโครงการในไพ ธ อนคุณจะผิดหวังอย่างแน่นอนโดยข้อ จำกัด ของการแสดงออกแลมบ์ ธ ของไพ ธ อน ในทางกลับกันถ้าคุณเริ่มคิดกับตัวเองว่า "รายการความเข้าใจจะทำงานได้หรือไม่ไม่สิ่งที่ฉันต้องได้รับประโยชน์จากการเป็นฟังก์ชั่นที่มีชื่อหรือไม่ไม่ดี: เรียงลำดับ (xs, key = lambda x: x.name, x.height) "คุณอาจจะใช้แลมบ์ดาในจำนวนครั้งที่เหมาะสม
Aaron Maenpaa

4
+1: ฉันไม่สามารถความเครียดที่เพียงพอเมื่อหนึ่งใช้แลมบ์ดาหนึ่งใช้ฟังก์ชันนิรนาม และชื่อมีมูลค่าเพิ่มทางปัญญาอันมีค่า
Stephane Rolland

19

ฉันใช้ Python มาหลายปีแล้วและฉันก็ไม่เคยเจอกับกรณีที่ฉันต้องการแลมบ์ดา ที่จริงแล้วในขณะที่การสอนมันเป็นเพียงน้ำตาล syntactic


8
พวกเขาเป็นอย่างมากที่มีประโยชน์เมื่อมีการพัฒนา GUI โดยใช้หลาม บ่อยครั้งที่วิดเจ็ตต้องการการอ้างอิงไปยังฟังก์ชั่น หากคุณต้องการวิดเจ็ตเพื่อเรียกใช้ฟังก์ชันและส่งผ่านข้อโต้แย้งแลมบ์ดาเป็นวิธีที่สะดวกมากในการทำเช่นนั้น
ไบรอัน Oakley

1
อะไรคือข้อได้เปรียบในการส่งอาร์กิวเมนต์จำนวนมากไปยังฟังก์ชัน func_name (a, b): ส่งคืน a + b แทนที่จะใช้ lambda
dter

2
ไม่จำเป็นแต่ช่วยในการเขียนรหัสที่สั้นลงและอ่านได้ง่ายขึ้นในหลาย ๆ กรณี ในภาษา verbose เช่น Java หรือ C ++
phuclv

17

ฉันไม่สามารถพูดถึงการใช้แลมบ์ดาของไพ ธ อนได้ แต่โดยทั่วไปแลมบ์ดาฟังก์ชั่นนั้นมีประโยชน์จริงๆ พวกเขาเป็นเทคนิคหลัก (อาจเป็นเทคนิค) ของการตั้งโปรแกรมการทำงานและพวกเขายังมีประโยชน์มากในโปรแกรมเชิงวัตถุ สำหรับปัญหาบางประเภทพวกเขาเป็นทางออกที่ดีที่สุดดังนั้นไม่ควรลืมอย่างแน่นอน!

ฉันขอแนะนำให้คุณอ่านข้อมูลเกี่ยวกับการปิดและฟังก์ชั่นแผนที่ (ที่เชื่อมโยงไปยังเอกสารหลาม แต่มันมีอยู่ในเกือบทุกภาษาที่รองรับโครงสร้างการทำงาน) เพื่อดูว่าทำไมมันมีประโยชน์


3
สิ่งนั้นสามารถทำได้โดยไม่ต้อง lambdas มันเป็นเรื่องยุ่งยากขนาดใหญ่
ไบรอัน

17

ฟังก์ชั่นแลมบ์ดาเป็นวิธีที่ไม่มีประสิทธิภาพในการสร้างฟังก์ชั่น

แค่นั้นแหละ. ตัวอย่างเช่นสมมติว่าคุณมีฟังก์ชั่นหลักและจำเป็นต้องมีค่ากำลังสอง ลองดูวิธีดั้งเดิมและวิธีแลมบ์ดาในการทำสิ่งนี้:

แบบดั้งเดิม:

def main():
...
...
y = square(some_number)
...
return something

def square(x):
    return x**2

วิธีแลมบ์ดา:

def main():
...
square = lambda x: x**2
y = square(some_number)
return something

ดูความแตกต่าง?

ฟังก์ชั่นแลมบ์ดาทำได้ดีมากกับรายการต่างๆเช่นรายการความเข้าใจหรือแผนที่ ในความเป็นจริงรายการเข้าใจเป็นวิธี "pythonic" เพื่อแสดงตัวเองโดยใช้แลมบ์ดา Ex:

>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]

เรามาดูความหมายขององค์ประกอบของไวยากรณ์ว่า:

[]: "ส่งรายการให้ฉัน"

x ** 2: "ใช้ฟังก์ชั่นที่เกิดใหม่นี้"

สำหรับ x ใน a: "ในแต่ละองค์ประกอบใน"

สะดวกใช่มั้ย การสร้างฟังก์ชั่นเช่นนี้ ลองเขียนใหม่โดยใช้แลมบ์ดา:

>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]

ทีนี้ลองใช้แผนที่ซึ่งเป็นสิ่งเดียวกัน แต่เป็นกลางมากกว่าภาษา แผนที่ใช้เวลา 2 ข้อโต้แย้ง:

(i) ฟังก์ชั่นเดียว

(ii) iterable

และให้รายการของฟังก์ชั่นที่ใช้กับแต่ละองค์ประกอบของ iterable

ดังนั้นโดยใช้แผนที่เราจะได้:

>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)

หากคุณเชี่ยวชาญ lambdas และการแมปคุณจะมีพลังอันยิ่งใหญ่ในการจัดการข้อมูลและกระชับ ฟังก์ชั่นของแลมบ์ดานั้นไม่ได้คลุมเครือและไม่ทำให้เกิดความคมชัดของรหัส อย่าสับสนสิ่งที่ยากกับสิ่งใหม่ เมื่อคุณเริ่มใช้พวกเขาคุณจะพบว่ามันชัดเจนมาก


13

หนึ่งในสิ่งที่ดีเกี่ยวกับlambdaที่อยู่ในความคิดของฉัน understated คือว่ามันเป็นวิธีการเลื่อนการประเมินผลสำหรับรูปแบบที่เรียบง่ายจนจำเป็นต้องมีค่า ให้ฉันอธิบาย

ไลบรารีรูทีนจำนวนมากถูกนำไปใช้เพื่ออนุญาตให้พารามิเตอร์บางอย่างเป็น callables (ซึ่งแลมบ์ดาเป็นหนึ่ง) แนวคิดคือมูลค่าที่แท้จริงจะถูกคำนวณเฉพาะในเวลาที่จะถูกนำไปใช้ (แทนที่จะเป็นเมื่อเรียกว่า) ตัวอย่าง (วางแผน) อาจช่วยอธิบายประเด็นได้ สมมติว่าคุณมีกิจวัตรซึ่งจะทำบันทึกเวลาที่กำหนด คุณต้องการให้รูทีนใช้เวลาปัจจุบันลบด้วย 30 นาที คุณจะเรียกมันว่าเป็นอย่างนั้น

log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))

ทีนี้สมมติว่าฟังก์ชั่นที่เกิดขึ้นจริงจะถูกเรียกเมื่อเหตุการณ์บางอย่างเกิดขึ้นและคุณต้องการให้การคำนวณเวลาประทับเท่านั้น ณ เวลานั้น คุณสามารถทำเช่นนี้ได้

log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))

สมมติว่าlog_timestampสามารถจัดการ callables ได้เช่นนี้มันจะประเมินสิ่งนี้เมื่อมันต้องการและคุณจะได้รับการประทับเวลาในเวลานั้น

มีวิธีอื่นที่แน่นอนในการทำเช่นนี้ (โดยใช้operatorตัวอย่างเช่นโมดูล) แต่ฉันหวังว่าฉันจะถ่ายทอดประเด็นนี้

อัปเดต : นี่คือตัวอย่างของโลกแห่งความเป็นจริงที่ชัดเจนกว่าเล็กน้อย

อัปเดต 2 : ฉันคิดว่านี่เป็นตัวอย่างของสิ่งที่เรียกว่าหนึ่งthunk


11

ตามที่ระบุไว้ข้างต้นตัวดำเนินการแลมบ์ดาใน Python กำหนดฟังก์ชันที่ไม่ระบุชื่อและในฟังก์ชั่น Python จะปิด มันเป็นสิ่งสำคัญที่จะไม่สับสนแนวคิดของการปิดกับแลมบ์ดาโอเปอเรเตอร์ซึ่งเป็นเพียงเมทาโดนวากยสัมพันธ์สำหรับพวกเขา

เมื่อฉันเริ่มต้นใน Python ไม่กี่ปีที่ผ่านมาฉันใช้ lambdas มากคิดว่ามันเจ๋งพร้อมกับความเข้าใจในรายการ อย่างไรก็ตามฉันเขียนและต้องรักษาเว็บไซต์ขนาดใหญ่ที่เขียนด้วย Python โดยเรียงตามลำดับของคะแนนฟังก์ชั่นหลายพันคะแนน ฉันได้เรียนรู้จากประสบการณ์ว่า lambdas อาจจะโอเคกับสิ่งต่าง ๆ ที่มีอยู่เดิม แต่ไม่มีอะไรในฟังก์ชั่นอินไลน์ (ชื่อปิด) ยกเว้นการบันทึกคีย์สโต๊กบางครั้ง

โดยทั่วไปสิ่งนี้จะทำให้เดือดหลาย ๆ จุด:

  • ง่ายต่อการอ่านซอฟต์แวร์ที่เขียนอย่างชัดเจนโดยใช้ชื่อที่มีความหมาย การปิดนิรนามโดยนิยามไม่สามารถมีชื่อที่สื่อความหมายได้เนื่องจากไม่มีชื่อ ความกะทัดรัดนี้ดูเหมือนว่าด้วยเหตุผลบางประการที่ทำให้พารามิเตอร์แลมบ์ดาติดเชื้อด้วยดังนั้นเรามักจะเห็นตัวอย่างเช่นแลมบ์ดา x: x + 1
  • เป็นการง่ายกว่าที่จะใช้การปิดชื่อซ้ำอีกครั้งเนื่องจากสามารถอ้างถึงได้มากกว่าหนึ่งครั้งเมื่อมีชื่อที่ใช้อ้างอิงถึงพวกเขาด้วย
  • ง่ายต่อการตรวจแก้จุดบกพร่องรหัสที่ใช้ชื่อ closures แทน lambdas เนื่องจากชื่อจะปรากฏในการสืบค้นกลับและรอบข้อผิดพลาด

นั่นเป็นเหตุผลเพียงพอที่จะปัดเศษมันขึ้นและแปลงเป็นชื่อปิด อย่างไรก็ตามฉันมีความเสียใจอีกสองข้อต่อการปิดที่ไม่ระบุชื่อ

ความขุ่นเคืองแรกก็คือพวกเขาเป็นเพียงคำหลักที่ไม่จำเป็นซึ่งทำให้ภาษาสับสน

ความขุ่นแค้นที่สองนั้นลึกซึ้งยิ่งขึ้นและในระดับกระบวนทัศน์นั่นคือฉันไม่ชอบที่พวกเขาส่งเสริมรูปแบบการเขียนโปรแกรมที่ใช้งานได้เพราะรูปแบบนั้นมีความยืดหยุ่นน้อยกว่าการส่งผ่านข้อความรูปแบบเชิงวัตถุหรือกระบวนงาน เสร็จสมบูรณ์ (โชคดีที่ Python เรายังสามารถแยกข้อ จำกัด นั้นออกได้แม้ในแลมบ์ดา) เหตุผลที่ฉันรู้สึกว่า lambdas ส่งเสริมสไตล์นี้คือ:

  • มีการส่งกลับโดยปริยายนั่นคือดูเหมือนว่าพวกเขาควรจะเป็นฟังก์ชัน

  • พวกมันเป็นกลไกการซ่อนสถานะทางเลือกสำหรับกลไกอื่นที่ชัดเจนกว่าอ่านได้มากขึ้นนำมาใช้ซ้ำได้มากขึ้นและกลไกทั่วไปมากขึ้น: เมธอด

ฉันพยายามอย่างหนักในการเขียน Python ที่ปราศจากแลมบ์ดาและลบแลมบ์ดาออกจากสายตา ฉันคิดว่า Python จะเป็นภาษาที่ดีกว่าเล็กน้อยโดยไม่มี lambdas แต่นั่นเป็นเพียงความคิดเห็นของฉัน


1
"... ในฟังก์ชั่น Python ปิด" มันไม่ถูกต้องเท่าที่ฉันเข้าใจ การปิดเป็นฟังก์ชั่น แต่ฟังก์ชั่นไม่ได้ปิดอยู่เสมอ ฟังก์ชั่น -> แลมบ์ดา x, y: x + y ปิด -> แลมบ์ดา x: แลมบ์ดา y: x + y
0atman

6
"เนื่องจากแคลคูลัสแลมบ์ดาไม่ทัวริงสมบูรณ์" เป็นข้อผิดพลาดธรรมดาแลมบ์ดาแลมบ์ดาไม่ถูกพิมพ์ทัวริงสมบูรณ์ทัวริงนั่นคือเหตุผลว่าทำไมมันจึงสำคัญ คุณสามารถรับการสอบถามซ้ำโดยใช้ Y-combinatorY = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Antti Haapala

นอกจากนี้หากมีใครไปที่ Wikipedia เพื่ออ่านเกี่ยวกับความสมบูรณ์ของทัวริงก็กล่าวว่า "ตัวอย่างคลาสสิกคือแคลคูลัสแลมบ์ดา"
Antti Haapala

อย่างจริงจัง - ไม่ทัวริงเสร็จ - คำตอบนี้ต้องมีการแก้ไขหรือเพิกถอนอย่างจริงจัง
Tony Suffolk 66

@ MarcinŁośโหวตขึ้นเพราะเป็นไปตาม KISS จากการเปรียบเทียบหนังสือ K&R กล่าวว่าในขณะที่การใช้การมอบหมายเป็นส่วนหนึ่งหรือการแสดงออกที่มีขนาดใหญ่กว่านั้นมีขนาดกะทัดรัดกว่า แต่ก็มักจะอ่านได้น้อยกว่า trend-wagon ของการใช้รูปแบบการเขียนโปรแกรมใช้งานได้นั้นซ้ำซากและเบื่อหน่าย มันเพียงพอที่จะระบุว่าพวกเขาสามารถนำมาใช้ได้อย่างไร แต่มันเกินความจริงที่จะกล่าวว่าพวกเขามีความสำคัญยิ่งที่จะเป็นนักพัฒนาที่มีความสามารถ อัตนัยอย่างสมบูรณ์ อาร์กิวเมนต์นี้คล้ายคลึงกับนักพัฒนา C ++ ที่อ้างว่าภาษาที่ไม่มีคลาสนั้นเป็นแบบดั้งเดิมต่ำกว่าและไม่เพียงพอ "ทัวริงสมบูรณ์" อาร์กิวเมนต์เป็นอวดความรู้
typedeaf

11

แลมบ์ดาเป็นสิ่งก่อสร้างที่ทรงพลังอย่างแท้จริงซึ่งเกิดจากแนวคิดในการเขียนโปรแกรมการทำงานและเป็นสิ่งที่ไม่สามารถแก้ไขแก้ไขหรือลบทิ้งได้ในอนาคตอันใกล้ของ Python พวกเขาช่วยให้คุณเขียนโค้ดที่มีประสิทธิภาพยิ่งขึ้นเพราะจะช่วยให้คุณสามารถส่งผ่านฟังก์ชั่นเป็นพารามิเตอร์ได้ดังนั้นแนวคิดของฟังก์ชั่นในฐานะพลเมืองชั้นหนึ่ง

แลมบ์ดามีแนวโน้มที่จะทำให้เกิดความสับสน แต่เมื่อได้รับความเข้าใจที่ดีแล้วคุณสามารถเขียนโค้ดที่สง่างามเช่นนี้:

squared = map(lambda x: x*x, [1, 2, 3, 4, 5])

บรรทัดด้านบนของโค้ดส่งคืนรายการของกำลังสองของตัวเลขในรายการ แน่นอนคุณสามารถทำเช่น:

def square(x):
    return x*x

squared = map(square, [1, 2, 3, 4, 5])

จะเห็นได้ชัดว่าโค้ดเก่านั้นสั้นกว่าและนี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งหากคุณต้องการใช้ฟังก์ชั่นแผนที่ (หรือฟังก์ชั่นอื่น ๆ ที่คล้ายกันซึ่งรับฟังก์ชั่นเป็นพารามิเตอร์) ในที่เดียวเท่านั้น นอกจากนี้ยังทำให้รหัสใช้งานง่ายและสวยงามยิ่งขึ้น

นอกจากนี้ตามที่ @David Zaslavsky พูดถึงในคำตอบของเขาความเข้าใจในรายการไม่ได้เป็นวิธีที่จะไปโดยเฉพาะอย่างยิ่งหากรายการของคุณต้องได้รับค่าจากวิธีการทางคณิตศาสตร์ที่คลุมเครือ

จากมุมมองที่ใช้งานได้จริงมากขึ้นข้อดีอย่างหนึ่งของ lambdas สำหรับฉันเมื่อเร็ว ๆ นี้คือใน GUI และการเขียนโปรแกรมที่ขับเคลื่อนด้วยเหตุการณ์ หากคุณดูการโทรกลับใน Tkinter สิ่งที่พวกเขาใช้เป็นข้อโต้แย้งคือเหตุการณ์ที่ทำให้พวกเขา เช่น

def define_bindings(widget):
    widget.bind("<Button-1>", do-something-cool)

def do-something-cool(event):
    #Your code to execute on the event trigger

ตอนนี้ถ้าคุณมีข้อโต้แย้งที่จะผ่าน? บางอย่างง่ายดายเพียงแค่ส่ง 2 ข้อโต้แย้งเพื่อจัดเก็บพิกัดของการคลิกเมาส์ คุณสามารถทำสิ่งนี้ได้อย่างง่ายดาย:

def main():
    # define widgets and other imp stuff
    x, y = None, None
    widget.bind("<Button-1>", lambda event: do-something-cool(x, y))

def do-something-cool(event, x, y):
    x = event.x
    y = event.y
    #Do other cool stuff

ตอนนี้คุณสามารถยืนยันว่าสิ่งนี้สามารถทำได้โดยใช้ตัวแปรทั่วโลก แต่คุณต้องการที่จะปังหัวของคุณกังวลเกี่ยวกับการจัดการหน่วยความจำและการรั่วไหลโดยเฉพาะอย่างยิ่งถ้าตัวแปรทั่วโลกจะถูกนำมาใช้ในที่เดียว? นั่นจะเป็นรูปแบบการเขียนโปรแกรมที่ไม่ดี

กล่าวโดยสรุปแลมบ์ดานั้นยอดเยี่ยมและไม่ควรประมาท Python lambdas นั้นไม่เหมือนกับ LISP lambdas (ซึ่งมีพลังมากกว่า) แต่คุณสามารถทำสิ่งมหัศจรรย์มากมายกับพวกมันได้


ขอบคุณ ฉันไม่เข้าใจตัวอย่างสุดท้ายของคุณอย่างสมบูรณ์ ทำไม x และ y จึงถูกกำหนดในทั้งสองmainและdo_something_cool? เกิดอะไรขึ้นกับxและyในฟังก์ชั่น? ค่าที่ผ่านมาดูเหมือนจะถูกเขียนทับทันทีหรือไม่ ฟังก์ชั่นรู้ได้eventอย่างไร? คุณสามารถเพิ่มความคิดเห็น / คำอธิบายได้ไหม? ขอบคุณ
Sanjay Manohar

@SanjayManohar ฉันผ่านxและyเป็นข้อโต้แย้งกับdo-something-coolและค่าของพวกเขาจะถูกตั้งค่าในฟังก์ชั่นเพื่อแสดงให้เห็นว่าคุณสามารถใช้ lambdas เพื่อส่งผ่านข้อโต้แย้งที่ไม่มีใครคาดหวัง widget.bindฟังก์ชั่นคาดว่าจะมีeventพารามิเตอร์ซึ่งระบุเหตุการณ์ GUI บนเครื่องมือที่โดยเฉพาะอย่างยิ่ง ฉันขอแนะนำให้อ่านโมเดลการเขียนโปรแกรมของ Tkinter เพื่อความชัดเจนที่มากขึ้น
varagrawal

อืมฉันคิดว่าฉันเข้าใจโมเดล Tkinter แต่ก็ยังไม่เข้าใจมาก - คุณผ่านแล้วทำx,y x=event.xไม่ได้เขียนทับค่าที่คุณส่งผ่านหรือไม่ และฟังก์ชั่นรู้ได้อย่างไรว่าeventมันคืออะไร? ฉันไม่เห็นว่าคุณผ่านสิ่งนั้นไปยังฟังก์ชั่นใด หรือมันเป็นวิธีการ? นอกจากนี้คุณยังได้รับอนุญาตลบเครื่องหมายในชื่อฟังก์ชั่น?
Sanjay Manohar

@SanjayManohar เพื่อนคุณต้องอ่านบน Tkinter และ Python Tkinter ผ่านวัตถุเหตุการณ์ฟังก์ชั่นเป็นการกระทำเริ่มต้น สำหรับตัวอย่างx, yนั้นเป็นเพียงตัวอย่างเพื่อจุดประสงค์ในการอธิบาย ฉันพยายามแสดงพลังของ lambdas ไม่ใช่ Tkinter :)
varagrawal

1
ตกลงตอนนี้ฉันเห็นสิ่งที่คุณต้องการ - คุณต้องการให้ฟังก์ชันรับeventหรือไม่ ในกรณีนั้นแลมบ์ดาของคุณไม่ควรอ่านlambda event: do_something_cool(event,x,y)หรือ
Sanjay Manohar

8

แลมบ์ดานั้นเชื่อมโยงกับสไตล์การเขียนโปรแกรมการใช้งานทั่วไป แนวคิดที่ว่าคุณสามารถแก้ปัญหาได้โดยการนำฟังก์ชั่นไปใช้กับข้อมูลบางส่วนและรวมผลลัพธ์เข้าด้วยกันคือสิ่งที่ google ใช้ในการใช้อัลกอริทึมส่วนใหญ่

โปรแกรมที่เขียนในรูปแบบการเขียนโปรแกรมฟังก์ชั่นนั้นขนานกันได้ง่ายและด้วยเหตุนี้จึงมีความสำคัญมากขึ้นเรื่อย ๆ กับเครื่องมัลติคอร์ที่ทันสมัย ดังนั้นในระยะสั้นไม่คุณไม่ควรลืมพวกเขา


7

ขอแสดงความยินดีครั้งแรกที่สามารถจัดการแลมบ์ดาได้ ในความคิดของฉันนี่เป็นสิ่งที่ทรงพลังจริงๆ แนวโน้มวันนี้ต่อภาษาการเขียนโปรแกรมการทำงานแน่นอนตัวบ่งชี้ว่ามันไม่ควรหลีกเลี่ยงหรือจะกำหนดใหม่ในอนาคตอันใกล้

คุณต้องคิดแตกต่างกันเล็กน้อย ฉันแน่ใจว่าเร็ว ๆ นี้คุณจะรักมัน แต่ระวังถ้าคุณจัดการกับงูหลามเท่านั้น เนื่องจากแลมบ์ดานั้นไม่ใช่การปิดจริงมันจึง“ แตก” อย่างใด: แลมบ์ ธ pythons ถูกทำลาย


แลมบ์ดาของไพ ธ อนไม่หัก มีสองวิธีในการจัดการกับคนท้องถิ่นใน lambdas ทั้งสองมีข้อดีและข้อเสีย ฉันคิดว่าวิธีการที่ Python (และ C #) ใช้อาจเป็นสิ่งที่ตรงกันข้ามกับผู้ที่คุ้นเคยกับภาษาที่ใช้งานได้ดีกว่าเนื่องจากด้วยภาษาที่ใช้งานได้จริงฉันไม่คิดว่าวิธีการนี้จะสมเหตุสมผล
ไบรอัน

มันใช้งานง่าย ฉันไม่ได้เป็นโปรแกรมเมอร์ของงูหลาม แต่ในกระดานเสากระโดงเล็ก ๆ มันเหมือนกันและฉันก็ทำอย่างนี้อย่างสม่ำเสมอ ดังนั้นแม้ผมจะพิจารณามันว่า "เสีย" :)
Norbert Hartl

ไม่มันไม่มีส่วนเกี่ยวข้องกับการตอบโต้ มันเป็นเพียงแค่ขอบเขตศัพท์ของชื่อตัวแปรเป็นที่ของฟังก์ชั่น; ลูปไม่แนะนำขอบเขตคำศัพท์ ฟังก์ชั่นยังทำงานในลักษณะเดียวกันใน Javascript หากคุณต้องการขอบเขตสำหรับ var คุณสามารถทำได้ (lambda scopedvar: lambda x: scopedvar + x) ()
Antti Haapala

6

ฉันเพิ่งเริ่มต้น Python และมุ่งหน้าไปที่ Lambda เป็นอันดับแรกซึ่งใช้เวลาพอสมควรในการคิด

โปรดทราบว่านี่ไม่ใช่การตัดสินของอะไรเลย ทุกคนมีสิ่งต่าง ๆ ที่ไม่ได้มาอย่างง่ายดาย

แลมบ์ดาเป็นหนึ่งในรายการภาษาที่ 'น่าสนใจ' ที่ควรลืมในชีวิตจริงหรือไม่?

เลขที่

ฉันแน่ใจว่ามีบางกรณีที่อาจจำเป็นต้องใช้ขอบ แต่ให้ความสับสนของมัน

มันไม่ชัดเจน 2 ทีมที่ผ่านมาที่ฉันทำงานทุกคนใช้คุณสมบัตินี้ตลอดเวลา

ศักยภาพของมันถูกนิยามใหม่ในการเปิดตัวในอนาคต (สมมติฐานของฉันขึ้นอยู่กับคำจำกัดความที่หลากหลายของมัน)

ฉันไม่เห็นข้อเสนอที่จริงจังในการกำหนดใหม่ใน Python เกินกว่ากำหนดความหมายปิดเมื่อไม่กี่ปีที่ผ่านมา

และการเข้ารหัสที่ลดลง - ควรหลีกเลี่ยงหรือไม่?

ยังไม่ชัดเจนถ้าคุณใช้ถูกต้อง ในทางตรงกันข้ามการมีโครงสร้างทางภาษามากขึ้นจะช่วยเพิ่มความชัดเจน

สิ่งนี้ทำให้ฉันนึกถึงการโอเวอร์โฟลว์ (บัฟเฟอร์โอเวอร์โฟลว์) ของประเภท C - ชี้ไปที่ตัวแปรด้านบนและการโหลดมากเกินไปเพื่อตั้งค่าฟิลด์อื่น ๆ ... เรียงลำดับจากนักแสดงด้านเทคนิค

แลมบ์ดาเป็นเหมือนบัฟเฟอร์ล้น ว้าว. ฉันนึกไม่ออกว่าคุณใช้แลมบ์ดาอย่างไรถ้าคุณคิดว่ามันเป็น "ฝันร้ายการบำรุงรักษา"


5
-1 ที่ทำให้ฉัน (และคนอื่น ๆ ) อ่านคำถามทั้งหมดอีกครั้ง โปรดทราบว่าคนอื่นสามารถตอบได้โดยไม่ต้องทำ
Paweł Polewicz

6

ฉันใช้ lambdas เพื่อหลีกเลี่ยงการทำสำเนารหัส มันจะทำให้ฟังก์ชั่นที่เข้าใจได้ง่ายเช่น:

def a_func()
  ...
  if some_conditon:
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)
  else
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)

ฉันแทนที่มันด้วยแลมบ์ดาอุณหภูมิ

def a_func()
  ...
  call_big_f = lambda args_that_change: call_some_big_func(arg1, arg2, arg3, args_that_change)
  if some_conditon:
     ...
     call_big_f(argX)
  else
     ...
     call_big_f(argY)

5

ฉันเริ่มอ่านหนังสือของ David Mertz วันนี้ 'การประมวลผลข้อความใน Python' ในขณะที่เขามีคำอธิบายสั้น ๆ ที่เป็นธรรมของแลมบ์ดาตัวอย่างในบทแรกที่รวมกับคำอธิบายในภาคผนวก A ทำให้พวกเขากระโดดออกจากหน้าสำหรับฉัน (ในที่สุด) และในทันใดฉันเข้าใจถึงคุณค่าของพวกเขา ไม่ได้หมายความว่าคำอธิบายของเขาจะทำงานให้คุณและฉันยังอยู่ในขั้นตอนการค้นพบดังนั้นฉันจะไม่พยายามเพิ่มคำตอบเหล่านี้นอกเหนือจากต่อไปนี้: ฉันใหม่กับ Python ฉันใหม่กับ OOP Lambdas เป็นการต่อสู้เพื่อฉัน ตอนนี้ฉันอ่าน Mertz ฉันคิดว่าฉันเข้าใจพวกเขาและฉันเห็นว่ามันมีประโยชน์มากเพราะฉันคิดว่าพวกเขาอนุญาตวิธีการเขียนโปรแกรมที่สะอาดขึ้น

เขาทำซ้ำ Zen of Python หนึ่งบรรทัดซึ่งSimple ง่ายดีกว่าซับซ้อน ในฐานะที่เป็นโปรแกรมเมอร์ที่ไม่ใช่การอ่านรหัส OOP กับ lambdas (และจนถึงความเข้าใจในรายการสัปดาห์ที่แล้ว) ฉันมีความคิด - นี่เป็นเรื่องง่าย? . ในที่สุดฉันก็รู้ว่าวันนี้จริง ๆ แล้วคุณสมบัติเหล่านี้ทำให้โค้ดอ่านได้ง่ายขึ้นและเข้าใจได้ดีกว่าตัวเลือก - ซึ่งเป็นวงวนของการเรียงลำดับ ฉันก็ตระหนักว่าเช่นเดียวกับงบการเงิน Python ไม่ได้ออกแบบมาสำหรับผู้ใช้มือใหม่ แต่มันถูกออกแบบมาสำหรับผู้ใช้ที่ต้องการได้รับการศึกษา ฉันไม่อยากจะเชื่อเลยว่าภาษานี้ทรงพลังเพียงใด เมื่อถึงรุ่งเช้า (ในที่สุด) จุดประสงค์และคุณค่าของลูกแกะฉันต้องการที่จะทำลายโปรแกรมประมาณ 30 รายการและเริ่มต้นวางลูกแกะในตำแหน่งที่เหมาะสม


5

กรณีที่มีประโยชน์สำหรับการใช้ lambdas คือการปรับปรุงความสามารถในการอ่านของรายการที่เข้าใจง่าย ในตัวอย่างloop_dicนี้ย่อมาจากความชัดเจน แต่คิดว่าloop_dicนานมาก หากคุณเพียงแค่จะใช้เป็นค่าธรรมดาที่มีแทนรุ่นแลมบ์ดาของมูลค่าที่คุณจะได้รับiNameError

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> loop_dic = lambda i: {"name": i["name"] + " Wallace" }
>>> new_lis = [loop_dic(i) for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

แทน

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> new_lis = [{"name": i["name"] + " Wallace"} for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

5

ฉันสามารถให้คุณตัวอย่างที่ฉันต้องการแลมบ์ดาจริงจัง ฉันกำลังสร้างโปรแกรมกราฟิกที่ผู้ใช้คลิกขวาที่ไฟล์และกำหนดหนึ่งในสามตัวเลือก ปรากฎว่าใน Tkinter (โปรแกรมเชื่อมต่อ GUI ที่ฉันกำลังเขียนนี้) เมื่อมีคนกดปุ่มมันไม่สามารถกำหนดให้กับคำสั่งที่รับอาร์กิวเมนต์ได้ ดังนั้นถ้าฉันเลือกหนึ่งในตัวเลือกและต้องการผลลัพธ์ของตัวเลือกของฉัน:

print 'hi there'

แล้วไม่มีเรื่องใหญ่ แต่ถ้าฉันต้องการตัวเลือกของฉันจะมีรายละเอียดเฉพาะ ตัวอย่างเช่นถ้าฉันเลือกตัวเลือก A มันเรียกใช้ฟังก์ชันที่รับอาร์กิวเมนต์บางตัวซึ่งขึ้นอยู่กับตัวเลือก A, B หรือ C ซึ่ง TKinter ไม่สามารถรองรับสิ่งนี้ได้ แลมดาเป็นทางเลือกเดียวที่จะหลีกเลี่ยงสิ่งนี้ได้จริง ...


2
ดีสันนิษฐานว่าคุณจะได้ทำdef foo...และส่งผ่านไปในนั้นแทนfoo lambdaมันเป็นรหัสที่มากกว่าและคุณต้องมีชื่อ
Jon Coombs

4

ฉันใช้มันบ่อยครั้งส่วนใหญ่เป็นวัตถุว่างเปล่าหรือเพื่อผูกพารามิเตอร์บางส่วนกับฟังก์ชั่น

นี่คือตัวอย่าง:

เพื่อใช้รูปแบบวัตถุ null:

{
    DATA_PACKET: self.handle_data_packets
    NET_PACKET: self.handle_hardware_packets
}.get(packet_type, lambda x : None)(payload)

สำหรับการผูกพารามิเตอร์:

สมมติว่าฉันมี API ต่อไปนี้

def dump_hex(file, var)
    # some code
    pass

class X(object):
    #...
    def packet_received(data):
        # some kind of preprocessing
        self.callback(data)
    #...

จากนั้นเมื่อฉันไม่ต้องการถ่ายโอนข้อมูลที่ได้รับไปยังไฟล์อย่างรวดเร็วฉันก็ทำเช่นนั้น:

dump_file = file('hex_dump.txt','w')
X.callback = lambda (x): dump_hex(dump_file, x)
...
dump_file.close()

4

ฉันใช้ lambdaเพื่อสร้างการเรียกกลับที่มีพารามิเตอร์ มันสะอาดกว่าการเขียนแลมบ์ดาในหนึ่งบรรทัดแทนที่จะเขียนวิธีการทำงานแบบเดียวกัน

ตัวอย่างเช่น:

import imported.module

def func():
    return lambda: imported.module.method("foo", "bar")

ตรงข้ามกับ:

import imported.module

def func():
    def cb():
        return imported.module.method("foo", "bar")
    return cb

4

ฉันเป็นผู้เริ่มต้นของงูใหญ่ดังนั้นเพื่อให้ได้แนวคิดที่ชัดเจนเกี่ยวกับแลมบ์ดาฉันเปรียบเทียบกับลูป 'for' ในแง่ของประสิทธิภาพ นี่คือรหัส (python 2.7) -

import time
start = time.time() # Measure the time taken for execution

def first():
    squares = map(lambda x: x**2, range(10))
    # ^ Lambda
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0 seconds

def second():
    lst = []
    for i in range(10):
        lst.append(i**2)
    # ^ a 'for' loop
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0019998550415 seconds.

print abs(second() - first()) # Gives 0.0019998550415 seconds!(duh)

6
คุณอาจสนใจtimeitโมดูลซึ่งโดยทั่วไปจะให้ผลลัพธ์ที่แม่นยำกว่าการลบtime.time()ค่า
เควิน

2
อืมคุณไม่จำเป็นต้องรีสตาร์ทเครื่องจับเวลาเมื่อเริ่มต้น () ครั้งแรกและครั้งที่สอง ()?
qneill

2

แลมบ์ดาเป็นตัวสร้างโพรซีเดอร์ คุณสามารถสังเคราะห์โปรแกรมได้ในเวลาทำงานแม้ว่าแลมบ์ดาของไพ ธ อนจะไม่ทรงพลังมาก โปรดทราบว่าบางคนเข้าใจการเขียนโปรแกรมประเภทนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.