อาร์กิวเมนต์ปกติกับอาร์กิวเมนต์ของคำหลัก


290

"อาร์กิวเมนต์คำหลัก" แตกต่างจากอาร์กิวเมนต์ปกติอย่างไร ไม่สามารถส่งอาร์กิวเมนต์ทั้งหมดname=valueแทนการใช้ไวยากรณ์ตำแหน่งได้หรือไม่


6
คุณอาจต้องการอ่าน PEP 3102 - พวกเขาจัดระเบียบ
Ben Hoyt

และไม่ว่าจะมีค่าเริ่มต้นหรือไม่ก็ตาม (ยกเว้นว่าคุณต้องการส่งค่าให้หรือไม่) ใช่ไหม
mk12

อ่านเพิ่มเติมเกี่ยวกับข้อโต้แย้งตำแหน่ง / คำหลักของหลาม
ducin

@Ben Hoyt เพิ่มคำตอบด้านล่างซึ่งครอบคลุม Python 3, อาร์กิวเมนต์คำหลักที่จำเป็น
Christophe Roussy

คำตอบ:


347

มีแนวคิดที่เกี่ยวข้องสองแนวคิดซึ่งเรียกว่า " อาร์กิวเมนต์ของคำหลัก "

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

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

def my_function(arg1, arg2, **kwargs)

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

def my_function(**kwargs):
    print str(kwargs)

my_function(a=12, b="abc")

{'a': 12, 'b': 'abc'}

5
+1 และยอมรับ: คุณเป็นคนเดียวที่พูดคุยเกี่ยวกับอาร์กิวเมนต์ตำแหน่ง + คำหลักทั้งสองประเภททุกคนคิดว่าฉันกำลังพูดถึงเรื่องแรกหรือครั้งที่สอง (แต่พวกเขายังโพสต์ได้ดี) ขอบคุณ!
mk12

34
การใช้ถ้อยคำไม่ชัดเจน: โดยปกติคุณพูดถึงการขัดแย้งในด้านการโทรในขณะที่พารามิเตอร์ด้านที่เรียก
glglgl

3
ชื่อพารามิเตอร์ต้องเป็นkwargsหรือฉันสามารถเปลี่ยนชื่อเป็น sth ชอบoptions( def my_fuction(arg1, arg2, **options))?
บรูซซัน

1
ชื่อสามารถเป็นอะไรก็ได้ แต่kwargsเป็นแบบแผนเมื่อไม่มีชื่อที่เหมาะสมกว่า
แมตต์ซิมเมอร์แมน

ฉันคิดว่าแนวคิดที่สองที่อธิบายไว้ที่นี่เรียกว่าเป็นข้อโต้แย้งทางคำหลักโดยพลการ
Anshul Dahiya

188

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

def foo(*positional, **keywords):
    print "Positional:", positional
    print "Keywords:", keywords

*positionalอาร์กิวเมนต์จะเก็บทั้งหมดของการขัดแย้งตำแหน่งผ่านไปfoo()โดยไม่มีการ จำกัด จำนวนที่คุณสามารถให้

>>> foo('one', 'two', 'three')
Positional: ('one', 'two', 'three')
Keywords: {}

**keywordsอาร์กิวเมนต์จะเก็บข้อโต้แย้งคำหลัก:

>>> foo(a='one', b='two', c='three')
Positional: ()
Keywords: {'a': 'one', 'c': 'three', 'b': 'two'}

และแน่นอนคุณสามารถใช้ทั้งสองอย่างในเวลาเดียวกัน:

>>> foo('one','two',c='three',d='four')
Positional: ('one', 'two')
Keywords: {'c': 'three', 'd': 'four'}

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


3
คำตอบที่ยอดเยี่ยม! เพียงแค่ทราบว่าจำเป็นต้องมีการขัดแย้งตำแหน่งสามารถส่งผ่านไปก่อน*positionalและถ้าเราเปลี่ยนนิยามฟังก์ชั่นเช่น**keywords def foo(arg1, *positional, **keywords):นี่arg1คือตำแหน่งและจำเป็น โปรดทราบว่าตำแหน่งในคำตอบหมายถึงตัวเลือกและจำนวนตัวแปรของการขัดแย้งตำแหน่ง
shaffooo

2
ใช่คำตอบที่ดี ทราบอีก: ถ้าคุณเรียกใช้ฟังก์ชันของคุณfoo(bar=True)คุณจะได้รับค่าใช้เช่นเดียวกับbar = keywords.pop('bar') bar = keywords.pop('bar', None)สำหรับค่าเริ่มต้นให้ใช้bar = keywords.pop('bar', False)
olibre

111

การใช้คำหลักอาร์กิวเมนต์เป็นสิ่งเดียวกับอาร์กิวเมนต์ปกติยกเว้นคำสั่งซื้อไม่สำคัญ ตัวอย่างเช่นการเรียกฟังก์ชันทั้งสองด้านล่างนี้จะเหมือนกัน:

def foo(bar, baz):
    pass

foo(1, 2)
foo(baz=2, bar=1)

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

47

อาร์กิวเมนต์ตำแหน่ง

พวกเขาไม่มีคำหลักมาก่อน คำสั่งซื้อเป็นสิ่งสำคัญ!

func(1,2,3, "foo")

อาร์กิวเมนต์ของคำหลัก

พวกเขามีคำหลักอยู่ข้างหน้า พวกเขาสามารถอยู่ในลำดับใด ๆ !

func(foo="bar", baz=5, hello=123)

func(baz=5, foo="bar", hello=123)

คุณควรทราบด้วยว่าหากคุณใช้อาร์กิวเมนต์เริ่มต้นและละเลยการแทรกคำหลักดังนั้นลำดับจะสำคัญ!

def func(foo=1, baz=2, hello=3): ...
func("bar", 5, 123)

8
IMHO ตัวอย่างที่ 3 (อาร์กิวเมนต์เริ่มต้น) ไม่ชัดเจน ฉันคิดว่าคุณกำลังพูดถึงสิ่งที่เกิดขึ้นเมื่อหนึ่งหรือมากกว่าหนึ่งพารามิเตอร์ประกาศค่าเริ่มต้นและการโทรใช้สัญกรณ์ตำแหน่ง แต่ส่งน้อยกว่าจำนวนของพารามิเตอร์ที่ประกาศ อย่างไรก็ตามตัวอย่างของคุณมี 3 ประกาศและ 3 ในการโทรดังนั้นค่าเริ่มต้นจึงไม่มีผลเลย! คุณตั้งใจจะละเว้นข้อโต้แย้งที่ 3 เช่นfunc("bar", 5)? แล้วบอกว่าhelloมันได้รับค่าเริ่มต้น3เป็น
ToolmakerSteve

25

มีสองวิธีในการกำหนดค่าอาร์กิวเมนต์ให้กับพารามิเตอร์ฟังก์ชันซึ่งใช้ทั้งสองวิธี

  1. ตามตำแหน่ง อาร์กิวเมนต์ตำแหน่งไม่ได้มีคำหลักและได้รับมอบหมายก่อน

  2. โดยใช้คำสำคัญ อาร์กิวเมนต์คำหลักมีคำหลักและได้รับการกำหนดที่สองหลังจากอาร์กิวเมนต์ตำแหน่ง

โปรดทราบว่าคุณมีตัวเลือกในการใช้อาร์กิวเมนต์ตำแหน่ง

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

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


1
โอ้ฉันคิดว่าพารามิเตอร์เมื่อสิ่งที่จริงคืออาร์กิวเมนต์ (สิ่งที่ฉันผ่าน) ขอบคุณ!
mk12

24

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

>>> def func(a='a', b='b', c='c', **kwargs):
...    print 'a:%s, b:%s, c:%s' % (a, b, c)
... 
>>> func()
a:a, b:b, c:c
>>> func(**{'a' : 'z', 'b':'q', 'c':'v'})
a:z, b:q, c:v
>>> 

11
+1 สำหรับเทคนิคที่มีประโยชน์ , **kwargsจุดของคุณจะเป็นที่ชัดเจนโดยไม่ต้อง นั่นจะแสดงให้เห็นว่าแม้แต่ฟังก์ชั่นการฟังก์ชั่นที่เรียบง่ายพร้อมพารามิเตอร์จำนวนคงที่ก็สามารถให้พจนานุกรมได้ นั่นคือมันไม่ต้องการอะไรแฟนซีในคำจำกัดความ จากนั้นคุณอาจเพิ่มตัวอย่างที่สองโดยมี ** kwargs ในคำจำกัดความและแสดงว่ารายการพิเศษในพจนานุกรมมีให้ผ่านทางนั้นได้อย่างไร
ToolmakerSteve

1
ฉันได้เห็นสิ่งนี้เกิดขึ้นในซอร์สโค้ดของไลบรารีต่างๆและสับสนมาก ขอบคุณสำหรับการล้างมัน!
Craig Labenz

3
พารามิเตอร์ที่เป็นทางการตัวที่สี่ด้านบน - ** kwargs เป็นสิ่งจำเป็นหากคุณเรียก func ด้วยพจนานุกรมที่มีคีย์อื่นนอกเหนือจาก 'a', 'b' และ 'c'
Eduardo

สำหรับฉันprint 'a:%s, b:%s, c:%s' % (a, b, c)ให้ข้อผิดพลาดทางไวยากรณ์ แต่ใช้print('a:%s, b:%s, c:%s' % (a, b, c))งานได้ มีบางอย่างในเวอร์ชั่น Python ใช่ไหม ยังไงก็ตามขอบคุณสำหรับความเข้าใจนี้จนถึงตอนนี้ฉันใช้ clunky มากขึ้นprint('a:{}, b:{}, c:{}'.format(a, b, c))
Axel Bregnsbo

17

การใช้Python 3คุณสามารถมีทั้งอาร์กิวเมนต์ที่จำเป็นและไม่จำเป็น:


ไม่บังคับ : (กำหนดค่าเริ่มต้นสำหรับพารามิเตอร์ 'b')

def func1(a, *, b=42):
    ...
func1(value_for_a) # b is optional and will default to 42

จำเป็น (ไม่ได้กำหนดค่าเริ่มต้นสำหรับพารามิเตอร์ 'b'):

def func2(a, *, b):
    ... 
func2(value_for_a, b=21) # b is set to 21 by the function call
func2(value_for_a) # ERROR: missing 1 required keyword-only argument: 'b'`

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


3
ต้องตัวแปรที่เป็นประโยชน์มาก มันกระตุ้นให้ตั้งชื่อโดยไม่ต้องตั้งค่าเริ่มต้นซึ่งมักจะไม่สมเหตุสมผล
ทีเอ็นที

ค่าเริ่มต้นดูดีและสามารถช่วยคุณประหยัดเวลาเมื่อคุณเริ่มต้น แต่ในค่าเริ่มต้นระยะยาวสามารถเป็น PITA
Christophe Roussy

11

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

def test_var_kwargs(farg, **kwargs):
    print "formal arg:", farg
    for key in kwargs:
        print "another keyword arg: %s: %s" % (key, kwargs[key])

สิ่งนี้ช่วยให้คุณสามารถใช้อาร์กิวเมนต์คำหลักโดยพลการซึ่งอาจมีคีย์ที่คุณไม่ต้องการกำหนดล่วงหน้า


0

ฉันกำลังมองหาตัวอย่างที่มี kwargs เริ่มต้นโดยใช้คำอธิบายประกอบประเภท:

def test_var_kwarg(a: str, b: str='B', c: str='', **kwargs) -> str:
     return ' '.join([a, b, c, str(kwargs)])

ตัวอย่าง:

>>> print(test_var_kwarg('A', c='okay'))
A B okay {}
>>> d = {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', c='c', b='b', **d))
a b c {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', 'b', 'c'))
a b c {}

0

เพียงแค่เพิ่ม / เพิ่มวิธีการกำหนดค่าเริ่มต้นของการขัดแย้งที่ไม่ได้กำหนดไว้ในคำสำคัญเมื่อเรียกใช้ฟังก์ชัน:

def func(**keywargs):
if 'my_word' not in keywargs:
    word = 'default_msg'
else:
    word = keywargs['my_word']
return word

เรียกสิ่งนี้โดย:

print(func())
print(func(my_word='love'))

คุณจะได้รับ:

default_msg
love

อ่านเพิ่มเติมเกี่ยวกับ*argsและ**kwargsในไพ ธ อน: https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3

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