2.30. Comprehensions

comprehension สร้าง list, set, dict หรือ generator ใหม่จาก iterable ที่มีอยู่ในนิพจน์เดียว เป็นการแทนที่รูปแบบทั่วไปของการเริ่มต้นด้วยคอนเทนเนอร์ว่างเปล่าและการ append ในลูป

2.30.1. List comprehensions

squares = [x * x for x in range(5)]
print(squares)

ผลลัพธ์:

[0, 1, 4, 9, 16]

ลูปเดียวกันที่เขียนแบบขยาย:

squares = []
for x in range(5):
    squares.append(x * x)

รูปแบบ comprehension เป็นนิพจน์เดียวที่สร้าง list ในที่เดียว ไม่มี squares = [] และไม่มี .append -- ผลลัพธ์คือค่าของ comprehension

The expression "[f(x) for x in xs if cond]" annotated: the leading expression is the result, the for clause names the loop variable, the if clause filters which items are kept.

นิพจน์นำหน้าผลิตแต่ละรายการ; ส่วน for clause ตั้งชื่อตัวแปรลูป; if เพิ่มเติมเพื่อกรองรายการออก

2.30.2. การกรองด้วย if

ส่วน if เพิ่มเติมเก็บเฉพาะรายการที่ตรงกัน:

evens = [x for x in range(10) if x % 2 == 0]
print(evens)

ผลลัพธ์:

[0, 2, 4, 6, 8]

ตัวกรองทำงานก่อนนิพจน์นำหน้า -- x % 2 == 0 ถูกตรวจสอบก่อน; เฉพาะค่าที่ตรงกันเท่านั้นที่ถึง x สำหรับผลลัพธ์

2.30.3. Dict และ set comprehensions

รูปแบบเดียวกันใช้งานได้กับ dict และ set literal

dict comprehension มีคู่ key: value ก่อน for:

squares = {x: x * x for x in range(5)}
print(squares)

ผลลัพธ์:

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

set comprehension ใช้วงเล็บปีกกาและนิพจน์เดียว:

unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)

ผลลัพธ์:

{1, 2}

2.30.4. Generator expressions

วงเล็บกลมผลิต generator expression แทน list ค่าถูกคำนวณทีละหนึ่งตามความต้องการ:

total = sum(x * x for x in range(1000))

ไม่มี list ล้านรายการถูกสร้างขึ้นเลย ค่าไหลทีละหนึ่งเข้าสู่ sum() ซึ่งบวกและทิ้งแต่ละค่าไปเรื่อยๆ

Generator expression เป็นตัวเลือกที่เหมาะสมเมื่อป้อนค่าเข้าสู่ฟังก์ชันรีดิวซ์ (sum(), max(), any(), all()) หรือโค้ดที่บริโภค iterator อื่นๆ -- ประหยัดหน่วยความจำที่ list เทียบเท่าจะใช้

2.30.5. เมื่อ ไม่ควร ใช้ comprehension

Comprehension กระชับแต่ไม่ชัดเจนเสมอ ใช้ลูป for ธรรมดาเมื่อ:

  • เนื้อหาต้องการมากกว่าหนึ่งคำสั่ง (comprehension พอดีกับนิพจน์เดียว)

  • เนื้อหามี side effect (การพิมพ์, การเขียนลงไฟล์) -- comprehension ใช้สำหรับ สร้าง คอลเลกชัน ไม่ใช่สำหรับรันการกระทำ

  • ตัวกรองหรือการแปลงมีหลายส่วนมากจนทำให้ comprehension ไม่ได้อ่านจากซ้ายไปขวาอีกต่อไป