รายการความเข้าใจกับตัวกรองแลมบ์ดา +


857

ฉันพบว่าตัวเองมีความจำเป็นในการกรองขั้นพื้นฐาน: ฉันมีรายการและฉันต้องกรองตามคุณลักษณะของรายการ

รหัสของฉันดูเหมือนว่านี้:

my_list = [x for x in my_list if x.attribute == value]

แต่ฉันก็คิดว่ามันคงจะดีกว่าถ้าเขียนมันแบบนี้?

my_list = filter(lambda x: x.attribute == value, my_list)

สามารถอ่านได้มากขึ้นและหากจำเป็นสำหรับการแสดงแลมบ์ดาสามารถนำออกมาเพื่อรับบางสิ่งได้

คำถามคือมีคำเตือนในการใช้วิธีที่สองหรือไม่? มีความแตกต่างด้านประสิทธิภาพหรือไม่ ฉันทำ Pythonic Way ™หายไปทั้งหมดและควรทำในวิธีอื่น (เช่นใช้ itemgetter แทนที่จะเป็นแลมบ์ดา) หรือไม่?


19
ตัวอย่างที่ดีกว่าอาจเป็นกรณีที่คุณมีฟังก์ชั่นที่ตั้งชื่อไว้เป็นอย่างดีเพื่อใช้เป็นเพรดิเคตของคุณ ในกรณีนี้ฉันคิดว่าผู้คนจำนวนมากจะยอมรับว่าfilterสามารถอ่านได้มากขึ้น เมื่อคุณมีการแสดงออกง่าย ๆ ที่สามารถใช้ตามที่เป็นอยู่ใน listcomp แต่จะต้องห่อในแลมบ์ดา (หรือสร้างจากpartialหรือoperatorหน้าที่อื่น ๆ ที่คล้ายกันฯลฯ ) เพื่อส่งผ่านfilterนั่นคือเมื่อ listcomps ชนะ
abarnert

3
มันควรจะกล่าวว่าใน Python3 อย่างน้อยการกลับมาของfilterวัตถุตัวสร้างตัวกรองไม่ใช่รายการ
Matteo Ferla

คำตอบ:


588

มันแปลกที่ความงามแตกต่างกันไปในแต่ละคน ฉันพบว่ารายการนั้นมีความเข้าใจที่ชัดเจนมากกว่าfilter+ lambdaแต่ใช้สิ่งที่คุณพบได้ง่ายกว่า

filterมีสองสิ่งที่อาจชะลอตัวลงการใช้งานของมี

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

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

ตัวเลือกอื่น ๆ ที่ควรพิจารณาคือการใช้ตัวสร้างแทนความเข้าใจในรายการ:

def filterbyvalue(seq, value):
   for el in seq:
       if el.attribute==value: yield el

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


68
+1 สำหรับเครื่องกำเนิดไฟฟ้า ฉันมีลิงก์ที่บ้านเพื่อนำเสนอที่แสดงว่าเครื่องกำเนิดไฟฟ้าที่น่าทึ่งสามารถเป็นอย่างไร นอกจากนี้คุณยังสามารถเปลี่ยนความเข้าใจของรายการที่มีการแสดงออกที่เครื่องกำเนิดไฟฟ้าเพียงแค่เปลี่ยนไป[] ()นอกจากนี้ฉันเห็นด้วยว่าคอมพ์รายการมีความสวยงามมากขึ้น
Wayne Werner

1
จริงๆแล้วไม่มีตัวกรองเร็วกว่า เพียงเรียกใช้การวัดประสิทธิภาพสองสามอย่างโดยใช้stackoverflow.com/questions/5998245/…
skqr

2
@skqr ดีกว่าที่จะใช้ timeit สำหรับการวัดประสิทธิภาพ แต่โปรดยกตัวอย่างที่คุณfilterจะพบได้เร็วขึ้นโดยใช้ฟังก์ชันการเรียกกลับของ Python
Duncan

8
@ tnq177 เป็นการนำเสนอของ David Beasley เกี่ยวกับเครื่องกำเนิดไฟฟ้า - dabeaz.com/generators
Wayne Werner

2
@ VictorSchröderใช่บางทีฉันก็ไม่ชัดเจน สิ่งที่ฉันพยายามจะพูดคือในรหัสหลักคุณต้องสามารถเห็นภาพที่ใหญ่ขึ้น ในฟังก์ชั่นตัวช่วยเล็ก ๆ คุณเพียงแค่ต้องใส่ใจกับฟังก์ชั่นหนึ่งนั้นสิ่งที่เกิดขึ้นภายนอกนั้นสามารถถูกละเว้นได้
Duncan

237

นี่เป็นปัญหาทางศาสนาใน Python แม้ว่ากุยพิจารณาลบmap, filterและreduceจากงูหลาม 3มีเพียงพอของฟันเฟืองว่าในท้ายที่สุดเพียงreduceถูกย้ายจากตัว -ins เพื่อfunctools.reduce

ส่วนตัวฉันค้นหาความเข้าใจในรายการง่ายต่อการอ่าน มันชัดเจนมากขึ้นว่าเกิดอะไรขึ้นจากนิพจน์[i for i in list if i.attribute == value]เนื่องจากพฤติกรรมทั้งหมดอยู่บนพื้นผิวที่ไม่ได้อยู่ในฟังก์ชันตัวกรอง

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

นอกจากนี้เนื่องจากBDFLต้องการให้filterหายไปจากภาษาแล้วแน่นอนว่าจะทำให้รายการความเข้าใจมากขึ้นโดยอัตโนมัติ Pythonic ;-)


1
ขอบคุณสำหรับลิงก์ไปยังอินพุตของ Guido ถ้าไม่มีอะไรอื่นสำหรับฉันนั่นหมายความว่าฉันจะพยายามไม่ใช้มันอีกต่อไปดังนั้นฉันจะไม่ติดนิสัยและฉันจะไม่สนับสนุนศาสนานั้น :)
dashesy

1
แต่การลดมีความซับซ้อนมากที่สุดในการทำเครื่องมือง่ายๆ! แผนที่และตัวกรองมีความสำคัญที่จะแทนที่ด้วยความเข้าใจ!
njzk2

8
ไม่ทราบว่าลดถูกลดระดับใน Python3 ขอบคุณสำหรับความเข้าใจ! ลด () ยังคงมีประโยชน์มากในการคำนวณแบบกระจายเช่น PySpark ฉันคิดว่านั่นเป็นข้อผิดพลาด ..
Tagar

1
@Tagar คุณยังสามารถใช้ลดคุณเพียงแค่ต้องนำเข้ามันจาก functools
icc97

69

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

กรณีการใช้งานบ่อยมากคือการดึงค่าของ X ที่ทำซ้ำได้บางส่วนไปยังเพรดิเคต P (x):

[x for x in X if P(x)]

แต่บางครั้งคุณต้องการใช้ฟังก์ชั่นบางอย่างกับค่าแรก:

[f(x) for x in X if P(f(x))]


เป็นตัวอย่างที่เฉพาะเจาะจงพิจารณา

primes_cubed = [x*x*x for x in range(1000) if prime(x)]

ฉันคิดว่ามันดูดีกว่าการใช้filterเล็กน้อย แต่ตอนนี้พิจารณา

prime_cubes = [x*x*x for x in range(1000) if prime(x*x*x)]

ในกรณีนี้เราต้องการfilterเทียบกับค่าที่คำนวณภายหลัง นอกเหนือจากปัญหาการคำนวณคิวบ์สองครั้ง (จินตนาการการคำนวณที่แพงกว่า) มีปัญหาในการเขียนนิพจน์สองครั้งละเมิดDRYความงามแบบในกรณีนี้ฉันจะใช้

prime_cubes = filter(prime, [x*x*x for x in range(1000)])

7
คุณจะไม่พิจารณาใช้ไพรม์ผ่านความเข้าใจในรายการอื่นหรือไม่? เช่น[prime(i) for i in [x**3 for x in range(1000)]]
viki.omega9

20
x*x*xไม่สามารถเป็นจำนวนเฉพาะตามที่มีx^2และxเป็นปัจจัยตัวอย่างไม่เหมาะสมจริง ๆ ในทางคณิตศาสตร์ แต่บางทีมันอาจยังคงเป็นประโยชน์ (บางทีเราสามารถหาอะไรที่ดีกว่านี้ได้ไหม?)
Zelphir Kaltstahl

3
โปรดทราบว่าเราอาจใช้นิพจน์ตัวสร้างแทนตัวอย่างล่าสุดหากเราไม่ต้องการที่จะกินความทรงจำ:prime_cubes = filter(prime, (x*x*x for x in range(1000)))
Mateen Ulhaq

4
@MateenUlhaq สิ่งนี้สามารถปรับให้เหมาะกับprime_cubes = [1]การบันทึกทั้งหน่วยความจำและ cpu cycles ;-)
Dennis Krupenik

7
@DennisKrupenik หรือมากกว่า[]
Mateen Ulhaq

29

แม้ว่าfilterอาจเป็น "วิธีที่เร็วกว่า" แต่ "Pythonic way" จะไม่สนใจสิ่งต่าง ๆ เว้นแต่ว่าประสิทธิภาพจะมีความสำคัญอย่างยิ่ง (ในกรณีนี้คุณจะไม่ใช้ Python!)


9
การแสดงความคิดเห็นล่าช้าไปยังอาร์กิวเมนต์ที่พบบ่อย: บางครั้งมันทำให้เกิดความแตกต่างในการวิเคราะห์ใน 5 ชั่วโมงแทนที่จะเป็น 10 และถ้าทำได้โดยใช้เวลาหนึ่งชั่วโมงในการปรับรหัสไพ ธ อนให้เหมาะสม (โดยเฉพาะอย่างยิ่งถ้าเป็น สะดวกสบายกับงูใหญ่และไม่ใช่ภาษาที่เร็วกว่า)
bli

แต่ที่สำคัญกว่านั้นคือซอร์สโค้ดทำให้เราพยายามอ่านและทำความเข้าใจได้มากน้อยเพียงใด!
thoni56

20

ฉันคิดว่าฉันเพิ่งจะเพิ่มใน python 3 filter () เป็นจริงวัตถุตัววนซ้ำดังนั้นคุณจะต้องผ่านการเรียกเมธอด filter ไปยัง list () เพื่อสร้างรายการตัวกรอง ดังนั้นใน python 2:

lst_a = range(25) #arbitrary list
lst_b = [num for num in lst_a if num % 2 == 0]
lst_c = filter(lambda num: num % 2 == 0, lst_a)

รายการ b และ c มีค่าเท่ากันและเสร็จในเวลาเดียวกับตัวกรอง () เท่ากับ [x สำหรับ x ใน y ถ้า z] อย่างไรก็ตามใน 3 รหัสเดียวกันนี้จะปล่อยให้รายการ c มีวัตถุตัวกรองไม่ใช่รายการที่ถูกกรอง เพื่อสร้างค่าเดียวกันใน 3:

lst_a = range(25) #arbitrary list
lst_b = [num for num in lst_a if num % 2 == 0]
lst_c = list(filter(lambda num: num %2 == 0, lst_a))

ปัญหาคือ list () รับค่า iterable เนื่องจากเป็นอาร์กิวเมนต์และสร้างรายการใหม่จากอาร์กิวเมนต์นั้น ผลลัพธ์คือการใช้ตัวกรองด้วยวิธีนี้ใน python 3 ใช้เวลานานถึงสองเท่าของวิธี [x สำหรับ x ใน y if z] เพราะคุณต้องวนซ้ำผลลัพธ์จากตัวกรอง () เช่นเดียวกับรายการต้นฉบับ


13

ความแตกต่างที่สำคัญคือความเข้าใจในรายการจะส่งคืน a listในขณะที่ตัวกรองส่งคืน a filterซึ่งคุณไม่สามารถจัดการได้เหมือนlist(เช่น: เรียกใช้lenบนซึ่งไม่ทำงานกับการส่งคืนfilter)

การเรียนรู้ด้วยตนเองของฉันเองทำให้ฉันมีปัญหาคล้ายกัน

ที่ถูกกล่าวว่าหากมีวิธีที่จะได้รับผลlistจาก a filter, บิตเช่นคุณจะทำใน. NET เมื่อคุณทำlst.Where(i => i.something()).ToList()ฉันอยากรู้ว่ามัน

แก้ไข: นี่เป็นกรณีสำหรับ Python 3 ไม่ใช่ 2 (ดูการสนทนาในความคิดเห็น)


4
ตัวกรองคืนค่ารายการและเราสามารถใช้ len กับมันได้ อย่างน้อยใน Python 2.7.6 ของฉัน
thiruvenkadam

7
ไม่ใช่ใน Python 3 a = [1, 2, 3, 4, 5, 6, 7, 8] f = filter(lambda x: x % 2 == 0, a) lc = [i for i in a if i % 2 == 0] >>> type(f) <class 'filter'> >>> type(lc) <class 'list'>
Adeynack

3
"ถ้ามีวิธีที่จะมีรายการผลลัพธ์ ... ฉันอยากรู้ว่ามัน" เพียงโทรหาlist()ผลลัพธ์: list(filter(my_func, my_iterable)). และแน่นอนว่าคุณสามารถแทนที่listด้วยsetหรือtupleหรือสิ่งอื่นใดที่สามารถทำซ้ำได้ แต่การที่บุคคลอื่นที่ไม่ใช่โปรแกรมเมอร์ทำงานกรณีที่แข็งแกร่งยิ่งขึ้นที่จะใช้ความเข้าใจรายการมากกว่าบวกที่ชัดเจนในการแปลงfilter list
Steve Jessop

10

ฉันค้นหาวิธีที่สองที่สามารถอ่านได้มากขึ้น มันจะบอกคุณอย่างชัดเจนว่าความตั้งใจคืออะไร: กรองรายการ
PS: อย่าใช้ 'รายการ' เป็นชื่อตัวแปร


7

โดยทั่วไป filterจะเร็วกว่าเล็กน้อยหากใช้ฟังก์ชัน builtin

ฉันคาดหวังว่าความเข้าใจในรายการจะเร็วขึ้นเล็กน้อยในกรณีของคุณ


python -m timeit 'ตัวกรอง (แลมบ์ดา x: x ใน [1,2,3,4,5], ช่วง (10,000000))' 10 ลูปที่ดีที่สุดคือ 3: 1.44 วินาทีต่อลูปไพ ธ อน -m timeit '[x สำหรับ x อยู่ในช่วง (10,000000) ถ้า x ใน [1,2,3,4,5]] '10 ลูปดีที่สุดใน 3: 860 msec ต่อลูปไม่จริงเหรอ?!
giaosudau

@sepdau ฟังก์ชั่นแลมบ์ดาไม่ได้สร้างขึ้น ความเข้าใจในรายการได้รับการปรับปรุงในช่วง 4 ปีที่ผ่านมา - ตอนนี้ความแตกต่างนั้นเล็กน้อยแม้ว่าจะมีฟังก์ชั่นในตัว
John La Rooy

7

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

ในตัวอย่างของคุณจะดีกว่าการใช้ตัวกรองมากกว่า list comprehension ตามนิยาม อย่างไรก็ตามถ้าคุณต้องการพูด other_attribute จากองค์ประกอบรายการในตัวอย่างของคุณจะถูกดึงเป็นรายการใหม่จากนั้นคุณสามารถใช้รายการความเข้าใจ

return [item.other_attribute for item in my_list if item.attribute==value]

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


2
ฉันยินดีที่จะทราบสาเหตุของการลงคะแนนเสียงเพื่อที่ฉันจะไม่ทำซ้ำอีกในอนาคต
thiruvenkadam

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

ฉันใช้คำนิยามเพื่อบอกว่าตัวกรองให้รายการที่มีองค์ประกอบเหมือนกันซึ่งเป็นจริงสำหรับกรณี แต่ด้วยความเข้าใจในรายการเราสามารถแก้ไของค์ประกอบเองได้เช่นการแปลง int เป็น str แต่ประเด็นที่ได้รับ :-)
thiruvenkadam

4

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

ในกรณีนี้ฉันกำลังอ่านไฟล์การลอกบรรทัดว่างการคอมเม้นต์บรรทัดและอะไรก็ได้หลังจากความคิดเห็นบนบรรทัด:

# Throw out blank lines and comments
with open('file.txt', 'r') as lines:        
    # From the inside out:
    #    [s.partition('#')[0].strip() for s in lines]... Throws out comments
    #   filter(lambda x: x!= '', [s.part... Filters out blank lines
    #  y for y in filter... Converts filter object to list
    file_contents = [y for y in filter(lambda x: x != '', [s.partition('#')[0].strip() for s in lines])]

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

คุณสามารถเขียนสิ่งนี้เป็นfile_contents = list(filter(None, (s.partition('#')[0].strip() for s in lines)))
สตีฟเจสซอพ

4

นอกเหนือจากคำตอบที่ยอมรับแล้วยังมีตัวพิมพ์ของมุมเมื่อคุณควรใช้ตัวกรองแทนความเข้าใจในรายการ หากรายการ unhashable คุณไม่สามารถประมวลผลได้โดยตรงด้วยความเข้าใจในรายการ ตัวอย่างโลกแห่งความจริงคือถ้าคุณใช้pyodbcเพื่ออ่านผลลัพธ์จากฐานข้อมูล fetchAll()ผลจากการcursorเป็นรายการที่ unhashable ในสถานการณ์นี้เพื่อจัดการโดยตรงกับผลลัพธ์ที่ส่งคืนควรใช้ตัวกรอง:

cursor.execute("SELECT * FROM TABLE1;")
data_from_db = cursor.fetchall()
processed_data = filter(lambda s: 'abc' in s.field1 or s.StartTime >= start_date_time, data_from_db) 

หากคุณใช้รายการความเข้าใจที่นี่คุณจะได้รับข้อผิดพลาด:

TypeError: ประเภท unhashable: 'รายการ'


1
รายการทั้งหมด unhashable >>> hash(list()) # TypeError: unhashable type: 'list'ประการที่สองนี้ใช้งานได้ดี:processed_data = [s for s in data_from_db if 'abc' in s.field1 or s.StartTime >= start_date_time]
Thomas Grainger

"ถ้ารายการ unhashable คุณไม่สามารถประมวลผลโดยตรงด้วยรายการความเข้าใจ" สิ่งนี้ไม่เป็นความจริงและรายการทั้งหมดจะไม่สามารถล้างได้
juanpa.arrivillaga

3

มันเอาฉันบางเวลาที่จะได้รับการช่วยเหลือด้วยและhigher order functions filter mapดังนั้นฉันจึงคุ้นเคยกับพวกเขาและฉันชอบจริง ๆfilterเพราะมันชัดเจนว่ามันกรองโดยการรักษาสิ่งที่เป็นความจริงและฉันรู้สึกดีที่ฉันรู้บางfunctional programmingคำ

จากนั้นฉันอ่านข้อนี้ (Fluent Python Book):

ฟังก์ชั่นแผนที่และตัวกรองยังคงมีอยู่ใน Python 3 แต่เนื่องจากการแนะนำความเข้าใจในรายการและการสร้างเครื่องกำเนิดไฟฟ้าจึงไม่สำคัญ listcomp หรือ genexp ทำงานของแผนที่และตัวกรองรวมกัน แต่อ่านได้ง่ายขึ้น

และตอนนี้ฉันคิดว่าทำไมตื๊อกับแนวคิดของ filter/ mapถ้าคุณสามารถประสบความสำเร็จกับการแพร่กระจายสำนวนที่กว้างขวางอยู่แล้วเช่นความเข้าใจในรายการ นอกจากนี้mapsและfiltersเป็นประเภทของฟังก์ชั่น ในกรณีนี้ฉันชอบใช้แลมAnonymous functionsบ์ดา

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

from timeit import Timer

timeMap = Timer(lambda: list(map(lambda x: x*x, range(10**7))))
print(timeMap.timeit(number=100))

timeListComp = Timer(lambda:[(lambda x: x*x) for x in range(10**7)])
print(timeListComp.timeit(number=100))

#Map:                 166.95695265199174
#List Comprehension   177.97208347299602

0

อยากรู้อยากเห็นเกี่ยวกับ Python 3 ฉันเห็นตัวกรองทำงานได้เร็วกว่ารายการความเข้าใจ

ฉันมักจะคิดว่ารายการความเข้าใจจะมีประสิทธิภาพมากกว่า บางอย่างที่ต้องการ: [ชื่อสำหรับชื่อใน brand_names_db หากชื่อไม่ใช่ไม่มี] bytecode ที่สร้างขึ้นนั้นดีขึ้นเล็กน้อย

>>> def f1(seq):
...     return list(filter(None, seq))
>>> def f2(seq):
...     return [i for i in seq if i is not None]
>>> disassemble(f1.__code__)
2         0 LOAD_GLOBAL              0 (list)
          2 LOAD_GLOBAL              1 (filter)
          4 LOAD_CONST               0 (None)
          6 LOAD_FAST                0 (seq)
          8 CALL_FUNCTION            2
         10 CALL_FUNCTION            1
         12 RETURN_VALUE
>>> disassemble(f2.__code__)
2           0 LOAD_CONST               1 (<code object <listcomp> at 0x10cfcaa50, file "<stdin>", line 2>)
          2 LOAD_CONST               2 ('f2.<locals>.<listcomp>')
          4 MAKE_FUNCTION            0
          6 LOAD_FAST                0 (seq)
          8 GET_ITER
         10 CALL_FUNCTION            1
         12 RETURN_VALUE

แต่พวกเขาจะช้ากว่าจริง:

   >>> timeit(stmt="f1(range(1000))", setup="from __main__ import f1,f2")
   21.177661532000116
   >>> timeit(stmt="f2(range(1000))", setup="from __main__ import f1,f2")
   42.233950221000214

8
การเปรียบเทียบที่ไม่ถูกต้อง ก่อนอื่นคุณไม่ได้ส่งผ่านฟังก์ชั่นแลมบ์ดาไปที่เวอร์ชั่นตัวกรองซึ่งทำให้เป็นค่าเริ่มต้นของฟังก์ชั่นระบุตัวตน เมื่อกำหนดif not Noneในรายการความเข้าใจคุณกำลังกำหนดฟังก์ชั่นแลมบ์ดา (สังเกต MAKE_FUNCTIONคำสั่ง) ประการที่สองผลลัพธ์จะแตกต่างกันเนื่องจากเวอร์ชันความเข้าใจในรายการจะลบเฉพาะNoneค่าในขณะที่รุ่นตัวกรองจะลบค่า "เท็จ" ทั้งหมด การที่กล่าวถึงวัตถุประสงค์ทั้งหมดของการทำเครื่องหมายไมโครอินเทอร์เฟซนั้นไร้ประโยชน์ นั่นคือหนึ่งล้านซ้ำ, คูณ 1k ไอเท็ม! ความแตกต่างคือเล็กน้อย
วิกเตอร์Schröder

-7

ของฉัน

def filter_list(list, key, value, limit=None):
    return [i for i in list if i[key] == value][:limit]

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