lulus argumen ** kwargs ke fungsi lain dengan ** kwargs

152

Saya tidak mengerti contoh berikut, katakanlah saya memiliki fungsi-fungsi ini:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

Mengapa # 1 solusi yang tepat dan # 2 yang salah? **kwargspada dasarnya adalah dict, jadi Jika saya ingin meneruskan argumen ke openX saya pikir cara yang benar akan tanpa **dan hanya memberikan dict. Tapi python jelas tidak suka yang kedua dan mengatakan saya memberi 3 bukannya 2 argumen. Jadi apa alasan di balik ini?


sumber
5
Saya ingin tahu mengapa Anda menyebutnya **argsdalam kode. Ini mungkin nama yang terburuk karena orang akan bingung dengan*args
John La Rooy
1
Yah saya tidak pernah benar-benar menggunakan * args, jadi saya menggunakan ** args ^^, tapi saya bisa memodifikasinya.

Jawaban:

155

Dalam contoh kedua Anda memberikan 3 argumen: nama file, mode dan kamus ( kwargs). Tapi Python mengharapkan: 2 argumen formal ditambah argumen kata kunci.

Dengan mengawali kamus dengan '**' Anda membongkar kamus kwargske argumen kata kunci.

Kamus (tipe dict) adalah variabel tunggal yang berisi pasangan nilai kunci.

"Argumen kata kunci" adalah parameter metode nilai kunci.

Kamus apa pun dapat dengan membongkar argumen kata kunci dengan awalan dengan **selama panggilan fungsi.

gecco
sumber
5
sekarang saya mengerti. Saya pikir kata kunci dan dikt adalah hal yang sama.
13
"Kamus apa pun dapat diperluas ke kata kunci dengan mengawali dengan ** selama panggilan fungsi." <- itu keren
1
Lihat juga: Python docs pada parameter kata kunci dan daftar argumen unpacking
dinosaurus
8
Contoh kode aktual akan membuat jawaban ini jauh lebih jelas.
OrangeDog
12

The **sintaks memberitahu Python untuk argumen kata kunci collect ke dalam kamus. Ini save2meneruskannya sebagai argumen non-kata kunci (objek kamus). The openXtidak melihat argumen kata kunci sehingga **argstidak digunakan. Alih-alih mendapatkan argumen non-kata kunci ketiga (kamus). Untuk memperbaikinya ubah definisi openXfungsi.

def openX(filename, mode, kwargs):
    pass
Keith
sumber
Terima kasih, tetapi saya juga ingin menggunakan openX tanpa menyimpan, jadi saya harus tetap menggunakan kata kunci. Saya pikir kata kunci yang diturunkan pada dasarnya sama dengan mengirimkan dict, tapi saya tidak tahu sampai sekarang :)
@xMRW Mereka tidak bisa sama karena Anda bisa meneruskan kamus sebagai parameter ke fungsi apa pun juga. Nomor 1 Anda adalah yang benar.
Keith
8

Memperluas jawaban @gecco, berikut ini adalah contoh yang akan menunjukkan perbedaan:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Di sini Anda dapat melihat cara membongkar kamus berfungsi, dan mengapa mengirim kamus yang sebenarnya gagal

Reda Drissi
sumber
1

Karena kamus adalah nilai tunggal. Anda perlu menggunakan perluasan kata kunci jika Anda ingin meneruskannya sebagai grup argumen kata kunci.

Ignacio Vazquez-Abrams
sumber
maaf tapi apa itu "perluasan kata kunci"? maksud Anda saya harus menggunakan dict_var bukan ** args dan hanya menggunakan def func (argumen, dict_var = 0) ... func (1, {1: "a", 2: "b"})
1

Untuk # 2 args hanya akan menjadi parameter formal dengan nilai dict, tetapi bukan parameter jenis kata kunci.

Jika Anda ingin meneruskan parameter jenis kata kunci ke argumen kata kunci, Anda perlu menentukan ** sebelum kamus Anda, yang berarti argumen **

lihat ini untuk detail lebih lanjut tentang penggunaan ** kw

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/

Kit Ho
sumber
Jadi ada perbedaan besar antara ** kwargs dan dict?
terima kasih, saya selalu suka membaca lebih lanjut tentang topik yang saya tidak mengerti.