ทักษะการเขียนโค้ดด้วย Python มีความต้องการเพิ่มขึ้นในช่วงไม่กี่ปีที่ผ่านมา เพื่อช่วยพัฒนาทักษะการเขียนโปรแกรม Python เราได้คัดสรร 30 ทริค Python เจ๋งๆ ที่สามารถนำไปใช้เพื่อปรับปรุงโค้ดของคุณ ลองเรียนรู้วันละหนึ่งอย่างตลอด 30 วันข้างหน้า และอย่าลืมอ่านโพสต์เกี่ยวกับแนวปฏิบัติที่ดีที่สุดของ Python เพื่อให้โค้ดของคุณอยู่ในระดับยอดเยี่ยม
หากทักษะ Python ยังไม่แข็งแรงพอ สามารถฝึกปรือได้ด้วยเส้นทางทักษะ Python Programming ของเรา
ทริคสำหรับลำดับ & โครงสร้างข้อมูล
#1 Slicing
a = "Hello World!"
print ( a[ : : - 1 ] )
"""
!dlroW olleH
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
Slicing เป็นความสามารถใน Python ที่อาศัยการทำงานกับดัชนีเพื่อให้เข้าถึงส่วนย่อยของลำดับได้ ดัชนีคือ ตำแหน่งขององค์ประกอบในลำดับ หากชนิดลำดับเป็นแบบแก้ไขได้ (mutable) สามารถใช้ slicing เพื่อดึงและแก้ไขข้อมูลได้
หมายเหตุ : เราสามารถใช้ slicing กับลำดับที่แก้ไขไม่ได้ (immutable) ได้เช่นกัน แต่ถ้าพยายามแก้ไข slice จะเกิด TypeError
รูปแบบของ slice คือ: sequence[start:stop:step] หากไม่ได้ระบุค่าในพารามิเตอร์ start , stop และ step จะใช้ค่าเริ่มต้นดังนี้:
"start" เริ่มต้นที่ 0
"stop" เริ่มต้นที่ความยาวของลำดับ
"step" เริ่มต้นที่ 1 หากไม่ระบุ
เมื่อใช้รูปแบบ sequence[start:stop] องค์ประกอบที่ถูกส่งกลับจะเริ่มตั้งแต่ดัชนีเริ่มต้นจนถึง stop - 1 (จะไม่รวมดัชนี stop)
สามารถส่งดัชนีติดลบได้ ซึ่งใช้กลับลำดับได้ เช่น ในลิสต์ที่มี 4 องค์ประกอบ ดัชนีที่ 0 ก็คือ -4 และดัชนีสุดท้ายคือ -1 ในตัวอย่างโค้ดด้านบน เราใช้ความรู้นี้กับพารามิเตอร์ step ของลำดับ ทำให้สตริงถูกพิมพ์ย้อนกลับจากท้ายลำดับไปยังดัชนี 0
#2 การสลับค่าแบบอินเพลซ / การกำหนดค่าพร้อมกัน
a = 10
b = 5
print ( f"First: { a, b} " )
"""
First: (10, 5)
"""
a, b = b, a + 2
print ( f"Second: { a, b} " )
"""
Second: (5, 12)
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
หากคิดว่า b จะมีค่าเป็น 7 แทน 12 แสดงว่าตกหลุมพรางของการสลับค่าแบบอินเพลซ
ใน Python เราสามารถคลี่ (unpack) iterable ไปยังตัวแปรหลายตัวในการกำหนดค่าเดียวได้ด้วยการคลี่อัตโนมัติ เช่น:
a, b, c = [ 1 , 2 , 3 ]
print ( a)
print ( b)
print ( c)
"""
1
2
3
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
เรายังสามารถรวบค่าหลายค่าไปไว้ในตัวแปรเดียวด้วย * – ทริคนี้เรียกว่า packing ดูตัวอย่างด้านล่าง
โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
การผสมผสาน packing และ unpacking อัตโนมัติ ทำให้เกิดเทคนิคที่เรียกว่า simultaneous assignment ซึ่งใช้กำหนดค่าชุดหนึ่งให้กับตัวแปรหลายตัวพร้อมกันได้
#3 List กับ tuple
import sys
a = [ 1 , 2 , 3 , 4 , 5 ]
b = ( 1 , 2 , 3 , 4 , 5 )
print ( f"List size: { sys. getsizeof( a) } bytes" )
print ( f"Tuple size: { sys. getsizeof( b) } bytes" )
"""
List size: 52 bytes
Tuple size: 40 bytes
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
โปรแกรมเมอร์ Python ส่วนใหญ่คุ้นเคยกับโครงสร้างข้อมูล list แต่ไม่ค่อยคุ้นกับtuple ทั้งคู่เป็น iterable เข้าถึงด้วยดัชนีได้ และเก็บชนิดข้อมูลผสมได้ แต่ก็มีสถานการณ์ที่ควรใช้ tuple แทน list
อย่างแรก list เป็นแบบแก้ไขได้ จึงปรับเปลี่ยนได้ตามต้องการ:
a = [ 1 , 2 , 3 , 4 , 5 ]
a[ 2 ] = 8
print ( a)
"""
[1,2,8,4,5]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ส่วน tuple เป็นแบบแก้ไขไม่ได้ หากพยายามแก้จะเกิด TypeError
ด้วยเหตุนี้ tuple จึงใช้หน่วยความจำมีประสิทธิภาพกว่า เพราะ Python สามารถจองหน่วยความจำได้พอดีกับข้อมูล ขณะที่ list ต้องจองเพิ่มไว้เผื่อขยายในอนาคต ซึ่งเรียกว่า dynamic memory allocation
สรุปสั้นๆ : เมื่อไม่ต้องการให้ข้อมูลเปลี่ยน ควรใช้ tuple แทน list ด้วยเหตุผลด้านหน่วยความจำ และ tuple ยังเร็วกว่า list ด้วย
เรียนรู้เพิ่มเติมเกี่ยวกับ โครงสร้างข้อมูลใน Python ในบทความนี้
#4 Generators
a = [ x * 2 for x in range ( 10 ) ]
b = ( x * 2 for x in range ( 10 ) )
print ( a)
print ( b)
"""
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
<generator object <genexpr> at 0x7f61f8808b50>
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
List comprehension คือวิธีแบบ Pythonic ในการสร้างลิสต์จาก iterable อื่น ซึ่งเร็วกว่าใช้ for loop มาก แต่ถ้าพลั้งมือเปลี่ยนวงเล็บจาก [] เป็น () จะได้ generator object
ใน Python วงเล็บกลมที่มีตรรกะแบบ list comprehension จะสร้างวัตถุชนิด generator ขึ้น Generator เป็น iterable ชนิดพิเศษ ต่างจากลิสต์ตรงที่ไม่เก็บรายการทั้งหมด แต่เก็บคำสั่งสำหรับสร้างแต่ละองค์ประกอบตามลำดับและสถานะระหว่างการวนรอบ
แต่ละองค์ประกอบจะถูกสร้างเมื่อถูกเรียกเท่านั้น ด้วยเทคนิคที่เรียกว่า lazy evaluation ประโยชน์หลักคือลดการใช้หน่วยความจำ เพราะไม่ต้องสร้างลำดับทั้งหมดในคราวเดียว
#5 Aliasing
a = [ 1 , 2 , 3 , 4 , 5 ]
b = a
b[ 4 ] = 7
print ( id ( a) )
print ( id ( b) )
print ( a)
"""
15136008
15136008
[1, 2, 3, 4, 7]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
Python เป็นภาษาเชิงวัตถุ ทุกอย่างเป็นอ็อบเจกต์ ดังนั้นการกำหนดอ็อบเจกต์ให้ตัวระบุ (identifier) จึงเป็นการสร้างการอ้างอิงไปยังอ็อบเจกต์นั้น
เมื่อกำหนดตัวระบุหนึ่งให้เท่ากับอีกตัวหนึ่ง เราจะได้ตัวระบุสองตัวที่อ้างอิงอ็อบเจกต์เดียวกัน แนวคิดนี้เรียกว่า aliasing การเปลี่ยนแปลงที่หนึ่งจะมีผลกับอีกที่ บางครั้งต้องการพฤติกรรมนี้ แต่บ่อยครั้งก็คาดไม่ถึง
วิธีเลี่ยงคือหลีกเลี่ยง aliasing เมื่อใช้อ็อบเจกต์ที่แก้ไขได้ หรือสร้างสำเนา (clone) ของอ็อบเจกต์ต้นฉบับแทนการอ้างอิง
วิธีสร้างสำเนาที่ง่ายที่สุดคือใช้ slicing:
b = a[:] ขับเคลื่อนโดย
วิธีนี้จะสร้างการอ้างอิงใหม่ไปยังอ็อบเจกต์ลิสต์ในตัวระบุ b
ยังมีวิธีอื่น เช่น เรียก list(a) ตอนกำหนดค่าให้ตัวระบุใหม่ หรือใช้เมธอด copy()
#6 ตัวดำเนินการ ‘not’
โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ทริคถัดไปคือวิธีเช็กว่าโครงสร้างข้อมูลว่างหรือไม่ด้วยตัวดำเนินการ not ในตัวของ Python not เป็นตัวดำเนินการเชิงตรรกะที่คืนค่า True หากนิพจน์ไม่เป็นจริง มิฉะนั้นจะคืน False — กล่าวคือกลับค่าความจริงของบูลีนและอ็อบเจกต์
อีกวิธีที่มักเห็นคือใช้ใน if:
if not a:
# do something... ขับเคลื่อนโดย
เมื่อ a เป็น True ตัวดำเนินการ not จะคืนค่า False และกลับกัน
อาจงงเล็กน้อย ลองฝึกใช้ดู
ทริคเกี่ยวกับสตริง & เอาต์พุต
#7 F-strings
first_name = "John"
age = 19
print ( f"Hi, I'm { first_name} and I'm { age} years old!" )
"""
Hi, I'm John and I'm 19 years old!
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
บางครั้งเราต้องจัดรูปแบบสตริง Python 3.6 ได้แนะนำคุณสมบัติที่เจ๋งมากชื่อ f-strings เพื่อให้ง่ายขึ้น จะเข้าใจวิธีใหม่นี้ได้ดีขึ้นหากรู้ว่าเมื่อก่อนจัดรูปแบบกันอย่างไร
ก่อนหน้านี้จัดรูปแบบด้วยวิธีนี้:
first_name = "John"
age = 19
print ( "Hi, I'm {} and I'm {} years old!" . format ( first_name, age) )
"""
Hi, I'm John and I'm 19 years old!
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
โดยสรุป วิธีใหม่เร็วกว่า อ่านง่ายกว่า กระชับกว่า และพลาดยากกว่า
อีกการใช้งานของ f-strings คือพิมพ์ชื่อตัวแปรพร้อมค่า ซึ่งถูกเพิ่มใน Python 3.8
x = 10
y = 20
print ( f" { x = } , { y = } " )
"""
x = 10, y = 20
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ดูบทความ การจัดรูปแบบ F-string ใน Python เพื่อเรียนรู้เพิ่มเติม
#8 พารามิเตอร์ ‘end’ ของฟังก์ชัน print()
languages = [ "english" , "french" , "spanish" , "german" , "twi" ]
print ( ' ' . join( languages) )
"""
english french spanish german twi
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
หลายครั้งเราจะใช้คำสั่ง print โดยไม่ระบุพารามิเตอร์ทางเลือกใดๆ ทำให้ Pythonista จำนวนไม่น้อยไม่รู้ว่าสามารถควบคุมเอาต์พุตได้ในระดับหนึ่ง
พารามิเตอร์ทางเลือกหนึ่งที่เปลี่ยนได้คือ end พารามิเตอร์นี้ระบุว่าจะให้แสดงอะไรท้ายการเรียก print แต่ละครั้ง
ค่าเริ่มต้นของ end คือ "\n" ซึ่งสั่งให้ขึ้นบรรทัดใหม่ ในโค้ดด้านบนเราเปลี่ยนเป็นช่องว่าง จึงได้เอาต์พุตที่พิมพ์องค์ประกอบทั้งหมดในบรรทัดเดียว
#9 เพิ่มค่าให้ tuple
a = ( 1 , 2 , [ 1 , 2 , 3 ] )
a[ 2 ] . append( 4 )
print ( a)
"""
(1, 2, [1, 2, 3, 4])
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
เราทราบแล้วว่า tuple แก้ไขไม่ได้ – ดูทริค #3 List vs. Tuples การพยายามเปลี่ยนสถานะของ tuple จะเกิด TypeError แต่ถ้านึกถึง tuple ว่าเป็นลำดับของชื่อที่ผูกกับอ็อบเจกต์ซึ่งเปลี่ยนการผูกไม่ได้ มุมมองจะต่างออกไป
สององค์ประกอบแรกเป็นจำนวนเต็มซึ่งแก้ไขไม่ได้ แต่อันสุดท้ายเป็นลิสต์ซึ่งเป็นอ็อบเจกต์แบบแก้ไขได้ใน Python
ถ้าถือว่าลิสต์เป็นเพียงชื่อหนึ่งในลำดับที่ผูกกับอ็อบเจกต์ซึ่งเปลี่ยนการผูกไม่ได้ ก็จะเห็นว่ายังแก้ไขลิสต์จากภายใน tuple ได้อยู่
แนะนำให้ทำจริงไหม? อาจไม่ แต่เป็นความรู้ติดตัวที่ดี!
#10 การรวมพจนานุกรม
a = { "a" : 1 , "b" : 2 }
b = { "c" : 3 , "d" : 4 }
a_and_b = a | b
print ( a_and_b)
"""
{"a": 1, "b": 2, "c": 3, "d": 4}
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ตั้งแต่ Python 3.9 ขึ้นไป สามารถรวมพจนานุกรมด้วย | (bitewise OR) ได้ ไม่มีอะไรซับซ้อนนอกจากอ่านง่ายขึ้นมาก!
ทริคด้านสไตล์โค้ด & ไวยากรณ์
#11 ตัวดำเนินการแบบ ternary / นิพจน์เงื่อนไข
condition = True
name = "John" if condition else "Doe"
print ( name)
"""
John
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ในโค้ดด้านบนคือสิ่งที่เรียกว่า ternary operator หรือ conditional expression ใช้ประเมินผลตามเงื่อนไขว่าเป็น True หรือ False
อีกวิธีที่เขียนได้คือ:
condition = True
if condition:
name = "John"
else :
name = "Doe"
print ( name)
"""
John
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
แม้ผลลัพธ์เหมือนกัน แต่สังเกตว่า ternary ทำให้โค้ดสั้นและชัดเจนกว่า เป็นวิธีที่ Pythonic กว่า
#12 ลบค่าซ้ำจากลิสต์
a = [ 1 , 1 , 2 , 3 , 4 , 5 , 5 , 5 , 6 , 7 , 2 , 2 ]
print ( list ( set ( a) ) )
"""
[1, 2, 3, 4, 5, 6, 7]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
วิธีที่ง่ายที่สุดในการลบค่าซ้ำจากลิสต์คือแปลงเป็นเซ็ต (แล้วจะแปลงกลับเป็นลิสต์ก็ได้)
ด้านความแก้ไขได้ เซ็ตกับลิสต์คล้ายกัน เราเพิ่มลบองค์ประกอบได้ทั้งคู่ แต่ก็แตกต่างกันมาก
ลิสต์มีลำดับ มีดัชนีเริ่มที่ศูนย์ และแก้ไขได้ เซ็ตไม่มีลำดับและไม่มีดัชนี องค์ประกอบในเซ็ตต้องเป็นชนิดที่แก้ไขไม่ได้ แม้ตัวเซ็ตเองจะแก้ไขได้ — การดึงด้วยดัชนีหรือแก้ค่าสมาชิกจะเกิดข้อผิดพลาด
ความต่างสำคัญอีกข้อคือ เซ็ตไม่มีค่าซ้ำ นี่เองที่ช่วยให้เราลบค่าซ้ำจากลิสต์ได้
#13 ขีดล่างเดี่ยวแบบสแตนด์อโลน
>> > print( _)
Traceback ( most recent call last) :
File "<stdin>" , line 1 , in < module>
>> > 1 + 2
3
>> > print( _)
3 ขับเคลื่อนโดย
ขีดล่าง (_) เป็นตัวระบุที่ถูกต้องใน Python จึงใช้เป็นชื่ออ้างอิงอ็อบเจกต์ได้ แต่ยังมีหน้าที่อีกอย่าง: เก็บผลลัพธ์จากการประเมินครั้งล่าสุด
ตามเอกสาร “ตัวแปลคำสั่งแบบโต้ตอบจะทำให้ผลของการประเมินครั้งล่าสุดพร้อมใช้งานในตัวแปร _ (เก็บในโมดูล builtins เช่นเดียวกับฟังก์ชันในตัวอย่าง print)”
เพราะเราไม่เคยกำหนดค่าให้ _ มาก่อนในบรรทัดแรก จึงเกิดข้อผิดพลาด แต่เมื่อคำนวณ 1 + 2 แล้ว ตัวแปลโต้ตอบก็เก็บผลไว้ในตัวระบุ _ ให้เรา
#14 ใช้ขีดล่างเพื่อเมินค่า
for _ in range ( 100 ) :
print ( "The index doesn't matter" )
"""
The index doesn't matter
The index doesn't matter
...
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ในทริค #13 เราเห็นว่า _ เก็บผลจากการประเมินครั้งล่าสุด แต่ยังมีกรณีใช้อีก
เราสามารถใช้แทนอ็อบเจกต์ที่ไม่สนใจหรือตั้งใจจะไม่ใช้ต่อในภายหลัง ซึ่งสำคัญ เพราะการใช้ตัวระบุปกติแทน _ อาจทำให้เกิดข้อผิดพลาด F841 ตอนทำ linting ซึ่งหมายถึงมีตัวแปรโลคอลถูกกำหนดแต่ไม่ถูกใช้งาน ถือว่าเป็นแนวปฏิบัติที่ไม่ดี
#15 ขีดล่างท้ายคำ
โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ต่อเนื่องจากสองทริคก่อน หนึ่งในวัตถุประสงค์ของการใช้ขีดล่าง (_) คือหลีกเลี่ยงชนกับคีย์เวิร์ดของ Python
PEP 8 ระบุว่าควรใช้ขีดล่างปิดท้าย “ตามธรรมเนียมเพื่อหลีกเลี่ยงชนกับคีย์เวิร์ดของ Python” และว่า “โดยทั่วไปควรเติมขีดล่างท้ายเดี่ยว ดีกว่าใช้คำย่อหรือสะกดเพี้ยน เช่น list_ ดีกว่า lst ”
#16 ขีดล่างนำหน้า
class Example :
def __init__ ( self) :
self. _internal = 2
self. external = 20 ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
มักเห็นโปรแกรมเมอร์ Python ที่มีประสบการณ์เติมขีดล่างนำหน้าตัวระบุหรือนามเมธอด ซึ่งมีเหตุผล
ขีดล่างที่นำหน้าตัวระบุหรือเมธอดมีนัยแฝงว่า ตัวแปรหรือเมธอดนี้ตั้งใจใช้ภายในเท่านั้น โดยหลักแล้วเป็นคำเตือนต่อโปรแกรมเมอร์คนอื่นตาม PEP 8 แต่ Python ไม่ได้บังคับใช้ ดังนั้นจึงเป็นตัวบ่งชี้ที่อ่อน
ต่างจาก Java, Python ไม่มีการแบ่ง private/public ที่เข้มแข็ง กล่าวคือมีความหมายเพราะชุมชนเห็นพ้องเท่านั้น การใส่ขีดล่างไม่กระทบพฤติกรรมของโปรแกรม
#17 ขีดล่างเพื่อความอ่านง่าย
ทริคสุดท้ายเกี่ยวกับขีดล่าง; จนถึงตอนนี้เราครอบคลุม 3 กรณีใช้แล้ว แต่สามารถดูบทความ บทบาทของขีดล่าง(_) ใน Python เพื่อเรียนรู้เพิ่มเติม
โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
อีกวิธีในการใช้ขีดล่างคือเป็นตัวคั่นช่วยมองเห็นกลุ่มหลักของตัวเลขใน literal แบบจำนวนเต็ม ทศนิยม และเชิงซ้อน — ฟีเจอร์นี้มีตั้งแต่ Python 3.6
แนวคิดคือช่วยให้อ่านค่าที่ยาว หรือค่าที่ควรแบ่งส่วนให้ชัด อ่านเพิ่มเติมได้ใน PEP 515
ทริคด้านสไตล์โค้ด & ไวยากรณ์
#18 __name__ == “__main__”
if __name__ == "__main__" :
print ( "Read on to understand what is going on when you do this." )
"""
print("Read on to understand what is going on when you do this.")
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
มีโอกาสสูงว่าคุณเคยเห็นไวยากรณ์นี้ในหลายโปรแกรม Python; Python ใช้ชื่อติเศษว่า "__main__" และกำหนดให้ตัวระบุ __name__ หากไฟล์ Python ที่รันอยู่เป็นโปรแกรมหลัก
ถ้านำโมดูลในภาพหน้าจอไป import ในโมดูลอื่น (ไฟล์ Python อื่น) แล้วรันไฟล์นั้น เงื่อนไขในโค้ดจะเป็นเท็จ เพราะเมื่อ import จากโมดูลอื่น __name__ จะถูกตั้งเป็นชื่อโมดูล (ชื่อไฟล์ Python)
#19 เมธอด ‘setdefault’
import pprint
text = "It's the first of April. It's still cold in the UK. But I'm going to the museum so it should be a wonderful day"
counts = { }
for word in text. split( ) :
counts. setdefault( word, 0 )
counts[ word] += 1
pprint. pprint( counts)
"""
{'April.': 1,
'But': 1,
"I'm": 1,
"It's": 2,
'UK.': 1,
'a': 1,
'be': 1,
'cold': 1,
'day': 1,
'first': 1,
'going': 1,
'in': 1,
'it': 1,
'museum': 1,
'of': 1,
'should': 1,
'so': 1,
'still': 1,
'the': 3,
'to': 1,
'wonderful': 1}
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
คุณอาจต้องการกำหนดค่าให้หลายคีย์ในพจนานุกรม เช่น ตอนนับคำในคลังข้อความ วิธีทั่วไปคือ:
ตรวจว่าคีย์มีอยู่ในพจนานุกรมหรือไม่
ถ้ามี ให้เพิ่มค่าทีละ 1
ถ้าไม่มีก็เพิ่มคีย์นั้นและตั้งค่าเป็น 1
โค้ดจะหน้าตาแบบนี้:
counts = { }
for word in text. split( ) :
if word in counts:
counts[ word] += 1
else :
counts[ word] = 1 ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
วิธีที่กระชับกว่าคือใช้เมธอด setdefault() บนพจนานุกรม
อาร์กิวเมนต์ตัวแรกคือคีย์ที่ต้องการตรวจสอบ ตัวที่สองคือค่าที่จะตั้งให้คีย์นั้นหากยังไม่มีอยู่ — ถ้าคีย์มีอยู่แล้ว เมธอดจะคืนค่าปัจจุบัน จึงไม่เปลี่ยนค่า
ทริคด้านโครงสร้างโปรแกรม
#20 จับคู่ regex
import re
number = re. compile ( r"(0)?(\+44)?\d{10}" )
num_1 = number. search( "My number is +447999999999" )
num_2 = number. search( "My number is 07999999999" )
print ( num_1. group( ) )
print ( num_2. group( ) )
"""
'+447999999999'
'07999999999'
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
Regular expressions ช่วยระบุรูปแบบของข้อความเพื่อค้นหา คนส่วนใหญ่รู้ว่าใช้ CTRL + F (Windows) เพื่อค้นหาได้ แต่ถ้าไม่รู้คำตรงๆ ที่จะหา จะทำอย่างไร? คำตอบคือค้นหารูปแบบ
เช่น หมายเลขในสหราชอาณาจักรมีรูปแบบคล้ายกัน: เริ่มด้วยเลขศูนย์ตามด้วยอีกสิบหลัก หรือเริ่มด้วย +44 แทนศูนย์และตามด้วยสิบหลัก — แบบหลังคือรูปแบบสากล
Regex ช่วยประหยัดเวลามหาศาล หากต้องเขียนกฎเพื่อดักกรณีในภาพแทน regex อาจยาวเกิน 10 บรรทัด
การเข้าใจ regex สำคัญแม้ไม่เขียนโค้ด เพราะโปรแกรมแก้ไขข้อความสมัยใหม่มักรองรับการค้นหาและแทนที่ด้วย regex
#21 เครื่องหมายท่อใน regex
import re
heros = re. compile ( r"Super(man|woman|human)" )
h1 = heros. search( "This will find Superman" )
h2 = heros. search( "This will find Superwoman" )
h3 = heros. search( "This will find Superhuman" )
print ( h1. group( ) )
print ( h2. group( ) )
print ( h3. group( ) )
"""
Superman
Superwoman
Superhuman
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ใน regex มีอักขระพิเศษเรียกว่า pipe (| ) สำหรับจับคู่หนึ่งในหลายๆ นิพจน์ และใช้ที่ใดก็ได้ มีประโยชน์มากเมื่อมีรูปแบบคล้ายกันหลายแบบ
เช่น ‘Superman’, ‘Superwoman’, และ ‘Superhuman’ มีคำนำหน้าเดียวกัน จึงใช้ pipe เพื่อคงส่วนที่ซ้ำและเปลี่ยนเฉพาะส่วนที่ต่าง ช่วยประหยัดเวลาอีกครั้ง
ข้อควรระวัง : หากทุกนิพจน์ที่ต้องการจับเกิดอยู่ในข้อความเดียวกัน จะคืนผลการจับคู่ครั้งแรกที่พบ — เช่น “An example text containing Superwoman, Superman, Superhuman,” จะคืน Superwoman
#22 พารามิเตอร์ ‘sep’ ของฟังก์ชัน print()
day = "04"
month = "10"
year = "2022"
print ( day, month, year)
print ( day, month, year, sep = "" )
print ( day, month, year, sep = "." )
"""
04 10 2022
04/10/2022
04.10.2022
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
มีโปรแกรมเมอร์ Python จำนวนไม่น้อยที่ไม่รู้ความสามารถเต็มรูปแบบของ print() ; หาก “Hello World” เป็นโปรแกรมแรกของคุณ print() คงเป็นฟังก์ชันในตัวแรกๆ ที่เรียน เราใช้เพื่อแสดงข้อความที่จัดรูปแบบ แต่จริงๆ แล้วยังทำได้อีกมาก
โค้ดด้านบนแสดงหลายวิธีในการแสดงข้อความที่จัดรูปแบบ พารามิเตอร์ sep เป็นอาร์กิวเมนต์ทางเลือกของ print() ที่ให้ระบุว่าจะแทรกอะไรคั่นระหว่างอ็อบเจกต์เมื่อพิมพ์มากกว่าหนึ่งตัว
ค่าเริ่มต้นคือเว้นวรรค แต่เราเปลี่ยนพฤติกรรมนี้ในคำสั่ง print — ครั้งหนึ่งตั้ง sep เป็น "" และอีกครั้งเป็น "."
#23 ฟังก์ชัน lambda
def square ( num: int ) - > int :
return num ** 2
print ( f"Function call: { square( 4 ) } " )
"""
Function call: 16
"""
square_lambda = lambda x: x** 2
print ( f"Lambda function: { square_lambda( 4 ) } " )
"""
Lambda functional: 16
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ฟังก์ชัน lambda พาคุณเข้าสู่ระดับกลาง-ขั้นสูงของสิ่งที่ทำได้ด้วย Python — เรียนคอร์ส Intermediate Python ได้ที่นี่ มองเผินๆ อาจดูยาก แต่จริงๆ เรียบง่าย
ในตัวอย่างเราใช้แค่อาร์กิวเมนต์เดียว แต่จะใช้หลายตัวก็ได้:
square = lambda a, b: a ** b
print ( f"Lambda function: { square( 4 , 2 ) } " )
"""
16
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
โดยแก่น คีย์เวิร์ด lambda อนุญาตให้สร้างฟังก์ชันขนาดเล็ก จำกัดความสามารถ แบบไม่ระบุชื่อ ในบรรทัดเดียว ทำงานเหมือนฟังก์ชันปกติที่ประกาศด้วย def เพียงแต่ไม่มีชื่อ
#24 เมธอด ‘swapcase’
string = "SoMe RaNDoM sTriNg"
print ( string. swapcase( ) )
"""
sOmE rAndOm StRInG
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
เมธอด swapcase() ใช้กับสตริงเพื่อสลับอักษรตัวใหญ่เป็นตัวเล็กและกลับกันได้ในบรรทัดเดียว แม้จะไม่ค่อยมีกรณีใช้งานมาก แต่ก็น่ารู้ไว้
#25 เมธอด ‘isalnum’
password = "ABCabc123"
print ( password. isalnum( ) )
"""
True
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
สมมติเราสร้างโปรแกรมที่กำหนดให้รหัสผ่านต้องมีทั้งตัวอักษรและตัวเลข สามารถทำได้ในบรรทัดเดียวด้วยการเรียก isalnum() บนอินสแตนซ์สตริง
เมธอดนี้ตรวจว่าตัวอักษรทั้งหมดเป็นตัวอักษร (A-Za-z) และตัวเลข (0-9) หรือไม่ หากมีช่องว่างหรือสัญลักษณ์ (!#%$&? เป็นต้น) จะคืนค่า False
#26 การจัดการข้อยกเว้น
def get_ration ( x: int , y: int ) - > int :
try :
ratio = x/ y
except ZeroDivisionError:
y = y + 1
ratio = x/ y
return ratio
print ( get_ration( x= 400 , y= 0 ) )
"""
400.0
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
โปรแกรม Python จะหยุดทำงานเมื่อพบข้อผิดพลาด
บางครั้งเราไม่ต้องการพฤติกรรมนี้ เช่น เมื่อมีผู้ใช้ปลายทางโต้ตอบกับโค้ดของเรา จะเลวร้ายเพียงใดหากโปรแกรมปิดก่อนกำหนด?
มีแนวคิดหลายแบบในการรับมือกรณีพิเศษ นักพัฒนา Python จำนวนมากมักยึดแนวคิดว่า “ขออภัยทีหลังง่ายกว่าขออนุญาตก่อน” นั่นคือจะยอมจับข้อผิดพลาดเมื่อเกิดขึ้นด้วยบริบทที่เตรียมรับข้อยกเว้นไว้ มากกว่าจะเสียเวลาป้องกันทุกกรณีที่อาจเกิดได้
แต่นี่จะใช้ได้ก็ต่อเมื่อมีวิธีรับมือหลังปัญหาเกิดจริง
#27 หาความแตกต่างในลิสต์
list_1 = [ 1 , 3 , 5 , 7 , 8 ]
list_2 = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]
solution_1 = list ( set ( list_2) - set ( list_1) )
solution_2 = list ( set ( list_1) ^ set ( list_2) )
solution_3 = list ( set ( list_1) . symmetric_difference( set ( list_2) ) )
print ( f"Solution 1: { solution_1} " )
print ( f"Solution 2: { solution_2} " )
print ( f"Solution 3: { solution_3} " )
"""
Solution 1: [9, 2, 4, 6]
Solution 2: [2, 4, 6, 9]
Solution 3: [2, 4, 6, 9]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
นี่คือสามวิธีในการเปรียบเทียบหาความต่างระหว่างลิสต์สองชุดใน Python
หมายเหตุ : เว้นแต่จะรู้แน่ชัดว่า list_1 เป็นสับเซ็ตของ list_2 มิฉะนั้นวิธีที่ 1 จะไม่เหมือนอีกสองวิธี
#28 Args & kwargs
def some_function ( * args, ** kwargs) :
print ( f"Args: { args} " )
print ( f"Kwargs: { kwargs} " )
some_function( 1 , 2 , 3 , a= 4 , b= 5 , c= 6 )
"""
Args: (1, 2, 3)
Kwargs: {'a': 4, 'b': 5, 'c': 6}
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
เราใช้ *args และ **kwargs เป็นพารามิเตอร์ของฟังก์ชันเมื่อไม่ทราบจำนวนตัวแปรล่วงหน้าที่ฟังก์ชันจะรับได้
*args อนุญาตให้ส่งอาร์กิวเมนต์แบบไม่มีคีย์เวิร์ดเข้ามาเป็นจำนวนแปรผัน ส่วน **kwargs อนุญาตให้ส่งอาร์กิวเมนต์แบบมีคีย์เวิร์ดได้ตามต้องการ
จริงๆ แล้วคำว่า *args และ **kwargs ไม่ได้วิเศษอะไร จุดสำคัญอยู่ที่ดอกจัน (*) หมายความว่าเราจะใช้คำใดตามหลังดอกจันก็ได้ เพียงแต่ args และ kwargs เป็นแบบแผนที่ใช้กันและเป็นที่ยอมรับในหมู่นักพัฒนา Python
#29 Ellipsis
print ( . . . )
"""
Ellipsis
"""
def some_function ( ) :
. . .
def another_function ( ) :
pass ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
Ellipsis เป็นอ็อบเจกต์ใน Python ที่เรียกได้ด้วยเครื่องหมายจุดสามจุด (...) หรือเรียกอ็อบเจกต์เอง (Ellipsis)
การใช้งานที่เด่นคือการเข้าถึงและ slice อาเรย์หลายมิติใน NumPy เช่น:
import numpy as np
arr = np. array( [ [ 2 , 3 ] , [ 1 , 2 ] , [ 9 , 8 ] ] )
print ( arr[ . . . , 0 ] )
"""
[2 1 9]
"""
print ( arr[ . . . ] )
"""
[[2 3]
[1 2]
[9 8]]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
อีกการใช้งานของ Ellipsis คือเป็นที่คั่น (placeholder) ในฟังก์ชันที่ยังไม่ implement
กล่าวคือจะใช้ Ellipsis, ... หรือ pass ก็ล้วนถูกต้อง
#30 List comprehension
even_numbers = [ x for x in range ( 10 ) if x % 2 == 0 and x != 0 ]
print ( even_numbers)
"""
[2, 4, 6, 8]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
ทริคสุดท้ายคือ list comprehension ซึ่งเป็นวิธีที่งดงามในการสร้างลิสต์จากลำดับอื่น สามารถเขียนตรรกะและการกรองที่ซับซ้อนได้ดังที่แสดงในโค้ด
มีวิธีอื่นทำได้เช่นกัน เช่น ใช้ lambda ดังนี้:
even_numbers = list ( filter ( lambda x: x % 2 == 0 and x != 0 , range ( 10 ) ) )
print ( even_numbers)
"""
[0, 2, 4, 6, 8]
""" ขับเคลื่อนโดย โปรแกรมแก้ไขแบบ Learn-by-Example กด Tab เพื่อเข้า กด Escape แล้ว Tab หรือ Shift+Tab เพื่อออก
แต่ Pythonista หลายคนจะโต้แย้งว่าวิธีนี้อ่านยากกว่า list comprehension มาก
ทักษะการเขียนโค้ดด้วย Python มีความต้องการเพิ่มขึ้นในช่วงไม่กี่ปีที่ผ่านมา เพื่อช่วยพัฒนาทักษะการเขียนโปรแกรม Python เราได้คัดสรร 30 ทริค Python เจ๋งๆ ที่สามารถนำไปใช้เพื่อปรับปรุงโค้ดของคุณ ลองเรียนรู้วันละหนึ่งอย่างตลอด 30 วันข้างหน้า และอย่าลืมอ่านโพสต์เกี่ยวกับแนวปฏิบัติที่ดีที่สุดของ Python เพื่อให้โค้ดของคุณอยู่ในระดับยอดเยี่ยม
หากทักษะ Python ยังไม่แข็งแรงพอ สามารถฝึกปรือได้ด้วยเส้นทางทักษะ Python Programming ของเรา
ทริคสำหรับลำดับ & โครงสร้างข้อมูล
#1 Slicing
Slicing เป็นความสามารถใน Python ที่อาศัยการทำงานกับดัชนีเพื่อให้เข้าถึงส่วนย่อยของลำดับได้ ดัชนีคือ ตำแหน่งขององค์ประกอบในลำดับ หากชนิดลำดับเป็นแบบแก้ไขได้ (mutable) สามารถใช้ slicing เพื่อดึงและแก้ไขข้อมูลได้
หมายเหตุ: เราสามารถใช้ slicing กับลำดับที่แก้ไขไม่ได้ (immutable) ได้เช่นกัน แต่ถ้าพยายามแก้ไข slice จะเกิด TypeError
รูปแบบของ slice คือ: sequence[start:stop:step] หากไม่ได้ระบุค่าในพารามิเตอร์ start, stop และ step จะใช้ค่าเริ่มต้นดังนี้:
เมื่อใช้รูปแบบ sequence[start:stop] องค์ประกอบที่ถูกส่งกลับจะเริ่มตั้งแต่ดัชนีเริ่มต้นจนถึง stop - 1 (จะไม่รวมดัชนี stop)
สามารถส่งดัชนีติดลบได้ ซึ่งใช้กลับลำดับได้ เช่น ในลิสต์ที่มี 4 องค์ประกอบ ดัชนีที่ 0 ก็คือ -4 และดัชนีสุดท้ายคือ -1 ในตัวอย่างโค้ดด้านบน เราใช้ความรู้นี้กับพารามิเตอร์ step ของลำดับ ทำให้สตริงถูกพิมพ์ย้อนกลับจากท้ายลำดับไปยังดัชนี 0
#2 การสลับค่าแบบอินเพลซ / การกำหนดค่าพร้อมกัน
หากคิดว่า b จะมีค่าเป็น 7 แทน 12 แสดงว่าตกหลุมพรางของการสลับค่าแบบอินเพลซ
ใน Python เราสามารถคลี่ (unpack) iterable ไปยังตัวแปรหลายตัวในการกำหนดค่าเดียวได้ด้วยการคลี่อัตโนมัติ เช่น:
เรายังสามารถรวบค่าหลายค่าไปไว้ในตัวแปรเดียวด้วย * – ทริคนี้เรียกว่า packing ดูตัวอย่างด้านล่าง
การผสมผสาน packing และ unpacking อัตโนมัติ ทำให้เกิดเทคนิคที่เรียกว่า simultaneous assignment ซึ่งใช้กำหนดค่าชุดหนึ่งให้กับตัวแปรหลายตัวพร้อมกันได้
#3 List กับ tuple
โปรแกรมเมอร์ Python ส่วนใหญ่คุ้นเคยกับโครงสร้างข้อมูล list แต่ไม่ค่อยคุ้นกับtuple ทั้งคู่เป็น iterable เข้าถึงด้วยดัชนีได้ และเก็บชนิดข้อมูลผสมได้ แต่ก็มีสถานการณ์ที่ควรใช้ tuple แทน list
อย่างแรก list เป็นแบบแก้ไขได้ จึงปรับเปลี่ยนได้ตามต้องการ:
ส่วน tuple เป็นแบบแก้ไขไม่ได้ หากพยายามแก้จะเกิด TypeError
ด้วยเหตุนี้ tuple จึงใช้หน่วยความจำมีประสิทธิภาพกว่า เพราะ Python สามารถจองหน่วยความจำได้พอดีกับข้อมูล ขณะที่ list ต้องจองเพิ่มไว้เผื่อขยายในอนาคต ซึ่งเรียกว่า dynamic memory allocation
สรุปสั้นๆ: เมื่อไม่ต้องการให้ข้อมูลเปลี่ยน ควรใช้ tuple แทน list ด้วยเหตุผลด้านหน่วยความจำ และ tuple ยังเร็วกว่า list ด้วย
เรียนรู้เพิ่มเติมเกี่ยวกับ โครงสร้างข้อมูลใน Python ในบทความนี้
#4 Generators
List comprehension คือวิธีแบบ Pythonic ในการสร้างลิสต์จาก iterable อื่น ซึ่งเร็วกว่าใช้ for loop มาก แต่ถ้าพลั้งมือเปลี่ยนวงเล็บจาก [] เป็น () จะได้ generator object
ใน Python วงเล็บกลมที่มีตรรกะแบบ list comprehension จะสร้างวัตถุชนิด generator ขึ้น Generator เป็น iterable ชนิดพิเศษ ต่างจากลิสต์ตรงที่ไม่เก็บรายการทั้งหมด แต่เก็บคำสั่งสำหรับสร้างแต่ละองค์ประกอบตามลำดับและสถานะระหว่างการวนรอบ
แต่ละองค์ประกอบจะถูกสร้างเมื่อถูกเรียกเท่านั้น ด้วยเทคนิคที่เรียกว่า lazy evaluation ประโยชน์หลักคือลดการใช้หน่วยความจำ เพราะไม่ต้องสร้างลำดับทั้งหมดในคราวเดียว
#5 Aliasing
Python เป็นภาษาเชิงวัตถุ ทุกอย่างเป็นอ็อบเจกต์ ดังนั้นการกำหนดอ็อบเจกต์ให้ตัวระบุ (identifier) จึงเป็นการสร้างการอ้างอิงไปยังอ็อบเจกต์นั้น
เมื่อกำหนดตัวระบุหนึ่งให้เท่ากับอีกตัวหนึ่ง เราจะได้ตัวระบุสองตัวที่อ้างอิงอ็อบเจกต์เดียวกัน แนวคิดนี้เรียกว่า aliasing การเปลี่ยนแปลงที่หนึ่งจะมีผลกับอีกที่ บางครั้งต้องการพฤติกรรมนี้ แต่บ่อยครั้งก็คาดไม่ถึง
วิธีเลี่ยงคือหลีกเลี่ยง aliasing เมื่อใช้อ็อบเจกต์ที่แก้ไขได้ หรือสร้างสำเนา (clone) ของอ็อบเจกต์ต้นฉบับแทนการอ้างอิง
วิธีสร้างสำเนาที่ง่ายที่สุดคือใช้ slicing:
วิธีนี้จะสร้างการอ้างอิงใหม่ไปยังอ็อบเจกต์ลิสต์ในตัวระบุ b
ยังมีวิธีอื่น เช่น เรียก list(a) ตอนกำหนดค่าให้ตัวระบุใหม่ หรือใช้เมธอด copy()
#6 ตัวดำเนินการ ‘not’
ทริคถัดไปคือวิธีเช็กว่าโครงสร้างข้อมูลว่างหรือไม่ด้วยตัวดำเนินการ not ในตัวของ Python not เป็นตัวดำเนินการเชิงตรรกะที่คืนค่า True หากนิพจน์ไม่เป็นจริง มิฉะนั้นจะคืน False — กล่าวคือกลับค่าความจริงของบูลีนและอ็อบเจกต์
อีกวิธีที่มักเห็นคือใช้ใน if:
เมื่อ a เป็น True ตัวดำเนินการ not จะคืนค่า False และกลับกัน
อาจงงเล็กน้อย ลองฝึกใช้ดู
ทริคเกี่ยวกับสตริง & เอาต์พุต
#7 F-strings
บางครั้งเราต้องจัดรูปแบบสตริง Python 3.6 ได้แนะนำคุณสมบัติที่เจ๋งมากชื่อ f-strings เพื่อให้ง่ายขึ้น จะเข้าใจวิธีใหม่นี้ได้ดีขึ้นหากรู้ว่าเมื่อก่อนจัดรูปแบบกันอย่างไร
ก่อนหน้านี้จัดรูปแบบด้วยวิธีนี้:
โดยสรุป วิธีใหม่เร็วกว่า อ่านง่ายกว่า กระชับกว่า และพลาดยากกว่า
อีกการใช้งานของ f-strings คือพิมพ์ชื่อตัวแปรพร้อมค่า ซึ่งถูกเพิ่มใน Python 3.8
ดูบทความ การจัดรูปแบบ F-string ใน Python เพื่อเรียนรู้เพิ่มเติม
#8 พารามิเตอร์ ‘end’ ของฟังก์ชัน print()
หลายครั้งเราจะใช้คำสั่ง print โดยไม่ระบุพารามิเตอร์ทางเลือกใดๆ ทำให้ Pythonista จำนวนไม่น้อยไม่รู้ว่าสามารถควบคุมเอาต์พุตได้ในระดับหนึ่ง
พารามิเตอร์ทางเลือกหนึ่งที่เปลี่ยนได้คือ end พารามิเตอร์นี้ระบุว่าจะให้แสดงอะไรท้ายการเรียก print แต่ละครั้ง
ค่าเริ่มต้นของ end คือ "\n" ซึ่งสั่งให้ขึ้นบรรทัดใหม่ ในโค้ดด้านบนเราเปลี่ยนเป็นช่องว่าง จึงได้เอาต์พุตที่พิมพ์องค์ประกอบทั้งหมดในบรรทัดเดียว
#9 เพิ่มค่าให้ tuple
เราทราบแล้วว่า tuple แก้ไขไม่ได้ – ดูทริค #3 List vs. Tuples การพยายามเปลี่ยนสถานะของ tuple จะเกิด TypeError แต่ถ้านึกถึง tuple ว่าเป็นลำดับของชื่อที่ผูกกับอ็อบเจกต์ซึ่งเปลี่ยนการผูกไม่ได้ มุมมองจะต่างออกไป
สององค์ประกอบแรกเป็นจำนวนเต็มซึ่งแก้ไขไม่ได้ แต่อันสุดท้ายเป็นลิสต์ซึ่งเป็นอ็อบเจกต์แบบแก้ไขได้ใน Python
ถ้าถือว่าลิสต์เป็นเพียงชื่อหนึ่งในลำดับที่ผูกกับอ็อบเจกต์ซึ่งเปลี่ยนการผูกไม่ได้ ก็จะเห็นว่ายังแก้ไขลิสต์จากภายใน tuple ได้อยู่
แนะนำให้ทำจริงไหม? อาจไม่ แต่เป็นความรู้ติดตัวที่ดี!
#10 การรวมพจนานุกรม
ตั้งแต่ Python 3.9 ขึ้นไป สามารถรวมพจนานุกรมด้วย | (bitewise OR) ได้ ไม่มีอะไรซับซ้อนนอกจากอ่านง่ายขึ้นมาก!
ทริคด้านสไตล์โค้ด & ไวยากรณ์
#11 ตัวดำเนินการแบบ ternary / นิพจน์เงื่อนไข
ในโค้ดด้านบนคือสิ่งที่เรียกว่า ternary operator หรือ conditional expression ใช้ประเมินผลตามเงื่อนไขว่าเป็น True หรือ False
อีกวิธีที่เขียนได้คือ:
แม้ผลลัพธ์เหมือนกัน แต่สังเกตว่า ternary ทำให้โค้ดสั้นและชัดเจนกว่า เป็นวิธีที่ Pythonic กว่า
#12 ลบค่าซ้ำจากลิสต์
วิธีที่ง่ายที่สุดในการลบค่าซ้ำจากลิสต์คือแปลงเป็นเซ็ต (แล้วจะแปลงกลับเป็นลิสต์ก็ได้)
ด้านความแก้ไขได้ เซ็ตกับลิสต์คล้ายกัน เราเพิ่มลบองค์ประกอบได้ทั้งคู่ แต่ก็แตกต่างกันมาก
ลิสต์มีลำดับ มีดัชนีเริ่มที่ศูนย์ และแก้ไขได้ เซ็ตไม่มีลำดับและไม่มีดัชนี องค์ประกอบในเซ็ตต้องเป็นชนิดที่แก้ไขไม่ได้ แม้ตัวเซ็ตเองจะแก้ไขได้ — การดึงด้วยดัชนีหรือแก้ค่าสมาชิกจะเกิดข้อผิดพลาด
ความต่างสำคัญอีกข้อคือ เซ็ตไม่มีค่าซ้ำ นี่เองที่ช่วยให้เราลบค่าซ้ำจากลิสต์ได้
#13 ขีดล่างเดี่ยวแบบสแตนด์อโลน
ขีดล่าง (_) เป็นตัวระบุที่ถูกต้องใน Python จึงใช้เป็นชื่ออ้างอิงอ็อบเจกต์ได้ แต่ยังมีหน้าที่อีกอย่าง: เก็บผลลัพธ์จากการประเมินครั้งล่าสุด
ตามเอกสาร “ตัวแปลคำสั่งแบบโต้ตอบจะทำให้ผลของการประเมินครั้งล่าสุดพร้อมใช้งานในตัวแปร _ (เก็บในโมดูล builtins เช่นเดียวกับฟังก์ชันในตัวอย่าง print)”
เพราะเราไม่เคยกำหนดค่าให้ _ มาก่อนในบรรทัดแรก จึงเกิดข้อผิดพลาด แต่เมื่อคำนวณ 1 + 2 แล้ว ตัวแปลโต้ตอบก็เก็บผลไว้ในตัวระบุ _ ให้เรา
#14 ใช้ขีดล่างเพื่อเมินค่า
ในทริค #13 เราเห็นว่า _ เก็บผลจากการประเมินครั้งล่าสุด แต่ยังมีกรณีใช้อีก
เราสามารถใช้แทนอ็อบเจกต์ที่ไม่สนใจหรือตั้งใจจะไม่ใช้ต่อในภายหลัง ซึ่งสำคัญ เพราะการใช้ตัวระบุปกติแทน _ อาจทำให้เกิดข้อผิดพลาด F841 ตอนทำ linting ซึ่งหมายถึงมีตัวแปรโลคอลถูกกำหนดแต่ไม่ถูกใช้งาน ถือว่าเป็นแนวปฏิบัติที่ไม่ดี
#15 ขีดล่างท้ายคำ
ต่อเนื่องจากสองทริคก่อน หนึ่งในวัตถุประสงค์ของการใช้ขีดล่าง (_) คือหลีกเลี่ยงชนกับคีย์เวิร์ดของ Python
PEP 8 ระบุว่าควรใช้ขีดล่างปิดท้าย “ตามธรรมเนียมเพื่อหลีกเลี่ยงชนกับคีย์เวิร์ดของ Python” และว่า “โดยทั่วไปควรเติมขีดล่างท้ายเดี่ยว ดีกว่าใช้คำย่อหรือสะกดเพี้ยน เช่น list_ ดีกว่า lst”
#16 ขีดล่างนำหน้า
มักเห็นโปรแกรมเมอร์ Python ที่มีประสบการณ์เติมขีดล่างนำหน้าตัวระบุหรือนามเมธอด ซึ่งมีเหตุผล
ขีดล่างที่นำหน้าตัวระบุหรือเมธอดมีนัยแฝงว่า ตัวแปรหรือเมธอดนี้ตั้งใจใช้ภายในเท่านั้น โดยหลักแล้วเป็นคำเตือนต่อโปรแกรมเมอร์คนอื่นตาม PEP 8 แต่ Python ไม่ได้บังคับใช้ ดังนั้นจึงเป็นตัวบ่งชี้ที่อ่อน
ต่างจาก Java, Python ไม่มีการแบ่ง private/public ที่เข้มแข็ง กล่าวคือมีความหมายเพราะชุมชนเห็นพ้องเท่านั้น การใส่ขีดล่างไม่กระทบพฤติกรรมของโปรแกรม
#17 ขีดล่างเพื่อความอ่านง่าย
ทริคสุดท้ายเกี่ยวกับขีดล่าง; จนถึงตอนนี้เราครอบคลุม 3 กรณีใช้แล้ว แต่สามารถดูบทความ บทบาทของขีดล่าง(_) ใน Python เพื่อเรียนรู้เพิ่มเติม
อีกวิธีในการใช้ขีดล่างคือเป็นตัวคั่นช่วยมองเห็นกลุ่มหลักของตัวเลขใน literal แบบจำนวนเต็ม ทศนิยม และเชิงซ้อน — ฟีเจอร์นี้มีตั้งแต่ Python 3.6
แนวคิดคือช่วยให้อ่านค่าที่ยาว หรือค่าที่ควรแบ่งส่วนให้ชัด อ่านเพิ่มเติมได้ใน PEP 515
ทริคด้านสไตล์โค้ด & ไวยากรณ์
#18 __name__ == “__main__”
มีโอกาสสูงว่าคุณเคยเห็นไวยากรณ์นี้ในหลายโปรแกรม Python; Python ใช้ชื่อติเศษว่า "__main__" และกำหนดให้ตัวระบุ __name__ หากไฟล์ Python ที่รันอยู่เป็นโปรแกรมหลัก
ถ้านำโมดูลในภาพหน้าจอไป import ในโมดูลอื่น (ไฟล์ Python อื่น) แล้วรันไฟล์นั้น เงื่อนไขในโค้ดจะเป็นเท็จ เพราะเมื่อ import จากโมดูลอื่น __name__ จะถูกตั้งเป็นชื่อโมดูล (ชื่อไฟล์ Python)
#19 เมธอด ‘setdefault’
คุณอาจต้องการกำหนดค่าให้หลายคีย์ในพจนานุกรม เช่น ตอนนับคำในคลังข้อความ วิธีทั่วไปคือ:
โค้ดจะหน้าตาแบบนี้:
วิธีที่กระชับกว่าคือใช้เมธอด setdefault() บนพจนานุกรม
อาร์กิวเมนต์ตัวแรกคือคีย์ที่ต้องการตรวจสอบ ตัวที่สองคือค่าที่จะตั้งให้คีย์นั้นหากยังไม่มีอยู่ — ถ้าคีย์มีอยู่แล้ว เมธอดจะคืนค่าปัจจุบัน จึงไม่เปลี่ยนค่า
ทริคด้านโครงสร้างโปรแกรม
#20 จับคู่ regex
Regular expressions ช่วยระบุรูปแบบของข้อความเพื่อค้นหา คนส่วนใหญ่รู้ว่าใช้ CTRL + F (Windows) เพื่อค้นหาได้ แต่ถ้าไม่รู้คำตรงๆ ที่จะหา จะทำอย่างไร? คำตอบคือค้นหารูปแบบ
เช่น หมายเลขในสหราชอาณาจักรมีรูปแบบคล้ายกัน: เริ่มด้วยเลขศูนย์ตามด้วยอีกสิบหลัก หรือเริ่มด้วย +44 แทนศูนย์และตามด้วยสิบหลัก — แบบหลังคือรูปแบบสากล
Regex ช่วยประหยัดเวลามหาศาล หากต้องเขียนกฎเพื่อดักกรณีในภาพแทน regex อาจยาวเกิน 10 บรรทัด
การเข้าใจ regex สำคัญแม้ไม่เขียนโค้ด เพราะโปรแกรมแก้ไขข้อความสมัยใหม่มักรองรับการค้นหาและแทนที่ด้วย regex
#21 เครื่องหมายท่อใน regex
ใน regex มีอักขระพิเศษเรียกว่า pipe (|) สำหรับจับคู่หนึ่งในหลายๆ นิพจน์ และใช้ที่ใดก็ได้ มีประโยชน์มากเมื่อมีรูปแบบคล้ายกันหลายแบบ
เช่น ‘Superman’, ‘Superwoman’, และ ‘Superhuman’ มีคำนำหน้าเดียวกัน จึงใช้ pipe เพื่อคงส่วนที่ซ้ำและเปลี่ยนเฉพาะส่วนที่ต่าง ช่วยประหยัดเวลาอีกครั้ง
ข้อควรระวัง: หากทุกนิพจน์ที่ต้องการจับเกิดอยู่ในข้อความเดียวกัน จะคืนผลการจับคู่ครั้งแรกที่พบ — เช่น “An example text containing Superwoman, Superman, Superhuman,” จะคืน Superwoman
#22 พารามิเตอร์ ‘sep’ ของฟังก์ชัน print()
มีโปรแกรมเมอร์ Python จำนวนไม่น้อยที่ไม่รู้ความสามารถเต็มรูปแบบของ print(); หาก “Hello World” เป็นโปรแกรมแรกของคุณ print() คงเป็นฟังก์ชันในตัวแรกๆ ที่เรียน เราใช้เพื่อแสดงข้อความที่จัดรูปแบบ แต่จริงๆ แล้วยังทำได้อีกมาก
โค้ดด้านบนแสดงหลายวิธีในการแสดงข้อความที่จัดรูปแบบ พารามิเตอร์ sep เป็นอาร์กิวเมนต์ทางเลือกของ print() ที่ให้ระบุว่าจะแทรกอะไรคั่นระหว่างอ็อบเจกต์เมื่อพิมพ์มากกว่าหนึ่งตัว
ค่าเริ่มต้นคือเว้นวรรค แต่เราเปลี่ยนพฤติกรรมนี้ในคำสั่ง print — ครั้งหนึ่งตั้ง sep เป็น "" และอีกครั้งเป็น "."
#23 ฟังก์ชัน lambda
ฟังก์ชัน lambda พาคุณเข้าสู่ระดับกลาง-ขั้นสูงของสิ่งที่ทำได้ด้วย Python — เรียนคอร์ส Intermediate Python ได้ที่นี่ มองเผินๆ อาจดูยาก แต่จริงๆ เรียบง่าย
ในตัวอย่างเราใช้แค่อาร์กิวเมนต์เดียว แต่จะใช้หลายตัวก็ได้:
โดยแก่น คีย์เวิร์ด lambda อนุญาตให้สร้างฟังก์ชันขนาดเล็ก จำกัดความสามารถ แบบไม่ระบุชื่อ ในบรรทัดเดียว ทำงานเหมือนฟังก์ชันปกติที่ประกาศด้วย def เพียงแต่ไม่มีชื่อ
#24 เมธอด ‘swapcase’
เมธอด swapcase() ใช้กับสตริงเพื่อสลับอักษรตัวใหญ่เป็นตัวเล็กและกลับกันได้ในบรรทัดเดียว แม้จะไม่ค่อยมีกรณีใช้งานมาก แต่ก็น่ารู้ไว้
#25 เมธอด ‘isalnum’
สมมติเราสร้างโปรแกรมที่กำหนดให้รหัสผ่านต้องมีทั้งตัวอักษรและตัวเลข สามารถทำได้ในบรรทัดเดียวด้วยการเรียก isalnum() บนอินสแตนซ์สตริง
เมธอดนี้ตรวจว่าตัวอักษรทั้งหมดเป็นตัวอักษร (A-Za-z) และตัวเลข (0-9) หรือไม่ หากมีช่องว่างหรือสัญลักษณ์ (!#%$&? เป็นต้น) จะคืนค่า False
#26 การจัดการข้อยกเว้น
โปรแกรม Python จะหยุดทำงานเมื่อพบข้อผิดพลาด
บางครั้งเราไม่ต้องการพฤติกรรมนี้ เช่น เมื่อมีผู้ใช้ปลายทางโต้ตอบกับโค้ดของเรา จะเลวร้ายเพียงใดหากโปรแกรมปิดก่อนกำหนด?
มีแนวคิดหลายแบบในการรับมือกรณีพิเศษ นักพัฒนา Python จำนวนมากมักยึดแนวคิดว่า “ขออภัยทีหลังง่ายกว่าขออนุญาตก่อน” นั่นคือจะยอมจับข้อผิดพลาดเมื่อเกิดขึ้นด้วยบริบทที่เตรียมรับข้อยกเว้นไว้ มากกว่าจะเสียเวลาป้องกันทุกกรณีที่อาจเกิดได้
แต่นี่จะใช้ได้ก็ต่อเมื่อมีวิธีรับมือหลังปัญหาเกิดจริง
#27 หาความแตกต่างในลิสต์
นี่คือสามวิธีในการเปรียบเทียบหาความต่างระหว่างลิสต์สองชุดใน Python
หมายเหตุ: เว้นแต่จะรู้แน่ชัดว่า list_1 เป็นสับเซ็ตของ list_2 มิฉะนั้นวิธีที่ 1 จะไม่เหมือนอีกสองวิธี
#28 Args & kwargs
เราใช้ *args และ **kwargs เป็นพารามิเตอร์ของฟังก์ชันเมื่อไม่ทราบจำนวนตัวแปรล่วงหน้าที่ฟังก์ชันจะรับได้
*args อนุญาตให้ส่งอาร์กิวเมนต์แบบไม่มีคีย์เวิร์ดเข้ามาเป็นจำนวนแปรผัน ส่วน **kwargs อนุญาตให้ส่งอาร์กิวเมนต์แบบมีคีย์เวิร์ดได้ตามต้องการ
จริงๆ แล้วคำว่า *args และ **kwargs ไม่ได้วิเศษอะไร จุดสำคัญอยู่ที่ดอกจัน (*) หมายความว่าเราจะใช้คำใดตามหลังดอกจันก็ได้ เพียงแต่ args และ kwargs เป็นแบบแผนที่ใช้กันและเป็นที่ยอมรับในหมู่นักพัฒนา Python
#29 Ellipsis
Ellipsis เป็นอ็อบเจกต์ใน Python ที่เรียกได้ด้วยเครื่องหมายจุดสามจุด (...) หรือเรียกอ็อบเจกต์เอง (Ellipsis)
การใช้งานที่เด่นคือการเข้าถึงและ slice อาเรย์หลายมิติใน NumPy เช่น:
อีกการใช้งานของ Ellipsis คือเป็นที่คั่น (placeholder) ในฟังก์ชันที่ยังไม่ implement
กล่าวคือจะใช้ Ellipsis, ... หรือ pass ก็ล้วนถูกต้อง
#30 List comprehension
ทริคสุดท้ายคือ list comprehension ซึ่งเป็นวิธีที่งดงามในการสร้างลิสต์จากลำดับอื่น สามารถเขียนตรรกะและการกรองที่ซับซ้อนได้ดังที่แสดงในโค้ด
มีวิธีอื่นทำได้เช่นกัน เช่น ใช้ lambda ดังนี้:
แต่ Pythonista หลายคนจะโต้แย้งว่าวิธีนี้อ่านยากกว่า list comprehension มาก