วิธีการเรียนสร้าง "TypeError: ... ได้หลายค่าสำหรับอาร์กิวเมนต์คำหลัก ... "


129

ถ้าฉันกำหนดวิธีการเรียนด้วยอาร์กิวเมนต์คำหลักจึง:

class foo(object):
  def foodo(thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

เรียกวิธีการสร้างTypeError:

myfoo = foo()
myfoo.foodo(thing="something")

...
TypeError: foodo() got multiple values for keyword argument 'thing'

เกิดอะไรขึ้น?


1
คุณจะไม่ได้คำตอบที่น่าพอใจว่าทำไมอย่างชัดเจนจะดีกว่าโดยปริยายself this
nurettin

คำตอบ:


163

selfปัญหาคือว่าอาร์กิวเมนต์แรกส่งผ่านไปยังวิธีการเรียนในหลามอยู่เสมอสำเนาเช่นชั้นที่วิธีการที่เรียกว่าป้ายโดยทั่วไป หากชั้นเรียนมีการประกาศดังนี้:

class foo(object):
  def foodo(self, thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

มันทำงานตามที่คาดไว้

คำอธิบาย:

โดยไม่ต้องselfเป็นพารามิเตอร์แรกเมื่อmyfoo.foodo(thing="something")ถูกดำเนินการวิธีการที่เรียกว่ามีข้อโต้แย้งfoodo จากนั้น(myfoo, thing="something")อินสแตนซ์myfooจะถูกกำหนดให้thing(เนื่องจากthingเป็นพารามิเตอร์แรกที่ประกาศไว้) แต่ไพ ธ อนก็พยายามกำหนด"something"ให้thingดังนั้นข้อยกเว้น

หากต้องการสาธิตให้ลองใช้รหัสเดิม:

myfoo.foodo("something")
print
print myfoo

คุณจะชอบ:

<__main__.foo object at 0x321c290>
a thong is something

<__main__.foo object at 0x321c290>

คุณจะเห็นว่า 'สิ่ง' ได้รับการอ้างอิงถึงอินสแตนซ์ 'myfoo' ของคลาส 'foo' ส่วนนี้ของเอกสารอธิบายวิธีการทำงานของอาร์กิวเมนต์ทำงานอีกเล็กน้อย


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

48

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


7
นั่นคือสิ่งที่เกิดขึ้นกับฉันขอบคุณที่เพิ่มคำตอบนี้ นี่อาจเป็นความผิดพลาดทั่วไปที่เกิดขึ้นซึ่งเป็นสาเหตุที่คุณรับ upvote ของฉัน
rdrey

เช่นเดียวกับที่เกิดขึ้นเมื่อการบรรทุกเกินพิกัด@classmethodการแก้ปัญหาที่ถูกใช้แทนsuper().function(...) <parentclass>.function(cls, ...)
ederag

30

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

>>> def foodo(thing=None, thong='not underwear'):
...     print thing if thing else "nothing"
...     print 'a thong is',thong
...
>>> foodo('something', thing='everything')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foodo() got multiple values for keyword argument 'thing'

6

เพียงเพิ่มมัณฑนากร 'staticmethod' ให้กับฟังก์ชันและปัญหาได้รับการแก้ไขแล้ว

class foo(object):
    @staticmethod
    def foodo(thing=None, thong='not underwear'):
        print thing if thing else "nothing" 
        print 'a thong is',thong

ฉันเพิ่งได้รับข้อผิดพลาดและวิธีนี้แก้ไขปัญหาของฉัน แต่คุณสามารถอธิบายรายละเอียดเกี่ยวกับวิธีการหรือเหตุผลที่มัณฑนากรนี้แก้ไขปัญหาได้หรือไม่?
เรย์

1
staticmethod หยุดวิธีการรับตนเองเป็นอาร์กิวเมนต์แรก ดังนั้นตอนนี้ถ้าคุณโทรหาmyfoo.foodo(thing="something")สิ่ง = "บางอย่าง" จะถูกกำหนดให้กับอาร์กิวเมนต์แรกแทนที่จะเป็นอาร์กิวเมนต์ตนเองโดยนัย
danio

นอกจากนี้ยังหมายความว่าคุณไม่สามารถเข้าถึงตัวแปรคลาสภายในฟังก์ชันซึ่งมักจะเข้าถึงได้ผ่านself
drevicko

4

ฉันต้องการเพิ่มคำตอบอีกหนึ่งข้อ:

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

there is difference between parameter and argumentคุณสามารถอ่านรายละเอียดเกี่ยวกับที่นี่อาร์กิวเมนต์และพารามิเตอร์เป็นไพ ธ อน

def hello(a,b=1, *args):
   print(a, b, *args)


hello(1, 2, 3, 4,a=12)

เนื่องจากเรามีสามพารามิเตอร์:

a คือพารามิเตอร์ตำแหน่ง

b = 1 คือคำหลักและพารามิเตอร์เริ่มต้น

* args เป็นพารามิเตอร์ความยาวผันแปร

ดังนั้นก่อนอื่นเรากำหนดพารามิเตอร์เป็นตำแหน่งหมายความว่าเราต้องให้ค่ากับอาร์กิวเมนต์ตำแหน่งในคำสั่งตำแหน่งของมันที่นี่มีคำสั่ง แต่เรากำลังผ่านอาร์กิวเมนต์ 1 ที่ฟังก์ชัน a ในการเรียกจากนั้นเราจะให้ค่าแก่ a ซึ่งถือเป็นอาร์กิวเมนต์ของคำหลัก ตอนนี้มีสองค่า:

หนึ่งคือค่าตำแหน่ง: a = 1

ที่สองคือค่าคีย์เวิร์ดซึ่งเป็น = 12

สารละลาย

เราต้องเปลี่ยนhello(1, 2, 3, 4,a=12)เป็นhello(1, 2, 3, 4,12) ดังนั้นตอนนี้ a จะได้รับค่าตำแหน่งเดียวซึ่งคือ 1 และ b จะได้รับค่า 2 และค่าที่เหลือจะได้รับ * args (พารามิเตอร์ความยาวผันแปร)

ข้อมูลเพิ่มเติม

ถ้าเราต้องการ * args ควรได้ 2,3,4 และ a ควรได้ 1 และ b ควรได้ 12

จากนั้นเราสามารถทำสิ่งนี้ได้
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

มีอะไรเพิ่มเติม:

def hello(a,*c,b=1,**kwargs):
    print(b)
    print(c)
    print(a)
    print(kwargs)

hello(1,2,1,2,8,9,c=12)

ผลลัพธ์:

1

(2, 1, 2, 8, 9)

1

{'c': 12}

ถูกครอบคลุมโดยคำตอบstackoverflow.com/a/31822875/12663 - ตัวอย่างของคุณมีพารามิเตอร์เดียวกัน (a) ที่กำหนดโดยตำแหน่งและชื่ออย่างชัดเจน
danio

3

ข้อผิดพลาดนี้สามารถเกิดขึ้นได้หากคุณส่งอาร์กิวเมนต์คำสำคัญซึ่งหนึ่งในคีย์นั้นคล้ายกัน (มีชื่อสตริงเดียวกัน) ไปยังอาร์กิวเมนต์ตำแหน่ง

>>> class Foo():
...     def bar(self, bar, **kwargs):
...             print(bar)
... 
>>> kwgs = {"bar":"Barred", "jokes":"Another key word argument"}
>>> myfoo = Foo()
>>> myfoo.bar("fire", **kwgs)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() got multiple values for argument 'bar'
>>> 

"fire" ได้รับการยอมรับในการโต้แย้ง 'bar' และยังมีการโต้เถียง 'บาร์' อื่นใน kwargs

คุณจะต้องลบอาร์กิวเมนต์คำหลักออกจาก kwargs ก่อนส่งผ่านไปยังเมธอด


1

นอกจากนี้ยังสามารถเกิดขึ้นได้ใน Django ถ้าคุณใช้ jquery ajax เพื่อ url ที่ย้อนกลับไปยังฟังก์ชันที่ไม่มีพารามิเตอร์ 'คำขอ'

$.ajax({
  url: '{{ url_to_myfunc }}',
});


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