จะใช้ตัวดำเนินการคลายแพ็ก (*, **) ใน Python ได้อย่างไร

Python เป็นภาษาโปรแกรมที่ใช้มากที่สุด วันนี้คุณจะได้เรียนรู้การใช้หนึ่งในแกนหลักของมัน — แต่มักถูกละเลย — คุณสมบัติ การแกะกล่องใน Python

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

นี่คือรายการของแนวคิดที่คุณจะพบว่ามีประโยชน์ในขณะที่อ่านบทช่วยสอนนี้:

  • Iterable: ลำดับใดๆ ที่สามารถวนซ้ำได้โดย for-loop เช่น set, list, tuples และ dictionaries
  • Callable: วัตถุ Python ที่สามารถเรียกได้โดยใช้วงเล็บคู่ () ตัวอย่างเช่น myfunction()
  • เชลล์: สภาพแวดล้อมรันไทม์แบบโต้ตอบซึ่งให้เรารันโค้ด Python เราสามารถเรียกมันได้ด้วยการเรียกใช้ “python” ในเทอร์มินัล
  • ตัวแปร: ชื่อสัญลักษณ์ที่เก็บวัตถุและมีตำแหน่งหน่วยความจำที่สงวนไว้

เริ่มจากความสับสนที่พบบ่อยที่สุดกันก่อน: Asteristics ใน Python เป็นตัวดำเนินการทางคณิตศาสตร์ด้วย หนึ่งเครื่องหมายดอกจัน

ใช้สำหรับการคูณ ในขณะที่สองตัว (**) หมายถึงการยกกำลัง

>>> 3*3
9
>>> 3**3
27

เราสามารถพิสูจน์ได้โดยเปิด Python shell แล้วพิมพ์:

หมายเหตุ: คุณต้องติดตั้ง Python 3 เพื่อติดตามพร้อมกับบทช่วยสอนนี้ หากคุณยังไม่ได้ติดตั้ง โปรดดูคู่มือการติดตั้ง Python ของเรา

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

>>> *range(1, 6),
(1, 2, 3, 4, 5)
>>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2}
{'vanilla': 3, 'chocolate': 2, 'strawberry': 2}

ในทางกลับกัน เราใช้เครื่องหมายดอกจัน (*, **) ก่อนการวนซ้ำเพื่อแกะมัน — ตัวอย่างเช่น:

สารบัญ

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

แกะกล่องอะไร?

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

การแกะกล่องใน Python นั้นคล้ายกับการแกะกล่องในชีวิตจริง

>>> mybox = ['cables', 'headphones', 'USB']
>>> item1, item2, item3 = mybox

ลองแปลตัวอย่างเดียวกันนี้เป็นโค้ดเพื่อความเข้าใจที่ดีขึ้น:

อย่างที่คุณเห็น เรากำลังกำหนดสามรายการภายในรายการ mybox ให้กับตัวแปรสามรายการ item1, item2, item2 การกำหนดตัวแปรประเภทนี้เป็นแนวคิดพื้นฐานของการคลายแพ็กใน Python

>>> item1
'cables'
>>> item2
'headphones'
>>> item3
'USB'

หากคุณพยายามหาค่าของแต่ละรายการ คุณจะสังเกตเห็นว่ารายการที่ 1 หมายถึง “สายเคเบิล” รายการที่ 2 หมายถึง “หูฟัง” และอื่นๆ

>>> newbox = ['cables', 'headphones', 'USB', 'mouse']
>>> item1, item2, item3 = newbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

จนถึงตอนนี้ ทุกอย่างดูเหมือนจะปกติดีกับโค้ดนี้ แต่ถ้าเราต้องการแกะรายการที่มีองค์ประกอบมากกว่านี้ — การรักษาตัวแปรที่กำหนดจำนวนเท่าเดิม

  วิธีลบล็อคการเปิดใช้งานบน iPhone

เป็นไปได้ว่าคุณคาดว่าจะเกิดข้อผิดพลาดในลักษณะนี้ โดยพื้นฐานแล้วเรากำลังกำหนด 4 รายการให้กับตัวแปร 3 ตัว Python จัดการเพื่อกำหนดค่าที่ถูกต้องได้อย่างไร ไม่ นั่นเป็นเพราะเราได้รับ ค่าข้อผิดพลาด

พร้อมข้อความว่า “too many value to unpack”. สิ่งนี้เกิดขึ้นเนื่องจากเรากำลังตั้งค่าตัวแปรสามตัวทางด้านซ้าย และสี่ค่า (ที่สอดคล้องกับรายการกล่องใหม่) ทางด้านขวา

>>> lastbox = ['cables', 'headphones']
>>> item1, item2, item3 = lastbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)

หากคุณพยายามทำกระบวนการที่คล้ายกัน แต่มีตัวแปรมากกว่าค่าที่จะแกะ คุณจะได้รับ ValueError อื่น ยกเว้นข้อความที่แตกต่างกันเล็กน้อย:

หมายเหตุ: เรากำลังทำงานกับรายการ แต่คุณสามารถใช้รูปแบบนี้ในการแกะกล่องกับ iterable ใดๆ (รายการ, ชุด, สิ่งอันดับ, พจนานุกรม)

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

แน่นอนว่ามี และเรียกว่าตัวดำเนินการแกะกล่องหรือตัวดำเนินการเครื่องหมายดอกจัน (*, **) มาดูวิธีใช้ในภาษา Python กัน

วิธีแกะรายการด้วยตัวดำเนินการ *

ตัวดำเนินการเครื่องหมายดอกจัน

>>> first, *unused, last = [1, 2, 3, 5, 7]
>>> first
1
>>> last
7
>>> unused
[2, 3, 5]

ใช้เพื่อแยกค่าทั้งหมดของ iterable ที่ยังไม่ได้กำหนด

>>> first, *_, last = [1, 2, 3, 5, 7]
>>> _
[2, 3, 5]

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

>>> first, *_, last = [1, 2]
>>> first
1
>>> last
2
>>> _
[]

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

เรายังสามารถใช้เคล็ดลับนี้ได้แม้ว่ารายการจะมีเพียงสององค์ประกอบ:

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

>>> *string = 'PythonIsTheBest'

การแก้ไขปัญหาทั่วไป

>>> *string = 'PythonIsTheBest'
  File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple

เราสามารถแยกองค์ประกอบเฉพาะของ iterable ได้ ตัวอย่างเช่น คุณจะพบสิ่งนี้: อย่างไรก็ตาม โค้ดด้านบนจะส่งคืน SyntaxError:ทั้งนี้เนื่องจากตาม

ข้อกำหนด PEP

:

>>> *string, = 'PythonIsTheBest'
>>> string
['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']

ทูเพิล (หรือรายการ) ทางด้านซ้ายของงานที่มอบหมายอย่างง่าย

>>> *numbers, = range(5)
>>> numbers
[0, 1, 2, 3, 4]

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

  วิธีการตั้งค่า Microsoft Teams

อีกตัวอย่างหนึ่งคือการใช้ฟังก์ชัน range ซึ่งส่งกลับลำดับของตัวเลข

ตอนนี้คุณรู้วิธีแกะรายการและทูเพิลด้วยเครื่องหมายดอกจันแล้ว ก็ถึงเวลาแกะพจนานุกรม

วิธีแกะพจนานุกรมด้วยตัวดำเนินการ **

>>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} 
...
SyntaxError: invalid syntax

ในขณะที่ใช้เครื่องหมายดอกจันเดียวเพื่อแยกรายการและทูเพิล เครื่องหมายดอกจันคู่ (**) ใช้เพื่อแยกพจนานุกรม

>>> food = {'fish':3, 'meat':5, 'pasta':9} 
>>> colors = {'red': 'intensity', 'yellow':'happiness'}
>>> merged_dict = {**food, **colors}
>>> merged_dict
{'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}

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

อย่างไรก็ตาม เราสามารถใช้ตัวดำเนินการ ** ภายใน callables และพจนานุกรมอื่นๆ ตัวอย่างเช่น หากเราต้องการสร้างพจนานุกรมแบบรวมจากพจนานุกรมอื่น เราสามารถใช้โค้ดด้านล่าง:

นี่เป็นวิธีสั้นๆ ในการสร้างพจนานุกรมผสม อย่างไรก็ตาม นี่ไม่ใช่แนวทางหลักของการแกะกล่องใน Python

มาดูกันว่าเราจะใช้การคลายไฟล์กับ callables ได้อย่างไร

การบรรจุในฟังก์ชั่น: args และ kwargs

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

>>> def product(n1, n2):
...     return n1 * n2
... 
>>> numbers = [12, 1]
>>> product(*numbers)
12

การบรรจุด้วยตัวดำเนินการ * (args)

>>> product(12, 1)
12

สมมติว่าเรามีฟังก์ชันที่คำนวณผลคูณของตัวเลขสองตัว

>>> numbers = [12, 1, 3, 4]
>>> product(*numbers)
...
TypeError: product() takes 2 positional arguments but 4 were given

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

>>> def product(*args):
...     result = 1
...     for i in args:
...             result *= i
...     return result
...
>>> product(*numbers)
144

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

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

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

>>> product(5, 5, 5)
125
>>> print(5, 5, 5)
5 5 5

ฟังก์ชันการพิมพ์

>>> def test_type(*args):
...     print(type(args))
...     print(args)
... 
>>> test_type(1, 2, 4, 'a string')
<class 'tuple'>
(1, 2, 4, 'a string')

.

สุดท้าย มารับประเภทวัตถุของ args ของฟังก์ชัน

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

บรรจุด้วยตัวดำเนินการ ** (kwargs)

>>> def make_person(name, **kwargs):
...     result = name + ': '
...     for key, value in kwargs.items():
...             result += f'{key} = {value}, '
...     return result
... 
>>> make_person('Melissa', id=12112, location='london', net_worth=12000)
'Melissa: id = 12112, location = london, net_worth = 12000, '

ดังที่เราเห็นก่อนหน้านี้ ตัวดำเนินการ ** ใช้สำหรับพจนานุกรมเท่านั้น ซึ่งหมายความว่าด้วยตัวดำเนินการนี้ เราสามารถส่งคู่คีย์-ค่าไปยังฟังก์ชันเป็นพารามิเตอร์ได้

  11 แอพฟิตเนสที่ดีที่สุดที่ช่วยให้คุณออกกำลังกายได้จากทุกที่

มาสร้างฟังก์ชัน make_person ซึ่งรับอาร์กิวเมนต์ตำแหน่ง “ชื่อ” และอาร์กิวเมนต์คำหลักจำนวนไม่แน่นอน

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

>>> def test_kwargs(**kwargs):
...     print(type(kwargs))
...     print(kwargs)
... 
>>> test_kwargs(random=12, parameters=21)
<class 'dict'>
{'random': 12, 'parameters': 21}

หมายเหตุ: kwargs เป็นเพียงข้อตกลง คุณสามารถตั้งชื่อพารามิเตอร์นี้ตามที่คุณต้องการ

เราสามารถตรวจสอบประเภทของ kwargs ได้แบบเดียวกับที่เราทำกับ args:

>>> def my_final_function(*args, **kwargs):
...     print('Type args: ', type(args))
...     print('args: ', args)
...     print('Type kwargs: ', type(kwargs))
...     print('kwargs: ', kwargs)
... 
>>> my_final_function('Python', 'The', 'Best', language="Python", users="A lot")
Type args:  <class 'tuple'>
args:  ('Python', 'The', 'Best')
Type kwargs:  <class 'dict'>
kwargs:  {'language': 'Python', 'users': 'A lot'}

ตัวแปรภายใน kwargs จะเปลี่ยนให้เป็นพจนานุกรมเสมอ ซึ่งเก็บคู่คีย์-ค่าที่ส่งผ่านไปยังฟังก์ชัน

สุดท้าย ลองใช้ args และ kwargs ในฟังก์ชันเดียวกัน:

บทสรุป

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

args ใช้เพื่อส่งผ่านพารามิเตอร์ที่ไม่ใช่คีย์เวิร์ดไปยังฟังก์ชันkwargs ใช้เพื่อส่งพารามิเตอร์คีย์เวิร์ดไปยังฟังก์ชัน

เรื่องล่าสุด

x