metode kelas menghasilkan "TypeError: ... mendapat beberapa nilai untuk argumen kata kunci ..."

129

Jika saya mendefinisikan metode kelas dengan argumen kata kunci sebagai berikut:

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

memanggil metode menghasilkan TypeError:

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

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

Apa yang sedang terjadi?

drevicko
sumber
2
Anda tidak akan pernah mendapatkan jawaban yang memuaskan mengapa eksplisit selflebih baik daripada implisit this.
nurettin

Jawaban:

164

Masalahnya adalah bahwa argumen pertama yang diteruskan ke metode kelas dengan python selalu merupakan salinan dari instance kelas di mana metode ini dipanggil, biasanya diberi label self. Jika kelas dinyatakan demikian:

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

berperilaku seperti yang diharapkan.

Penjelasan:

Tanpa selfsebagai parameter pertama, ketika myfoo.foodo(thing="something")dijalankan, foodometode ini dipanggil dengan argumen (myfoo, thing="something"). Contoh myfookemudian ditugaskan untuk thing(karena thingmerupakan parameter pertama menyatakan), tetapi python juga upaya untuk menetapkan "something"ke thing, maka Eksepsi.

Untuk menunjukkan, coba jalankan ini dengan kode asli:

myfoo.foodo("something")
print
print myfoo

Anda akan menghasilkan seperti:

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

<__main__.foo object at 0x321c290>

Anda dapat melihat bahwa 'benda' telah diberi referensi ke instance 'myfoo' dari kelas 'foo'. Bagian dokumen ini menjelaskan cara kerja argumen fungsi sedikit lebih.

drevicko
sumber
1
catatan: Anda bisa mendapatkan jenis kesalahan yang sama jika fungsi Anda def menyertakan diri sebagai parameter pertama, dan kemudian Anda secara tidak sengaja memanggil fungsi juga dengan diri sebagai parameter pertama.
Christopher Hunter
48

Terima kasih untuk posting instruktif. Saya hanya ingin mencatat bahwa jika Anda mendapatkan "TypeError: foodo () mendapat beberapa nilai untuk argumen kata kunci 'thing'", mungkin juga Anda keliru menyampaikan 'self' sebagai parameter saat memanggil fungsi (mungkin karena Anda menyalin garis dari deklarasi kelas - ini adalah kesalahan umum ketika seseorang sedang terburu-buru).

joe_doe
sumber
7
Itulah yang terjadi pada saya, terima kasih telah menambahkan jawaban ini. Ini mungkin kesalahan yang lebih umum untuk dilakukan, itulah sebabnya Anda mendapatkan jawaban saya.
rdrey
Hal yang sama terjadi ketika overloading @classmethod, solusinya adalah menggunakan super().function(...)alih-alih <parentclass>.function(cls, ...).
ederag
30

Ini mungkin jelas, tetapi mungkin membantu seseorang yang belum pernah melihatnya sebelumnya. Ini juga terjadi untuk fungsi reguler jika Anda secara keliru menetapkan parameter berdasarkan posisi dan secara eksplisit berdasarkan nama.

>>> 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'
woot
sumber
6

cukup tambahkan dekorator 'staticmethod' agar berfungsi dan masalah telah diperbaiki

class foo(object):
    @staticmethod
    def foodo(thing=None, thong='not underwear'):
        print thing if thing else "nothing" 
        print 'a thong is',thong
adi gunawan
sumber
Saya baru saja mendapatkan kesalahan ini dan solusi ini menyelesaikan masalah saya. Tetapi dapatkah Anda menguraikan bagaimana atau mengapa dekorator ini memecahkan masalah?
Ray
1
staticmethod menghentikan metode menerima diri sebagai argumen pertama. Jadi sekarang, jika Anda memanggil myfoo.foodo(thing="something"), thing = "sesuatu" akan ditugaskan ke argumen pertama, daripada argumen diri implisit.
danio
itu juga berarti bahwa Anda tidak dapat mengakses variabel kelas dalam fungsi, yang biasanya diakses melaluiself
drevicko
4

Saya ingin menambahkan satu jawaban lagi:

Itu terjadi ketika Anda mencoba untuk melewati parameter posisi dengan urutan posisi yang salah bersama dengan argumen kata kunci dalam fungsi panggilan.

there is difference between parameter and argumentAnda dapat membaca secara detail tentang di sini Argumen dan Parameter dalam python

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


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

karena kami memiliki tiga parameter:

a adalah parameter posisi

b = 1 adalah kata kunci dan parameter default

* args adalah parameter panjang variabel

jadi pertama-tama kita menetapkan parameter sebagai posisi, artinya kita harus memberikan nilai pada argumen posisi dalam urutan posisinya, di sini urutan penting. tapi kami melewati argumen 1 di tempat fungsi panggil dan kemudian kami juga memberikan nilai kepada, memperlakukan sebagai argumen kata kunci. sekarang a memiliki dua nilai:

satu adalah nilai posisi: a = 1

kedua adalah nilai kata kunci yang a = 12

Larutan

Kita harus berubah hello(1, 2, 3, 4,a=12)untuk hello(1, 2, 3, 4,12) jadi sekarang akan mendapatkan hanya satu nilai posisional yang 1 dan b akan mendapatkan nilai 2 dan beristirahat dari nilai-nilai akan mendapatkan * args (panjang variabel parameter)

informasi tambahan

jika kita menginginkan * args harus mendapatkan 2,3,4 dan a harus mendapatkan 1 dan b harus mendapatkan 12

maka kita bisa melakukan ini
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

Sesuatu yang lebih :

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

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

keluaran:

1

(2, 1, 2, 8, 9)

1

{'c': 12}
Aaditya Ura
sumber
yang sudah dicakup oleh jawaban stackoverflow.com/a/31822875/12663 - contoh Anda memiliki parameter yang sama (a) ditentukan oleh posisi dan juga secara eksplisit berdasarkan nama.
danio
3

Kesalahan ini juga dapat terjadi jika Anda memberikan argumen kata kunci yang salah satu kuncinya serupa (memiliki nama string yang sama) dengan argumen posisi.

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

"api" telah diterima dalam argumen 'bilah'. Namun ada argumen 'bar' lain yang hadir dalam kwargs.

Anda harus menghapus argumen kata kunci dari kwargs sebelum meneruskannya ke metode.

buka kunci saya
sumber
1

Juga ini bisa terjadi di Django jika Anda menggunakan jquery ajax untuk url yang membalikkan ke fungsi yang tidak mengandung parameter 'permintaan'

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


def myfunc(foo, bar):
    ...
lukeaus
sumber