** kwarg'ların amacı ve kullanımı nedir?


763

**kwargsPython ne için kullanılır ?

Senin bir yapabileceğini biliyorum objects.filterbir masada ve geçmek **kwargsargüman.  

Bunu zaman deltalarını belirtmek için de yapabilir miyim timedelta(hours = time1)?

Tam olarak nasıl çalışır? Sınıflar 'ambalajdan çıkarma' mıdır? Gibi a,b=1,2mi?


27
Bu soruyu benim gibi görürseniz, ayrıca bkz: * args ve ** kwargs?
sumid

3
Bir derece özlü açıklama burada : "Bir demet içinde * toplar bütün pozisyonel argümanlar", "** bir sözlükte tüm anahtar kelime argümanları toplar". Anahtar kelime toplar .
osa

24
Bilginize: kwargsaçılımı KeyWord ARGumentStuşları belirledik, yani argümanlar
Richard de Wit

Yanıtlar:


868

**kwargsİşlevlerinizin isteğe bağlı sayıda anahtar kelime bağımsız değişkeni almasına izin vermek için kullanabilirsiniz ("kwargs", "anahtar kelime bağımsız değişkenleri" anlamına gelir):

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

Ayrıca kullanabilirsiniz **kwargskelime argümanlardan bir sözlük oluşturmak ve işlevine ileterek işlevi çağrılırken sözdizimi:

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

Python Kılavuzu bazı güzel örneklerle birlikte nasıl çalıştığını iyi bir açıklama içerir.

<- Güncelleme ->

İteritems () yerine Python 3 kullanan kişiler için items () kullanın


1
@ yashas123 Hayır; boş bir şey üzerinde döngü yaparsanız, hiçbir şey olmaz, bu nedenle bir sonraki kod ne olursa olsun normal şekilde çalışır.
JG

330

Sözlükleri açma

** sözlükleri açar.

Bu

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

aynıdır

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

Parametreleri yapılandırmanız gerekiyorsa yararlıdır:

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)

Bir fonksiyonun paketleme parametreleri

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

Bu, işlevi şu şekilde kullanmanızı sağlar:

setstyle(color="red", bold=False)

13
kwarg sadece değişken bir isim değil mi? def func (** args) kullanabilirsiniz: ve wud çalışır?
Sriram

11
@Sriram: Doğru. Yıldız işaretleri önemlidir. kwargs , daha iyisi yoksa , sadece birinin verdiği isimdir. (Genellikle vardır.)
Georg Schölly

54
@Sriram: okunabilirlik uğruna kwarglara sadık kalmalısınız - diğer programcılar bunu takdir edecektir.
johndodo

12
** do unpack dictionaries.>> zihin üfleme / tabii! Bu biti açıklamak için +1.
Marc

13
Not: Python 3 .iteritems()olarak yeniden adlandırılmıştır .items().
fnkr

67

kwargs sadece parametrelere eklenen bir sözlüktür.

Bir sözlük anahtar, değer çiftleri içerebilir. Ve bunlar kwarglar. Tamam, işte böyle.

Ne için o kadar basit değil.

Örneğin (çok varsayımsal), işi yapmak için sadece diğer rutinleri çağıran bir arayüze sahipsiniz:

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

Şimdi yeni bir yöntem "sürücü" olsun:

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

Ama bir dakika, yeni bir parametre "araç" var - daha önce bilmiyordum. Şimdi bunu myDo işlevinin imzasına eklemelisiniz.

Burada kwargları oyuna atabilirsiniz - sadece imzaya kwargs eklersiniz:

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

Bu şekilde, aradığınız bazı yordamlar her değiştiğinde arayüz işlevinizin imzasını değiştirmeniz gerekmez.

Bu, kwargları yararlı bulabileceğiniz güzel bir örnektir.


46

İyi bir örneğin bazen uzun bir söylemden daha iyi olması temelinde, tüm python değişken argümanlarını (hem konumsal hem de adlandırılmış argümanlar) geçiren iki işlev yazacağım. Ne yaptığını kolayca görebilmelisiniz:

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)

Ve işte çıktı:

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

28

Motif: *argsve**kwargs bir işlev çağrısına geçirilmesi gereken bağımsız değişkenler için yer tutucu görevi görür

bir işlevi çağırmak için *argsve **kwargstuşlarını kullanma

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

Şimdi *argsyukarıda tanımlanan işlevi çağırmak için kullanacağız

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

sonuç:

arg1: iki
arg2: 3
arg3: 5


Şimdi, **kwargsaynı işlevi çağırmak için

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

sonuç:

arg1: 5
arg2: iki
arg3: 3

Alt satır: *argszeka yok, sadece geçirilen argümanları parametrelere (soldan sağa sırayla) enterpole ederken **kwargs, uygun değeri gerekli yere @ yerleştirerek akıllıca davranır


24
  • kwargsin **kwargssadece değişken adıdır. Çok iyi olabilir**anyVariableName
  • kwargs"anahtar kelime bağımsız değişkenleri" anlamına gelir. Ama onlar daha iyi "adlandırılmış argümanlar" olarak adlandırılması gerektiğini hissediyorum, çünkü bunlar sadece isimleri ile birlikte aktarılan argümanlar ("anahtar kelime argümanları" teriminde "anahtar kelime" kelimesi için herhangi bir anlam bulmuyorum. Programlama dili tarafından ayrılan ve dolayısıyla programcı tarafından değişken isimler için kullanılmayan kelimeler. Burada kwarg durumunda böyle bir şey olmaz.). Biz isim vermek Yani param1ve param2işleve geçirilen iki parametre değerlerine aşağıdaki gibi: func(param1="val1",param2="val2")yerine sadece verileri iletmenin en: func(val1,val2). Bu nedenle, bu parametrelerin herhangi bir sayısını belirtebileceğimiz için (isteğe bağlı olarak adlandırılmış bağımsız değişken sayısı) olarak adlandırılmaları gerektiğini hissediyorum (yani,funcfunc(**kwargs)

Öyleyse önce "adlandırılmış argümanları" ve sonra "rastgele adlandırılmış argüman sayısını" açıklayayım. kwargs .

Adlandırılmış bağımsız değişkenler

  • adlandırılmış argümanlar konumsal argümanları izlemelidir
  • adlandırılmış argümanların sırası önemli değil
  • Misal

    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'

Rasgele adlandırılmış bağımsız değişken sayısı kwargs

  • Fonksiyon parametrelerinin sırası:
    1. konumsal parametreler
    2. rasgele sayıda bağımsız değişkeni yakalayan resmi parametre (* ön ekine sahiptir)
    3. adlandırılmış resmi parametreler
    4. rasgele adlandırılmış parametre sayısını yakalayan resmi parametre (** ön ekine sahiptir)
  • Misal

    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

Özel argümanlar için tuple ve dict değişkenlerini iletme

Bitirmek için, geçebileceğimizi de not edeyim

  • tuple değişkeni olarak "rastgele sayıda argüman yakalayan resmi parametre" ve
  • dict değişkeni olarak "adlandırılmış parametrelerin keyfi sayısını yakalayan resmi parametre"

Böylece yukarıdaki çağrı aşağıdaki gibi yapılabilir:

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

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

Son olarak not *ve **yukarıdaki işlev çağrıları. Onları atlarsak, kötü sonuçlar alabiliriz.

*Tuple bağımsız değişkenlerinde atlama :

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

baskılar

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

Yukarıdaki demet ('custom param1', 'custom param2', 'custom param3')olduğu gibi yazdırılır.

Bağımsız dictdeğişkenleri atlamak :

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

verir

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg

3
keywordTerminolojinin, anahtar-değer çiftlerinin bir veritabanı olan bir dikte içinde geçtiğiniz gerçeğinden geldiğini hayal ediyorum .
crobar

"anahtar" değer çiftlerinde "anahtar" kelimesini mi kastediyorsunuz? Ayrıca genellikle veritabanı değil, sözlük denir. Ancak yine de "anahtar kelime" kelimesinin kullanımı için herhangi bir anlam bulamamaktadır.
Mahesha999

9

Ek olarak, kwargs işlevlerini çağırırken farklı kullanım yollarını da karıştırabilirsiniz:

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


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

test( a=1, **args )

bu çıktıyı verir:

1
2
3

** kwargs'ın son argüman olması gerektiğini unutmayın


5

kwargs, ad bağımsız değişkenlerini sözlük olarak (işlev için) veya adlandırılmış bağımsız değişken olarak (işlev) geçmek için sözdizimsel bir şekerdir


5

Kullanımı açıklamaya yarayan basit bir fonksiyon:

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

Verilen tüm argümanlar değil işlev tanımında belirtilen konacaktır argslistesi veya kwargsonlar anahtar kelime argümanlar olup olmadığına bağlı olarak, listede:

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

Bir işleve hiçbir zaman iletilmeyen bir anahtar kelime bağımsız değişkeni eklerseniz bir hata ortaya çıkar:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function

1

İşte size yardımcı olacağını umduğum bir örnek:

#! /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] )

Programı çalıştırdığınızda şunları elde edersiniz:

$ 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

Buradaki anahtar alma, çağrıdaki adlandırılmış argümanların değişken sayısının işlevdeki bir sözlüğe dönüşmesidir.


0

Bu, python paketini açma hakkında anlamanın basit bir örneğidir ,

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

0

Java'da, sınıfları aşırı yüklemek ve birden çok giriş parametresine izin vermek için yapıcılar kullanırsınız. Python'da, benzer davranışlar sağlamak için kwargs kullanabilirsiniz.

java örneği: https://beginnersbook.com/2013/05/constructor-overloading/

python örneği:

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.

sadece düşünmenin başka bir yolu.


0

Anahtar Kelime Bağımsız Değişkenleri genellikle Python'daki kwarglara kısaltılır . Gelen bilgisayar programlama ,

anahtar kelime bağımsız değişkenleri, bir bilgisayar dilinin, işlev çağrısındaki her bir parametrenin adını açıkça belirten işlev çağrıları desteğini ifade eder.

İki yıldız işaretinin ** kwargs parametre adından önce kullanılması, işleve kaç anahtar kelime bağımsız değişkeninin aktarılacağını bilmediği zamandır . Bu durumda, Keyfi / Joker Karakter Anahtar Kelime Bağımsız Değişkenleri olarak adlandırılır.

Buna bir örnek, Django'nun alıcı işlevleridir .

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

İşlevin, joker karakter anahtar argümanları (** kwargs) ile birlikte bir gönderen argümanı aldığına dikkat edin; tüm sinyal işleyiciler bu argümanları almalıdır. Tüm sinyaller anahtar kelime bağımsız değişkenleri gönderir ve bu anahtar kelime bağımsız değişkenlerini her zaman değiştirebilir. Request_finished durumunda , biz my_callback (gönderici) olarak ele sinyalimizi yazmak için cazip olabilir hayır demektir argümanlar, gönderme gibi belgeli.

Bu yanlış olur - aslında, bunu yaparsanız Django bir hata atar. Çünkü herhangi bir noktada argümanlar sinyale eklenebilir ve alıcınızın bu yeni argümanları işleyebilmesi gerekir.

Bunun kwargs olarak adlandırılması gerekmediğini , ancak ** olması gerektiğini unutmayın ( kwargs adı bir konvansiyondur).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.