Phương thức lớp tạo ra Type TypeError: Có nhiều giá trị cho đối số từ khóa


129

Nếu tôi định nghĩa một phương thức lớp với một đối số từ khóa, thì:

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

gọi phương thức này tạo ra một TypeError:

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

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

Chuyện gì đang xảy ra vậy?


1
Bạn sẽ không bao giờ có được một câu trả lời thỏa đáng về lý do tại sao rõ ràng selflà tốt hơn so với ngầm this.
Nurettin

Câu trả lời:


163

Vấn đề là đối số đầu tiên được truyền cho các phương thức lớp trong python luôn là một bản sao của thể hiện lớp mà phương thức được gọi, thường được gắn nhãn self. Nếu lớp được khai báo như vậy:

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

nó cư xử như mong đợi

Giải trình:

Không có selftham số đầu tiên, khi myfoo.foodo(thing="something")được thực thi, foodophương thức được gọi với các đối số (myfoo, thing="something"). Ví dụ myfoosau đó được gán cho thing(vì thinglà tham số được khai báo đầu tiên), nhưng python cũng cố gắng gán "something"cho thing, do đó Exception.

Để chứng minh, hãy thử chạy mã này với mã gốc:

myfoo.foodo("something")
print
print myfoo

Bạn sẽ xuất ra như sau:

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

<__main__.foo object at 0x321c290>

Bạn có thể thấy rằng 'điều' đã được chỉ định tham chiếu đến trường hợp 'myfoo' của lớp 'foo'. Phần này của tài liệu giải thích cách các đối số chức năng hoạt động nhiều hơn một chút.


1
lưu ý: bạn có thể nhận được cùng một loại lỗi nếu hàm def của bạn bao gồm self là tham số đầu tiên, và sau đó bạn vô tình gọi hàm cũng với self là tham số đầu tiên.
Christopher Hunter

48

Cảm ơn các bài viết hướng dẫn. Tôi chỉ muốn lưu ý rằng nếu bạn nhận được "TypeError: foodo () có nhiều giá trị cho đối số từ khóa 'điều'", thì cũng có thể bạn đang nhầm lẫn 'tự' là một tham số khi gọi hàm (có thể là do bạn đã sao chép dòng từ khai báo lớp - đó là lỗi phổ biến khi ai đó vội vàng).


7
Đó là những gì đã xảy ra với tôi, cảm ơn vì đã thêm vào câu trả lời này. Đây có thể là lỗi phổ biến hơn để thực hiện, đó là lý do tại sao bạn nhận được upvote của tôi.
ndrey 20/2/2015

Điều tương tự xảy ra khi quá tải một @classmethod, giải pháp được sử dụng super().function(...)thay vì <parentclass>.function(cls, ...).
ederag

30

Điều này có thể rõ ràng, nhưng nó có thể giúp một người chưa bao giờ nhìn thấy nó trước đây. Điều này cũng xảy ra đối với các hàm thông thường nếu bạn gán nhầm một tham số theo vị trí và rõ ràng theo tên.

>>> 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

chỉ cần thêm trang trí 'staticmethod' vào chức năng và vấn đề đã được khắc phục

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

Tôi chỉ nhận được lỗi này và giải pháp này đã giải quyết vấn đề của tôi. Nhưng bạn có thể giải thích làm thế nào hoặc tại sao trang trí này giải quyết vấn đề?
Ray

1
staticmethod dừng phương thức nhận tự làm đối số đầu tiên. Vì vậy, bây giờ, nếu bạn gọi myfoo.foodo(thing="something"), thing = "Something" sẽ được gán cho đối số đầu tiên, thay vì đối số ngầm.
danio

điều đó cũng có nghĩa là bạn không thể truy cập các biến lớp trong hàm, thường được truy cập thông quaself
drevicko

4

Tôi muốn thêm một câu trả lời:

Nó xảy ra khi bạn cố gắng truyền tham số vị trí với thứ tự vị trí sai cùng với đối số từ khóa trong chức năng gọi.

there is difference between parameter and argumentbạn có thể đọc chi tiết về đây Đối số và tham số trong python

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


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

vì chúng ta có ba tham số:

a là tham số vị trí

b = 1 là từ khóa và tham số mặc định

* args là tham số độ dài thay đổi

Vì vậy, trước tiên chúng ta gán một tham số theo vị trí, có nghĩa là chúng ta phải cung cấp giá trị cho đối số vị trí theo thứ tự vị trí của nó, ở đây là vấn đề thứ tự. nhưng chúng ta đang chuyển đối số 1 tại vị trí của hàm gọi và sau đó chúng ta cũng đang cung cấp giá trị cho a, coi là đối số từ khóa. bây giờ có hai giá trị:

một là giá trị vị trí: a = 1

thứ hai là giá trị từ khóa là a = 12

Giải pháp

Chúng ta phải thay đổi hello(1, 2, 3, 4,a=12)để hello(1, 2, 3, 4,12) bây giờ a sẽ chỉ nhận được một giá trị vị trí là 1 và b sẽ nhận giá trị 2 và phần còn lại của các giá trị sẽ nhận * args (tham số độ dài biến)

thông tin thêm

nếu chúng ta muốn rằng * args sẽ nhận được 2,3,4 và a nên lấy 1 và b sẽ nhận được 12

sau đó chúng ta có thể làm như thế này
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

Một cái gì đó nữa:

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

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

đầu ra:

1

(2, 1, 2, 8, 9)

1

{'c': 12}

đã được bao phủ bởi câu trả lời stackoverflow.com/a/31822875/12663 - ví dụ của bạn có cùng tham số (a) được gán theo vị trí và cũng rõ ràng theo tên.
danio

3

Lỗi này cũng có thể xảy ra nếu bạn chuyển một đối số từ khóa mà một trong các khóa tương tự (có cùng tên chuỗi) cho một đối số vị trí.

>>> 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'
>>> 

"lửa" đã được chấp nhận vào đối số 'thanh'. Tuy nhiên, có một đối số 'thanh' khác hiện diện trong kwargs.

Bạn sẽ phải xóa đối số từ khóa khỏi kwargs trước khi chuyển nó sang phương thức.


1

Ngoài ra, điều này có thể xảy ra trong Django nếu bạn đang sử dụng jquery ajax để url đảo ngược chức năng không chứa tham số 'request'

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


def myfunc(foo, bar):
    ...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.