Apa tujuan dan penggunaan ** kwargs?

763

Apa kegunaan untuk **kwargsdi Python?

Saya tahu Anda bisa melakukan objects.filterdi atas meja dan menyampaikan **kwargsargumen.  

Bisakah saya juga melakukan ini untuk menentukan delta waktu yaitu timedelta(hours = time1)?

Bagaimana tepatnya cara kerjanya? Apakah ini kelas 'membongkar'? Suka a,b=1,2?

Federer
sumber
27
Jika Anda menabrak pertanyaan ini sebagai saya, lihat juga: * args dan ** kwargs?
sumid
3
Penjelasan yang sangat singkat di sini : "* mengumpulkan semua argumen posisi dalam sebuah tuple", "** mengumpulkan semua argumen kata kunci dalam kamus". Kata kuncinya adalah mengumpulkan .
Osa
24
Just FYI: kwargssingkatan KeyWord ARGumentS, yaitu argumen yang telah menetapkan kunci
Richard de Wit

Jawaban:

868

Anda dapat menggunakan **kwargsuntuk membiarkan fungsi Anda mengambil sejumlah argumen kata kunci sewenang-wenang ("kwargs" berarti "argumen kata kunci"):

>>> def print_keyword_args(**kwargs):
...     # kwargs is a dict of the keyword args passed to the function
...     for key, value in kwargs.iteritems():
...         print "%s = %s" % (key, value)
... 
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe

Anda juga dapat menggunakan **kwargssintaks saat memanggil fungsi dengan membuat kamus argumen kata kunci dan meneruskannya ke fungsi Anda:

>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith

The Python Tutorial berisi penjelasan yang baik dari cara kerjanya, bersama dengan beberapa contoh yang bagus.

<--Perbaruan-->

Untuk orang yang menggunakan Python 3, alih-alih iteritems (), gunakan item ()

Pär Wieslander
sumber
1
@ yashas123 Tidak; jika Anda mengulangi sesuatu yang kosong, tidak ada yang terjadi, jadi kode apa pun yang muncul selanjutnya berjalan secara normal.
JG
330

Membongkar kamus

** membongkar kamus.

Ini

func(a=1, b=2, c=3)

sama dengan

args = {'a': 1, 'b': 2, 'c':3}
func(**args)

Ini berguna jika Anda harus membuat parameter:

args = {'name': person.name}
if hasattr(person, "address"):
    args["address"] = person.address
func(**args)  # either expanded to func(name=person.name) or
              #                    func(name=person.name, address=person.address)

Parameter pengepakan suatu fungsi

def setstyle(**styles):
    for key, value in styles.iteritems():      # styles is a regular dictionary
        setattr(someobject, key, value)

Ini memungkinkan Anda menggunakan fungsi seperti ini:

setstyle(color="red", bold=False)
Georg Schölly
sumber
13
apakah kwarg hanyalah nama variabel, bukan? jadi saya bisa menggunakan def func (** args): dan itu wud bekerja?
Sriram
11
@Riram: Benar. Tanda bintang itu penting. kwargs hanya nama yang diberikannya jika tidak ada yang lebih baik. (Biasanya ada.)
Georg Schölly
54
@Riram: demi keterbacaan Anda harus tetap menggunakan kwargs - programmer lain akan menghargainya.
johndodo
12
** do unpack dictionaries.>> Pikiran meledak / tentu saja! +1 untuk menjelaskan bagian itu.
Marc
13
Catatan: .iteritems()telah diubah namanya menjadi .items()Python 3.
fnkr
67

kwargs hanyalah kamus yang ditambahkan ke parameter.

Kamus dapat berisi kunci, pasangan nilai. Dan itu adalah kwarg. Ok begini caranya.

Untuk apa tidak begitu sederhana.

Misalnya (sangat hipotetis) Anda memiliki antarmuka yang hanya memanggil rutinitas lain untuk melakukan pekerjaan:

def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

Sekarang Anda mendapatkan metode baru "drive":

elif what == 'drive':
   doDrive(where, why, vehicle)

Tapi tunggu dulu, ada parameter baru "kendaraan" - Anda tidak tahu itu sebelumnya. Sekarang Anda harus menambahkannya ke tanda tangan dari fungsi myDo.

Di sini Anda dapat melempar kwarg ke dalam permainan - Anda hanya menambahkan kwarg ke tanda tangan:

def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

Dengan cara ini Anda tidak perlu mengubah tanda tangan dari fungsi antarmuka Anda setiap kali beberapa rutinitas yang Anda panggil mungkin berubah.

Ini hanyalah satu contoh bagus yang menurut Anda bermanfaat bagi kwarg.

Juergen
sumber
46

Atas dasar bahwa sampel yang baik kadang-kadang lebih baik daripada wacana panjang saya akan menulis dua fungsi menggunakan semua fasilitas variabel lewat argumen python (baik argumen posisional dan bernama). Anda harus dapat dengan mudah melihat apa yang dilakukannya sendiri:

def f(a = 0, *args, **kwargs):
    print("Received by f(a, *args, **kwargs)")
    print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
    print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
    g(10, 11, 12, *args, d = 13, e = 14, **kwargs)

def g(f, g = 0, *args, **kwargs):
    print("Received by g(f, g = 0, *args, **kwargs)")
    print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))

print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)

Dan inilah hasilnya:

Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs) 
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})
Kriss
sumber
28

Motif: *argsdan **kwargsberfungsi sebagai pengganti untuk argumen yang perlu diteruskan ke pemanggilan fungsi

menggunakan *argsdan **kwargsmemanggil suatu fungsi

def args_kwargs_test(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

Sekarang kita akan gunakan *argsuntuk memanggil fungsi yang didefinisikan di atas

#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)  
>>> args_kwargs_test(*args)

hasil:

arg1: two
arg2: 3
arg3: 5


Sekarang, gunakan **kwargsuntuk memanggil fungsi yang sama

#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)

hasil:

arg1: 5
arg2: two
arg3: 3

Bottomline: *argstidak memiliki kecerdasan, itu hanya menginterpolasi argumen yang dilewatkan ke parameter (dalam urutan kiri-ke-kanan) sementara **kwargsberperilaku cerdas dengan menempatkan nilai yang sesuai @ tempat yang diperlukan

kmario23
sumber
24
  • kwargsdi **kwargshanya nama variabel. Anda dapat melakukannya dengan sangat baik**anyVariableName
  • kwargssingkatan dari "argumen kata kunci". Tetapi saya merasa mereka lebih baik disebut sebagai "argumen yang dinamai", karena ini hanyalah argumen yang diberikan bersama dengan nama (saya tidak menemukan arti kata "kata kunci" dalam istilah "argumen kata kunci". Saya kira "kata kunci" biasanya berarti kata-kata dicadangkan oleh bahasa pemrograman dan karenanya tidak dapat digunakan oleh programmer untuk nama-nama variabel. Tidak ada hal seperti itu terjadi di sini dalam kasus kwargs.). Jadi kita memberikan nama param1dan param2untuk dua nilai parameter dilewatkan ke fungsi sebagai berikut: func(param1="val1",param2="val2"), bukan lewat hanya nilai: func(val1,val2). Jadi, saya merasa mereka harus secara tepat disebut "jumlah arbitrase dari argumen yang dinamai" karena kita dapat menentukan sejumlah parameter ini (yaitu,funcfunc(**kwargs)

Jadi dikatakan bahwa izinkan saya menjelaskan "argumen bernama" pertama dan kemudian "sejumlah argumen bernama" kwargs.

Argumen yang dinamai

  • arg yang dinamai harus mengikuti argumen posisi
  • Urutan nama args tidak penting
  • Contoh

    def function1(param1,param2="arg2",param3="arg3"):
        print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
    
    function1(1)                      #1 arg2 arg3   #1 positional arg
    function1(param1=1)               #1 arg2 arg3   #1 named arg
    function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
    function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
    function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
    function1(1, param3=3, param2=2)  #1 2 3         #
    
    #function1()                      #invalid: required argument missing
    #function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
    #function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
    #function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'

Sejumlah argumen bernama yang sewenang-wenang kwargs

  • Urutan parameter fungsi:
    1. parameter posisi
    2. parameter formal yang menangkap jumlah argumen yang berubah-ubah (diawali dengan *)
    3. bernama parameter formal
    4. parameter formal yang menangkap jumlah parameter yang ditentukan secara arbitrer (diawali dengan **)
  • Contoh

    def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
        print("param1: "+ param1)
        print("param2: "+ param2)
        print("param3: "+ param3)
        print("custom tuple params","-"*10)
        for p in tupleParams:
            print(str(p) + ",")
        print("custom named params","-"*10)
        for k,v in dictionaryParams.items():
            print(str(k)+":"+str(v))
    
    function2("arg1",
              "custom param1",
              "custom param2",
              "custom param3",
              param3="arg3",
              param2="arg2", 
              customNamedParam1 = "val1",
              customNamedParam2 = "val2"
              )
    
    # Output
    #
    #param1: arg1
    #param2: arg2
    #param3: arg3
    #custom tuple params ----------
    #custom param1,
    #custom param2,
    #custom param3,
    #custom named params ----------
    #customNamedParam2:val2
    #customNamedParam1:val1

Melewati variabel tuple dan dict untuk argumen khusus

Untuk menyelesaikannya, izinkan saya juga mencatat bahwa kita dapat lulus

  • msgstr "parameter formal yang menangkap jumlah argumen sembarang" sebagai variabel tuple dan
  • + msgstr "parameter formal yang menangkap sejumlah parameter bernama" sebagai variabel dict

Dengan demikian panggilan di atas yang sama dapat dilakukan sebagai berikut:

tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}

function2("arg1",
      *tupleCustomArgs,    #note *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs     #note **
      )

Akhirnya perhatikan *dan **dalam panggilan fungsi di atas. Jika kita menghilangkannya, kita mungkin mendapatkan hasil yang buruk.

Menghilangkan *tuple args:

function2("arg1",
      tupleCustomArgs,   #omitting *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs
      )

cetakan

param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1

Di atas tuple ('custom param1', 'custom param2', 'custom param3')dicetak apa adanya.

Menghilangkan dictargumen:

function2("arg1",
      *tupleCustomArgs,   
      param3="arg3",
      param2="arg2", 
      dictCustomNamedArgs   #omitting **
      )

memberi

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
Mahesha999
sumber
3
Saya akan membayangkan keywordterminologi berasal dari fakta Anda melewati dict yang merupakan basis data pasangan kunci-nilai.
crobar
maksud Anda kata "kunci" di "kunci" - nilai pasangan? Juga tidak biasa disebut basis data, tetapi kamus. Tetapi masih belum dapat menemukan signifikansi untuk penggunaan kata "kata kunci".
Mahesha999
9

Sebagai tambahan, Anda juga dapat mencampur berbagai cara penggunaan saat memanggil fungsi kwargs:

def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


args = { 'b': 2, 'c': 3}

test( a=1, **args )

memberikan hasil ini:

1
2
3

Perhatikan bahwa ** kwarg harus menjadi argumen terakhir

philipp
sumber
5

kwargs adalah gula sintaksis untuk meneruskan argumen nama sebagai kamus (untuk fungsi), atau kamus sebagai argumen bernama (untuk fungsi)


sumber
5

Berikut adalah fungsi sederhana yang berfungsi untuk menjelaskan penggunaan:

def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

Argumen apa pun yang tidak ditentukan dalam definisi fungsi akan dimasukkan ke dalam argsdaftar, atau kwargsdaftar, tergantung pada apakah itu argumen kata kunci atau tidak:

>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

Jika Anda menambahkan argumen kata kunci yang tidak pernah diteruskan ke suatu fungsi, kesalahan akan dimunculkan:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
tidak ada apa-apa101
sumber
1

Berikut adalah contoh yang saya harap sangat membantu:

#! /usr/bin/env python
#
def g( **kwargs) :
  print ( "In g ready to print kwargs" )
  print kwargs
  print ( "in g, calling f")
  f ( **kwargs )
  print ( "In g, after returning from f")

def f( **kwargs ) :
  print ( "in f, printing kwargs")
  print ( kwargs )
  print ( "In f, after printing kwargs")


g( a="red", b=5, c="Nassau")

g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )

Saat Anda menjalankan program, Anda mendapatkan:

$ python kwargs_demo.py 
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f

Kuncinya mengambil di sini adalah bahwa jumlah variabel argumen bernama dalam panggilan diterjemahkan ke dalam kamus dalam fungsi.

pengguna1928764
sumber
0

Ini adalah contoh sederhana untuk memahami tentang membongkar python ,

>>> def f(*args, **kwargs):
...    print 'args', args, 'kwargs', kwargs

eg1:

>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary
Mohideen bin Mohammed
sumber
0

Di Jawa, Anda menggunakan konstruktor untuk membebani kelas dan memungkinkan untuk beberapa parameter input. Dengan python, Anda bisa menggunakan kwargs untuk memberikan perilaku serupa.

contoh java: https://beginnersbook.com/2013/05/constructor-overloading/

contoh python:

class Robot():
    # name is an arg and color is a kwarg
    def __init__(self,name, color='red'):
        self.name = name
        self.color = color

red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')

print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))

>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.

hanya cara lain untuk memikirkannya.

Aidan Melen
sumber
0

Argumen kata kunci sering disingkat menjadi kwargs dengan Python. Dalam pemrograman komputer ,

argumen kata kunci merujuk pada dukungan bahasa komputer untuk panggilan fungsi yang dengan jelas menyatakan nama setiap parameter dalam panggilan fungsi.

Penggunaan dua tanda bintang sebelum nama parameter, ** kwargs , adalah ketika seseorang tidak tahu berapa banyak argumen kata kunci yang akan diteruskan ke dalam fungsi. Ketika itu terjadi, itu disebut Argumen Kata Kunci Sewenang-wenang / Wildcard.

Salah satu contohnya adalah fungsi penerima Django .

def my_callback(sender, **kwargs):
    print("Request finished!")

Perhatikan bahwa fungsi tersebut mengambil argumen pengirim, bersama dengan argumen kata kunci wildcard (** kwargs); semua penangan sinyal harus mengambil argumen ini. Semua sinyal mengirim argumen kata kunci, dan dapat mengubah argumen kata kunci tersebut kapan saja. Dalam hal request_finished , ini didokumentasikan sebagai pengiriman tanpa argumen, yang berarti kita mungkin tergoda untuk menulis penanganan sinyal kita sebagai my_callback (pengirim).

Ini akan salah - pada kenyataannya, Django akan membuat kesalahan jika Anda melakukannya. Itu karena pada titik mana pun argumen bisa ditambahkan ke sinyal dan penerima Anda harus dapat menangani argumen baru itu.

Perhatikan bahwa itu tidak harus disebut kwarg , tetapi harus memiliki ** (nama kwarg adalah konvensi).

Tiago Martins Peres 李大仁
sumber