** (çift yıldız / yıldız) ve * (yıldız / yıldız) parametreler için ne yapar?


2350

Aşağıdaki yöntem tanımlarda ne yok *ve **yapmak param2?

def foo(param1, *param2):
def bar(param1, **param2):



Ayrıca çıplak bir yıldız işareti için stackoverflow.com/questions/14301967/…
adresine

24
Bu soru çok popüler bir yinelenen hedef, ancak ne yazık ki sıklıkla yanlış kullanılıyor. Bu sorunun varargs ( def func(*args)) ile işlevleri tanımlamayı istediğini unutmayın . İşlev çağrılarında ( func(*[1,2])) ne anlama geldiğini soran bir soru için buraya bakın . Argüman listelerinin nasıl açılacağını soran bir soru için buraya bakın . Değişmez değerlerdeki ( ) ne *anlama geldiğini soran bir soru için buraya bakın . [*[1, 2]]
Aran-Fey

İşlev tanımı ve işlev çağrısında kullanımı hakkında bilgi edinebilirsiniz: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Yanıtlar:


2237

*argsVe **kwargsbölümünde açıklandığı gibi işlevlere bağımsız değişken keyfi sayıda izin vermek için ortak bir deyim olan daha fazla fonksiyon tanımlama konusunda Python belgelerinde.

*argsSen iyi işlev parametreleri verecek bir demet olarak :

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

**kwargs , resmi bir parametreye sözlük olarak karşılık gelenler dışındaki tüm anahtar kelime bağımsız değişkenlerini verir .

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name='one', age=27)
# age 27
# name one

Her iki deyim, bir dizi sabit ve bazı değişken bağımsız değişkenlere izin vermek için normal bağımsız değişkenlerle karıştırılabilir:

def foo(kind, *args, **kwargs):
   pass

Bunu başka bir şekilde kullanmak da mümkündür:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

*lDeyimin bir başka kullanımı da argüman listelerini açmaktır bir işlevi çağırırken .

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

Python 3'te *lbir ödevin sol tarafında kullanılabilir ( Genişletilmiş Tekrarlanabilir Paket Açma) ) kullanmak mümkündür, ancak bu bağlamda bir demet yerine bir liste verir:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Ayrıca Python 3 yeni semantik ekler (bkz. PEP 3102 ):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Bu işlev yalnızca 3 konum bağımsız değişkenini kabul eder ve bundan sonraki her şey *yalnızca anahtar kelime bağımsız değişkenleri olarak geçirilebilir.


9
[6] çıkışı ters sıradadır. adı bir yaş 27
thanos.a

54
@ thanos.a Anahtar kelime argümanını geçmek için semantik olarak kullanılan Python dikteleri isteğe bağlı olarak sıralanır. Ancak, Python 3.6'da, anahtar kelime bağımsız değişkenlerinin ekleme sırasını hatırlaması garanti edilir. "İçindeki öğelerin **kwargssırası, anahtar kelime bağımsız değişkenlerinin işleve iletildiği sıraya karşılık geliyor." - docs.python.org/3/whatsnew/3.6.html Aslında, CPython 3.6'daki tüm dikteler ekleme talimatını bir uygulama detayı olarak hatırlayacaktır, bu Python 3.7'de standart hale gelir.
Aaron Hall

13
Çok hassas, temiz ve kolay anlaşılır. Bunun bir "paketten çıkarma operatörü" olduğunu kaydettiğiniz için teşekkür ederiz, böylece
C.'de

PEP 3102 ile son fonksiyon nasıl test edilir? Ben func (1,2,3, name = "me", yaş = 10) ile çağırıyorum ve istisna atıyor:got an unexpected keyword argument 'name'
Kok How Teh

@KokHowTeh İşlevde oldukları gibi adlandırılan kwargları geçirmeniz gerekir: func (1, 2, 3, kwarg1 = 'me', kwarg2 = 10)
John Aaron

622

Kullanabileceğinizi *ve **işlevleri çağırırken de dikkat etmeniz gerekir . Bu, bir liste / grup veya sözlük kullanarak doğrudan bir işleve birden çok argüman iletmenizi sağlayan bir kısayoldur. Örneğin, aşağıdaki işleve sahipseniz:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Şöyle şeyler yapabilirsiniz:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Not: içindeki tuşlar mydicttam olarak fonksiyon parametreleri gibi adlandırılmalıdır foo. Aksi takdirde TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'

175

Tekli *, herhangi bir sayıda ekstra konum bağımsız değişkeni olabileceği anlamına gelir. foo()gibi çağrılabilirfoo(1,2,3,4,5) . Foo () gövdesinde param2 2-5 içeren bir dizidir.

İkili **, herhangi bir sayıda ekstra adlandırılmış parametre olabileceği anlamına gelir. bar()gibi çağrılabilir bar(1, a=2, b=3). Bar () gövdesinde param2, {'a': 2, 'b': 3} içeren bir sözlüktür

Aşağıdaki kodla:

def foo(param1, *param2):
    print(param1)
    print(param2)

def bar(param1, **param2):
    print(param1)
    print(param2)

foo(1,2,3,4,5)
bar(1,a=2,b=3)

çıktı

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}

5
foobar(param1, *param2, **param3)Bu cevabın eksiksiz olması için belki de ek bir örnek gereklidir.
Aniket Thakur

1
@AniketThakur kalan kısmı buraya ekledi .
Raj

148

**(Çift yıldız) ve *(yıldız) parametreler için ne yapar

İşlevlerin kabul edilmesini ve kullanıcıların herhangi bir sayıda argüman, pozisyon ( *) ve anahtar kelime ( **) iletmesini sağlarlar .

Fonksiyonların Tanımlanması

*argsadlı bir tuple grubuna atanacak herhangi bir sayıda isteğe bağlı konumsal argümana (parametre) izin verir args.

**kwargsadında bir dikte olacak herhangi bir sayıda isteğe bağlı anahtar kelime argümanı (parametresi) sağlar kwargs.

Herhangi bir uygun ismi seçebilirsiniz (ve seçmelisiniz), ancak amaç argümanların spesifik olmayan anlambilimsel olması argsve kwargsstandart isimler olmasıdır.

Genişletme, İstenen sayıda argümanın iletilmesi

Ayrıca kullanabilir *argsve **kwargssırasıyla listeleri (veya herhangi iterable) ve dicts (veya herhangi bir haritalama) den parametrelerinde geçmesine.

Parametreleri alan fonksiyonun genişletildiklerini bilmek zorunda değildir.

Örneğin, Python 2'nin xrange'i açıkça beklemez *args, ancak bağımsız değişken olarak 3 tamsayıyı aldığından:

>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)

Başka bir örnek olarak, dict genişlemesini şu alanlarda kullanabiliriz str.format:

>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'

Python 3'teki yenilikler: Yalnızca anahtar kelime bağımsız değişkenleriyle işlevleri tanımlama

Sen olabilir ancak argümanları anahtar kelime sonra *argsörneğin burada, - kwarg2bir anahtar kelime argüman olarak verilmelidir - değil pozisyonel:

def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs

Kullanımı:

>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})

Ayrıca, *sınırsız konumsal argümanlara izin vermeden, yalnızca anahtar kelime argümanlarının takip ettiğini belirtmek için tek başına kullanılabilir.

def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs

Burada, kwarg2yine açıkça adlandırılmış bir anahtar kelime argümanı olmalıdır:

>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})

Ve artık sınırsız konumsal argümanı kabul edemeyiz çünkü elimizde *args*:

>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given

Yine, daha basit olarak, burada kwargkonumsal olarak değil, isimle verilmemizi istiyoruz:

def bar(*, kwarg=None): 
    return kwarg

Bu örnekte, kwargkonumsal olarak geçmeye çalışırsak bir hata alırız:

>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given

kwargParametreyi bir anahtar kelime argümanı olarak açıkça geçmeliyiz.

>>> bar(kwarg='kwarg')
'kwarg'

Python 2 uyumlu demolar

*args(tipik olarak "yıldız-args" olarak adlandırılır) ve **kwargs(yıldızlar "kwargs" diyerek ima edilebilir, ancak "çift yıldız kwargs" ile açık olun), Python'un *ve **gösterimini kullanmak için yaygın olarak kullanılan deyimleridir . Bu belirli değişken adları gerekli değildir (örn kullanabilirdin *foosve**bars ), ancak konvansiyondan ayrılma muhtemelen Python kodlayıcılarınızı öfkelendirecektir.

Bunları genellikle işlevimizin ne alacağını veya kaç argümanı alacağımızı bilmediğimizde ve bazen her değişkeni ayrı olarak adlandırdığımızda bile çok dağınık ve gereksiz olur (ancak bu genellikle açık olan bir durumdur) örtükten daha iyi).

örnek 1

Aşağıdaki işlev, bunların nasıl kullanılabileceğini açıklar ve davranışı gösterir. Belirtilen bargümanın, aşağıdaki ikinci konumsal argüman tarafından kullanılacağını unutmayın :

def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and any number of unknown positional arguments and keyword arguments after
    '''
    print('a is a required argument, and its value is {0}'.format(a))
    print('b not required, its default value is 10, actual value: {0}'.format(b))
    # we can inspect the unknown arguments we were passed:
    #  - args:
    print('args is of type {0} and length {1}'.format(type(args), len(args)))
    for arg in args:
        print('unknown arg: {0}'.format(arg))
    #  - kwargs:
    print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                        len(kwargs)))
    for kw, arg in kwargs.items():
        print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
    # But we don't have to know anything about them 
    # to pass them to other functions.
    print('Args or kwargs can be passed without knowing what they are.')
    # max can take two or more positional args: max(a, b, c...)
    print('e.g. max(a, b, *args) \n{0}'.format(
      max(a, b, *args))) 
    kweg = 'dict({0})'.format( # named args same as unknown kwargs
      ', '.join('{k}={v}'.format(k=k, v=v) 
                             for k, v in sorted(kwargs.items())))
    print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
      dict(**kwargs), kweg=kweg))

İle Biz işlevin imza için online yardım kontrol edebilirsiniz help(foo)söyler, hangi

foo(a, b=10, *args, **kwargs)

Bu işlevi foo(1, 2, 3, 4, e=5, f=6, g=7)

hangi baskılar:

a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}

ÖRNEK 2

Ayrıca, sadece sağladığımız başka bir işlev kullanarak da çağırabiliriz a:

def bar(a):
    b, c, d, e, f = 2, 3, 4, 5, 6
    # dumping every local variable into foo as a keyword argument 
    # by expanding the locals dict:
    foo(**locals()) 

bar(100) baskılar:

a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}

Örnek 3: Dekoratörlerde pratik kullanım

Tamam, belki de programı henüz görmüyoruz. Bu nedenle, farklılaştırma kodundan önce ve / veya sonra yedek kod içeren çeşitli işlevleriniz olduğunu düşünün. Aşağıdaki adlandırılmış işlevler, açıklama amacıyla yalnızca sözde koddur.

def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

def bar(a, b, c=None, d=0, e=100, f=None):
    preprocess()
    differentiating_process_bar(a,b,c,d,e,f)
    postprocess()

def baz(a, b, c, d, e, f):
    ... and so on

Bunu farklı bir şekilde ele alabiliriz, ancak artıklığı bir dekoratörle kesinlikle çıkarabiliriz ve bu nedenle aşağıdaki örneğimiz nasıl *argsve **kwargsçok yararlı olabileceğini göstermektedir :

def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper

Ve artık, sarılı her işlev, fazlalığı hesaba kattığımız için çok daha özlü bir şekilde yazılabilir:

@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)

Ve yapmamıza izin veren *argsve **kwargskodumuzu hesaba katarak, kod satırlarını azaltıyor, okunabilirliği ve sürdürülebilirliği geliştiriyoruz ve programımızdaki mantık için tek kanonik konumlara sahibiz. Bu yapının herhangi bir bölümünü değiştirmemiz gerekiyorsa, her değişikliği yapabileceğimiz bir yerimiz var.


48

Önce konumsal ve anahtar kelime argümanlarının ne olduğunu anlayalım. Aşağıda, Konumsal bağımsız değişkenlere sahip işlev tanımına bir örnek verilmiştir .

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

Bu, konumsal argümanları olan bir fonksiyon tanımıdır. Anahtar kelime / adlandırılmış bağımsız değişkenlerle de arayabilirsiniz:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3

Şimdi anahtar kelime argümanlarıyla bir işlev tanımı örneği inceleyelim :

def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------

Bu işlevi konum bağımsız değişkenleriyle de çağırabilirsiniz:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

Bu yüzden şimdi pozisyon tanımlarının yanı sıra anahtar kelime argümanları ile fonksiyon tanımlarını biliyoruz.

Şimdi '*' operatörünü ve '**' operatörünü inceleyelim.

Bu operatörlerin 2 alanda kullanılabileceğini lütfen unutmayın:

a) fonksiyon çağrısı

b) fonksiyon tanımı

İşlev çağrısında '*' operatörü ve '**' operatörünün kullanımı .

Doğrudan bir örneğe bakalım ve tartışalım.

def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
    print(a+b)

my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}

# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 

# output is 3 in all three calls to sum function.

Hatırla

bir işlev çağrısında '*' veya '**' operatörü kullanıldığında -

'*' operatörü liste veya grup gibi veri yapısını fonksiyon tanımının gerektirdiği argümanlara açar.

'**' operatörü, sözlük tanımını işlev tanımının gerektirdiği argümanlara açar.

Şimdi fonksiyon tanımında '*' operatör kullanımını inceleyelim . Misal:

def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10

Fonksiyon tanımında '*' operatörü alınan argümanları bir demet halinde paketler.

Şimdi fonksiyon tanımında kullanılan '**' örneğini görelim:

def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum

İşlev tanımında '**' operatörü, alınan argümanları bir sözlüğe paketler.

Hatırla:

Bir fonksiyonda '*' paketinden çıkar fonksiyon tanım gereği alınacak pozisyonel veya anahtar kelime argümanları içine tuple veya listenin veri yapısını.

Bir de fonksiyonu çağırmak '**' paketten çıkarır fonksiyon tanım gereği alınacak pozisyonel veya anahtar kelime argümanları içine sözlüğü veri yapısını.

Bir olarak işlev tanımında '*' paketleri bir başlığın içine konum hatası.

Bir de işlev tanımı '**' packs bir sözlüğüne kelime argümanlar.


Gerçekten temiz, adım adım ve takip edilmesi kolay bir açıklama!
Aleksandar

teşekkürler Upvotes geliyor tutun. [Ayrıca benden daha fazla not almak için twitter'da mrtechmaker'deyim]
Karan Ahuja

32

Bu tablo kullanmak için kullanışlı *ve **fonksiyon içinde inşaat ve fonksiyon çağrısı :

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

Bu gerçekten Lorin Hochstein'ın cevabını özetlemeye hizmet ediyor ama yardımcı buluyorum.

İlgili olarak: Python 3'te yıldız / uyarıcı operatörlerinin kullanımları genişletildi


22

*ve **işlev argümanı listesinde özel kullanımları vardır. * argümanın bir liste **olduğunu ve argümanın bir sözlük olduğunu ima eder. Bu, işlevlerin isteğe bağlı sayıda bağımsız değişken almasını sağlar


17

Örneklerle öğrenenler için!

  1. Amacı, * size bir liste olarak sağlanan rasgele sayıda argüman alabilen bir işlev tanımlama yeteneği vermektir (örn. f(*myList)).
  2. Amacı, **size bir sözlük (ör. f(**{'x' : 1, 'y' : 2})) Sağlayarak bir işlevin bağımsız değişkenlerini besleme olanağı vermektir .

İki normal değişkenleri alır bir işlevi tanımlayarak bize bu göstereyim x, yve daha argümanları kabul edebilir myArgsve hatta daha argümanları kabul edebilir myKW. Daha sonra, ykullanarak nasıl besleneceğinizi göstereceğiz myArgDict.

def f(x, y, *myArgs, **myKW):
    print("# x      = {}".format(x))
    print("# y      = {}".format(y))
    print("# myArgs = {}".format(myArgs))
    print("# myKW   = {}".format(myKW))
    print("# ----------------------------------------------------------------------")

# Define a list for demonstration purposes
myList    = ["Left", "Right", "Up", "Down"]
# Define a dictionary for demonstration purposes
myDict    = {"Wubba": "lubba", "Dub": "dub"}
# Define a dictionary to feed y
myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}

# The 1st elem of myList feeds y
f("myEx", *myList, **myDict)
# x      = myEx
# y      = Left
# myArgs = ('Right', 'Up', 'Down')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# y is matched and fed first
# The rest of myArgDict becomes additional arguments feeding myKW
f("myEx", **myArgDict)
# x      = myEx
# y      = Why?
# myArgs = ()
# myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
# ----------------------------------------------------------------------

# The rest of myArgDict becomes additional arguments feeding myArgs
f("myEx", *myArgDict)
# x      = myEx
# y      = y
# myArgs = ('y0', 'q')
# myKW   = {}
# ----------------------------------------------------------------------

# Feed extra arguments manually and append even more from my list
f("myEx", 4, 42, 420, *myList, *myDict, **myDict)
# x      = myEx
# y      = 4
# myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# Without the stars, the entire provided list and dict become x, and y:
f(myList, myDict)
# x      = ['Left', 'Right', 'Up', 'Down']
# y      = {'Wubba': 'lubba', 'Dub': 'dub'}
# myArgs = ()
# myKW   = {}
# ----------------------------------------------------------------------

Uyarılar

  1. ** yalnızca sözlükler için ayrılmıştır.
  2. İsteğe bağlı olmayan bağımsız değişken ataması önce gerçekleşir.
  3. İsteğe bağlı olmayan bir bağımsız değişkeni iki kez kullanamazsınız.
  4. Mümkünse , her zaman **sonra gelmelidir *.

14

Python belgelerinden:

Resmi parametre yuvalarından daha fazla konum bağımsız değişkeni varsa, "* tanımlayıcı" sözdizimini kullanan resmi bir parametre yoksa, bir TypeError istisnası oluşur; bu durumda, bu resmi parametre, fazla konumsal argüman içeren bir grup alır (veya fazla konumsal argüman yoksa boş bir grup).

Herhangi bir anahtar kelime argümanı resmi bir parametre adına karşılık gelmezse, "** tanımlayıcı" sözdizimini kullanan resmi bir parametre mevcut değilse, TypeError istisnası oluşur; bu durumda, bu resmi parametre, fazla anahtar kelime bağımsız değişkenlerini içeren bir sözlük (anahtar kelimeler olarak anahtarlar ve bağımsız değişken değerleri karşılık gelen değerler olarak kullanarak) veya fazla anahtar kelime bağımsız değişkenleri yoksa (yeni) boş bir sözlük alır.


10

* grup olarak değişken argüman alma anlamına gelir

** sözlük olarak değişken argüman almak anlamına gelir

Aşağıdaki gibi kullanılır:

1) tek *

def foo(*args):
    for arg in args:
        print(arg)

foo("two", 3)

Çıktı:

two
3

2) Şimdi **

def bar(**kwargs):
    for key in kwargs:
        print(key, kwargs[key])

bar(dic1="two", dic2=3)

Çıktı:

dic1 two
dic2 3

8

Başkalarının bahsetmediği bir örnek vermek istiyorum

* ayrıca bir jeneratörü açabilir

Python3 Dokümanından bir örnek

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x [1, 2, 3], unzip_y [4, 5, 6] olacak

Zip () birden fazla iretable argüman alır ve bir jeneratör döndürür.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))

7

Python 3.5, ayrıca bu sözdizimini kullanabilirsiniz list, dict, tuple, ve setgörüntüler (bazen denir değişmezleri). Bkz. PEP 488: Ek Ambalajdan Çıkarma Genelleştirmeleri .

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

Ayrıca, tek bir işlev çağrısında birden çok yinelemenin paketinin açılmasını sağlar.

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(PEP bağlantısı için mgilson'a teşekkürler.)


1
Bunun "bunu yapmanın tek bir yolu var" ihlali olduğundan emin değilim. Birden fazla yinelemeden bir liste / grup başlatmanın başka bir yolu yoktur - Şu anda bunları her zaman uygun olmayan tek bir yinelenebilir olarak zincirlemeniz gerekir. Rasyonel hakkında PEP-0448'den okuyabilirsiniz . Ayrıca, bu bir python3.x özelliği değil, bir python3.5 + özelliği :-).
mgilson

mgilson, bu neden daha önce bahsedilmediğini açıklardı.
leewz

6

İşlev çağrılarına ek olarak, * args ve ** kwargs sınıf hiyerarşilerinde yararlıdır ve __init__Python'da yazma yöntemi kullanmaktan kaçınır . Benzer kullanım Django kodu gibi çerçevelerde de görülebilir.

Örneğin,

def __init__(self, *args, **kwargs):
    for attribute_name, value in zip(self._expected_attributes, args):
        setattr(self, attribute_name, value)
        if kwargs.has_key(attribute_name):
            kwargs.pop(attribute_name)

    for attribute_name in kwargs.viewkeys():
        setattr(self, attribute_name, kwargs[attribute_name])

Daha sonra bir alt sınıf olabilir

class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

Daha sonra alt sınıf şu şekilde somutlaştırılır:

food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())

Ayrıca, yalnızca bu alt sınıf örneği için anlamlı olan yeni bir özniteliğe sahip bir alt sınıf __init__, öznitelikler ayarını boşaltmak için Base sınıfını çağırabilir . Bu, * args ve ** kwargs aracılığıyla yapılır. kwargs çoğunlukla kodun adlandırılmış argümanlar kullanılarak okunabilmesi için kullanılır. Örneğin,

class ElectronicAccessories(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['specifications']
    # Depend on args and kwargs to populate the data as needed.
    def __init__(self, specifications = None, *args, **kwargs):
        self.specifications = specifications  # Rest of attributes will make sense to parent class.
        super(ElectronicAccessories, self).__init__(*args, **kwargs)

ki bu şekilde oluşturulabilir

usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')

Kodun tamamı burada


1
1. Temel olarak init bir yöntemdir, bu yüzden (bu bağlamda) gerçekten farklı değildir. .. 2. # değil """, sadece işaretleri edebi dizeleri 3. özellikle çok düzeyli miras ile örneğin tercih edilen bir yol olmalıdır süper kullanma yorumlar için
0xc0de

4

Nickd'in cevabı üzerine inşa ...

def foo(param1, *param2):
    print(param1)
    print(param2)


def bar(param1, **param2):
    print(param1)
    print(param2)


def three_params(param1, *param2, **param3):
    print(param1)
    print(param2)
    print(param3)


foo(1, 2, 3, 4, 5)
print("\n")
bar(1, a=2, b=3)
print("\n")
three_params(1, 2, 3, 4, s=5)

Çıktı:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

1
(2, 3, 4)
{'s': 5}

Temel olarak, herhangi bir sayıda konum argümanı * argümanı kullanabilir ve adlandırılmış herhangi bir argüman (veya anahtar kelime argümanları olarak adlandırılan kwargs) ** kwargs kullanabilir.


3

*argsve **kwargs: bir işleve değişken sayıda bağımsız değişken iletmenizi sağlar.

*args: işleve anahtar sözcük içermeyen bir değişken uzunluklu bağımsız değişken listesi göndermek için kullanılır:

def args(normal_arg, *argv):
    print("normal argument:", normal_arg)

    for arg in argv:
        print("Argument in list of arguments from *argv:", arg)

args('animals', 'fish', 'duck', 'bird')

Üretecek:

normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird

**kwargs*

**kwargsanahtar sözcüklü değişken uzunluktaki bağımsız değişkenleri bir işleve iletmenizi sağlar. **kwargsBir işlevdeki adlandırılmış bağımsız değişkenleri işlemek istiyorsanız kullanmalısınız .

def who(**kwargs):
    if kwargs is not None:
        for key, value in kwargs.items():
            print("Your %s is %s." % (key, value))

who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")  

Üretecek:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.

2

Bu örnek hatırlamanıza yardımcı olur *args, **kwargshatta superaynı anda Python ve miras.

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg

class child2(base):
    def __init__(self, child_param, **kwargs):
        self.child_param = child_param
        super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg

c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1

1

Her ikisini bir işlevde kullanmaya iyi bir örnek:

>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}

1

TL; DR

Aşağıda python programlama için *ve **python programlamasında 6 farklı kullanım durumu bulunmaktadır :

  1. Kullanarak herhangi bir sayıda konum argümanı kabul etmek için *args: def foo(*args): pass burada fooherhangi bir sayıda konum argümanı kabul eder, yani aşağıdaki çağrılar geçerlidir foo(1),foo(1, 'bar')
  2. Kullanarak anahtar kelime herhangi bir sayıda argümanı kabul etmek **kwargs: def foo(**kwargs): pass burada 'foo' yani anahtar kelime argümanlar, herhangi bir sayıda kabul aşağıdaki aramalar geçerlidir foo(name='Tom'),foo(name='Tom', age=33)
  3. Kullanarak pozisyonel ve anahtar kelime herhangi bir sayıda argümanı kabul etmek *args, **kwargs: def foo(*args, **kwargs): pass burada fooyani pozisyonel ve anahtar kelime argümanlar, herhangi bir sayıda kabul aşağıdaki aramalar geçerlidir foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Yalnızca anahtar kelime bağımsız değişkenlerini *: kullanarak zorlamak için def foo(pos1, pos2, *, kwarg1): pass , burada *foo yalnızca pos2'den sonra anahtar kelime bağımsız değişkenlerini kabul ettiği anlamına gelir, bu nedenle foo(1, 2, 3)TypeError öğesini yükseltir , ancak foo(1, 2, kwarg1=3)tamamdır.
  5. Kullanarak daha fazla pozisyonel argümanlar içerisinde daha başka ilgi ifade etmek *_(Not: Bu bir kuralıdır için): def foo(bar, baz, *_): pass (Kongre tarafından) araçlar foosadece kullanımları barvebaz argümanları başkalarını görmezden gelir.
  6. \**_(Not: bu yalnızca bir sözleşmedir) kullanarak daha fazla anahtar kelime bağımsız değişkenine daha fazla ilgi göstermeyeceğini ifade etmek için : def foo(bar, baz, **_): pass (kural gereği) fooyalnızca çalışmalarında barve bazbağımsız değişkenlerini kullanır ve diğerlerini yok sayar.

BONUS: Python 3.8'den itibaren, /yalnızca konum parametrelerini uygulamak için işlev tanımında kullanılabilir . Aşağıdaki örnekte, a ve b parametreleri yalnızca konumsalken , c veya d konum veya anahtar kelime olabilir ve e veya f'nin anahtar kelime olması gerekir:

def f(a, b, /, c, d, *, e, f):
    pass

0

TL; DR

İşleve , işlev gövdesinin içine listve içine aktarılan bağımsız değişkenleri paketler dict. Bunun gibi bir işlev imzası tanımladığınızda:

def func(*args, **kwds):
    # do stuff

herhangi bir sayıda argüman ve anahtar kelime argümanı ile çağrılabilir. Anahtar kelime olmayan bağımsız değişkenler args, işlev gövdesi içinde çağrılan bir listeye ve anahtar kelime bağımsız değişkenleri kwds, işlev gövdesi içinde çağrılan bir dikte içine paketlenir .

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

Şimdi fonksiyonu olarak adlandırılan fonksiyonu gövdenin içinde, iki lokal değişkenler, orada argsbir listesi olan bir değerdir ["this", "is a list of", "non-keyword", "arguments"]ve kwdsbir edilir dictolan bir değer{"keyword" : "ligma", "options" : [1,2,3]}


Bu aynı zamanda, yani arayan tarafından ters yönde de çalışır. örneğin şu şekilde tanımlanmış bir fonksiyonunuz varsa:

def f(a, b, c, d=1, e=10):
    # do stuff

arama kapsamındaki yinelemeleri veya eşlemeleri açarak bunu arayabilirsiniz:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)

0

bağlam

  • python 3.x
  • ambalajından çıkarma **
  • dize biçimlendirme ile kullanma

Dize biçimlendirmesiyle kullanma

Bu konudaki cevaplara ek olarak, burada başka bir yerde bahsedilmeyen bir ayrıntı daha var. Bu Brad Solomon'ın cevabını genişletiyor

İle paketten çıkarma, **python kullanırken de yararlıdır str.format.

Bu, python f-string ile yapabileceklerinize biraz benziyorf-strings ancak değişkenleri tutmak için bir dikte bildirme ek yükü ile (f-string bir dikte gerektirmez).

Hızlı Örnek

  ## init vars
  ddvars = dict()
  ddcalc = dict()
  pass
  ddvars['fname']     = 'Huomer'
  ddvars['lname']     = 'Huimpson'
  ddvars['motto']     = 'I love donuts!'
  ddvars['age']       = 33
  pass
  ddcalc['ydiff']     = 5
  ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
  pass
  vdemo = []

  ## ********************
  ## single unpack supported in py 2.7
  vdemo.append('''
  Hello {fname} {lname}!

  Today you are {age} years old!

  We love your motto "{motto}" and we agree with you!
  '''.format(**ddvars)) 
  pass

  ## ********************
  ## multiple unpack supported in py 3.x
  vdemo.append('''
  Hello {fname} {lname}!

  In {ydiff} years you will be {ycalc} years old!
  '''.format(**ddvars,**ddcalc)) 
  pass

  ## ********************
  print(vdemo[-1])

-2
  • def foo(param1, *param2):için rasgele sayıda değer kabul edebilen bir yöntemdir *param2,
  • def bar(param1, **param2): tuşları ile keyfi sayıda değer kabul edebileceğiniz bir yöntemdir *param2
  • param1 basit bir parametredir.

Örneğin, Java'da varargs uygulamak için sözdizimi aşağıdaki gibidir:

accessModifier methodName(datatype arg) {
    // method body
}
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.