จันดอกจันในฟังก์ชันอาร์กิวเมนต์?


242

เครื่องหมายดอกจันเปลือยในอาร์กิวเมนต์ของฟังก์ชันทำอะไร

เมื่อฉันดูโมดูลดองฉันเห็นสิ่งนี้:

pickle.dump(obj, file, protocol=None, *, fix_imports=True)

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

>>> def func(*):
...     pass
...
  File "<stdin>", line 1
SyntaxError: named arguments must follow bare *

ถ้ามันเป็นเรื่องสำคัญฉันใช้ python 3.3.0


คำตอบ:


221

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

ดูคำตอบนี้หรือเอกสาร Python 3สำหรับรายละเอียดเพิ่มเติม


3
หมายเหตุว่าทุกตำแหน่ง (ไม่มีชื่อ) ข้อโต้แย้งรวมทั้งจะต้องเกิดขึ้นก่อนที่เปลือย*args *
BallpointBen

4
นอกจากนี้โปรดทราบว่ามีการเรียงลำดับของคู่ / / ซึ่งทำเครื่องหมายจุดสิ้นสุดของอาร์กิวเมนต์ตำแหน่งเท่านั้น ( stackoverflow.com/questions/28243832/ … )
สตีเฟ่น

2
@BallpointBen: *แทนที่*argsและในทางกลับกัน; พวกเขาไม่สามารถอยู่ร่วมกันในลายเซ็นได้ นั่นเป็นเหตุผลที่พวกเขาเลือก*; ก่อนหน้านี้*argsเป็นวิธีเดียวที่จะบังคับให้มีการขัดแย้งตำแหน่งอย่างหมดจดและมันเป็นจุดสิ้นสุดของการขัดแย้งที่สามารถส่งผ่านตำแหน่ง (เนื่องจากมีการรวบรวมอาร์กิวเมนต์ตำแหน่งที่เหลืออยู่ทั้งหมด *หมายถึง "อาร์กิวเมนต์ตำแหน่งไม่สามารถไปไกลกว่าที่นี่" แต่การขาดชื่อหมายถึง "แต่ฉันจะไม่ยอมรับพวกเขาเลยเพราะฉันเลือกที่จะไม่ให้สถานที่ที่จะทำให้พวกเขา"
ShadowRanger

70

ในขณะที่คำตอบเดิมตอบคำถามได้อย่างสมบูรณ์เพียงแค่เพิ่มข้อมูลที่เกี่ยวข้องเล็กน้อย PEP-3102สำหรับพฤติกรรมที่เกิดขึ้นเครื่องหมายดอกจันเดียวจาก การอ้างถึงส่วนที่เกี่ยวข้อง:

The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:

    def compare(a, b, *, key=None):
        ...

key="value"ในภาษาอังกฤษง่ายๆก็หมายความว่าจะผ่านค่าสำหรับคีย์คุณจะต้องผ่านอย่างชัดเจนว่ามันเป็น


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

11
@ สตีเฟ่นฉันคิดว่าเหมือนกันผลของการเปลือย*คือการฮุบการโต้เถียงในตำแหน่งที่เหลือ แต่นั่นไม่ใช่กรณี ผ่านข้อโต้แย้งตำแหน่งพิเศษกว่าคาดว่าฟังก์ชั่นที่ช่วยให้เกิดข้อผิดพลาดแบบนี้:foo() takes exactly 1 positional argument (2 given)
Ajay M

19
def func(*, a, b):
    print(a)
    print(b)

func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb

ตัวอย่างข้างต้นด้วย ** kwargs

def func(*, a, b, **kwargs):
    print(a)
    print(b)
    print(kwargs)

func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}

6

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

>>> def f(a, *, b):
...     return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3

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

เปรียบเทียบเช่นเทียบกับถ้าคุณเขียนsorted(nums, reverse=True) sorted(nums, True)หลังจะอ่านได้น้อยกว่ามากดังนั้นผู้พัฒนา Python จึงเลือกที่จะทำให้คุณเขียนแบบเดิม


4

สมมติว่าคุณมีฟังก์ชั่น:

def sum(a,key=5):
    return a + key 

คุณสามารถเรียกใช้ฟังก์ชันนี้ได้ 2 วิธี:

sum(1,2) หรือ sum(1,key=2)

สมมติว่าคุณต้องการsumให้เรียกใช้ฟังก์ชันโดยใช้อาร์กิวเมนต์คำหลักเท่านั้น

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

ฟังก์ชั่นจึงกำหนดเป็น:

def sum(a,*,key=5):
    return a + key 

อาจถูกเรียกใช้เพียงอย่างเดียว sum(1,key=2)


-1

ฉันได้พบลิงค์ต่อไปนี้จะเป็นประโยชน์มากอธิบาย*, *argsและ**kwargs:

https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/

เป็นหลักนอกเหนือจากคำตอบข้างต้นฉันได้เรียนรู้จากเว็บไซต์ด้านบน (เครดิต: https://pythontips.com/author/yasoob008/ ) ต่อไปนี้:

ด้วยฟังก์ชั่นการสาธิตที่กำหนดไว้ด้านล่างแรกมีสองตัวอย่างหนึ่งรายการ*argsและหนึ่งรายการ**kwargs

def test_args_kwargs(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5

# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3

ดังนั้น*argsช่วยให้คุณสามารถสร้างรายการของข้อโต้แย้งที่จะดำเนินการตามลำดับที่ถูกป้อนในขณะที่**kwargsสามารถเปิดใช้งานการส่งผ่านของอาร์กิวเมนต์ NAMED และสามารถประมวลผลโดย NAME ตามลำดับ (โดยไม่คำนึงถึงลำดับที่พวกเขาป้อน) .

ไซต์ยังคงดำเนินต่อไปโดยสังเกตว่าการเรียงลำดับอาร์กิวเมนต์ที่ถูกต้องควรเป็น:

some_func(fargs,*args,**kwargs)

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