Wat doen ** (dubbele ster/sterretje) en * (ster/sterretje) voor parameters?

Wat doen de *en **in de volgende methodedefinities voor param2?

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

Antwoord 1, autoriteit 100%

De *argsen **kwargsis een veelgebruikt idioom om een willekeurig aantal argumenten toe te staan aan functies zoals beschreven in de sectie meer over het definiëren van functiesin de Python-documentatie.

De *argsgeeft je alle functieparameters als een tuple:

def foo(*args):
    for a in args:
        print(a)        
foo(1)
# 1
foo(1,2,3)
# 1
# 2
# 3

De **kwargszullen je alles geven
zoekwoordargumentenbehalve die overeenkomen met een formele parameter als een woordenboek.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  
bar(name='one', age=27)
# name one
# age 27

Beide idiomen kunnen worden gemengd met normale argumenten om een reeks vaste en enkele variabele argumenten mogelijk te maken:

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

Het is ook mogelijk om dit andersom te gebruiken:

def foo(a, b, c):
    print(a, b, c)
obj = {'b':10, 'c':'lee'}
foo(100,**obj)
# 100 10 lee

Een ander gebruik van het *lidioom is om argumentenlijsten uit te pakkenbij het aanroepen van een functie.

def foo(bar, lee):
    print(bar, lee)
l = [1,2]
foo(*l)
# 1 2

In Python 3 is het mogelijk om *laan de linkerkant van een opdracht te gebruiken (Extended Iterable Unpacking), hoewel het in deze context een lijst geeft in plaats van een tuple:

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

Python 3 voegt ook nieuwe semantiek toe (zie PEP 3102):

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

Een dergelijke functie accepteert slechts 3 positionele argumenten en alles na *kan alleen als trefwoordargumenten worden doorgegeven.

Opmerking:

  • Een Python dict, semantisch gebruikt voor het doorgeven van trefwoordargumenten, is willekeurig geordend. In Python 3.6 onthouden trefwoordargumenten echter gegarandeerd de invoegvolgorde.
  • “De volgorde van elementen in **kwargskomt nu overeen met de volgorde waarin trefwoordargumenten aan de functie zijn doorgegeven.” – Wat is er nieuw in Python 3.6
  • In feite zullen alle dicts in CPython 3.6 de invoegvolgorde onthouden als een implementatiedetail, dit wordt standaard in Python 3.7.

Antwoord 2, autoriteit 27%

Het is ook vermeldenswaard dat u *en **ook kunt gebruiken bij het bellen van functies. Dit is een snelkoppeling waarmee u meerdere argumenten met een functie rechtstreeks gebruikt met behulp van een lijst / tuple of een woordenboek. Als u bijvoorbeeld de volgende functie hebt:

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

U kunt dingen doen zoals:

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

Opmerking: de toetsen in mydictmoeten exact zoals de parameters van de functie fooworden genoemd. Anders gooide het een 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'

3, Autoriteit 7%

De single * betekent dat er een willekeurig aantal extra positionele argumenten kan zijn. foo()kan worden aangeroepen als foo(1,2,3,4,5). In het lichaam van foo () is Param2 een reeks met 2-5.

De dubbele ** betekent dat er een aantal extra genoemde parameters kan zijn. bar()kan worden ingeroepen als bar(1, a=2, b=3). In het lichaam van de balk () is Param2 een woordenboek met {‘A’: 2, ‘B’: 3}

Met de volgende code:

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)

De uitvoer is

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

4

Deze tabel is handig voor het gebruik van *en **in functie constructie en functie bel :

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

Dit is eigenlijk alleen maar bedoeld om het antwoordvan Lorin Hochstein samen te vatten, maar ik vind het nuttig.

Aanverwant: gebruik voor de ster/splat-operators is uitgevouwenin Python 3


Antwoord 5

*en **hebben een speciaal gebruik in de lijst met functieargumenten. *
houdt in dat het argument een lijst is en **impliceert dat het argument
is een woordenboek. Hierdoor kunnen functies een willekeurig aantal
argumenten


6

Vanaf de Python-documentatie:

Als er meer positionele argumenten zijn dan formeel parameter slots, wordt een TypeError-uitzondering verhoogd, tenzij een formele parameter met behulp van de syntaxis “Identificatie” aanwezig is; In dit geval ontvangt die formele parameter een tuple met de overtollige positionele argumenten (of een lege tuple als er geen overtollige positionele argumenten waren).

Als een trefwoordargument niet overeenkomt met een formele parameternaam, wordt een TypeError-uitzondering gegenereerd, tenzij een formele parameter met de syntaxis “**identifier” aanwezig is; in dit geval ontvangt die formele parameter een woordenboek met de overtollige trefwoordargumenten (met de trefwoorden als sleutels en de argumentwaarden als corresponderende waarden), of een (nieuw) leeg woordenboek als er geen overtollige trefwoordargumenten waren.


Antwoord 7

*betekent variabele argumenten als tuple ontvangen

**betekent variabele argumenten als woordenboek ontvangen

Als volgt gebruikt:

1) single *

def foo(*args):
    for arg in args:
        print(arg)
foo("two", 3)

Uitvoer:

two
3

2) Nu **

def bar(**kwargs):
    for key in kwargs:
        print(key, kwargs[key])
bar(dic1="two", dic2=3)

Uitvoer:

dic1 two
dic2 3

Antwoord 8

In Python 3.5 kun je deze syntaxis ook gebruiken in list, dict, tupleen setdisplays (ook wel letterlijke letters genoemd). Zie PEP 488: aanvullende generalisaties voor uitpakken.

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

Het maakt het ook mogelijk meerdere iterables voor onverpakte in een enkele functie gesprek zijn.

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

(Met dank aan mgilson voor de PEP link.)


9

Ik wil een voorbeeld te geven, die anderen hebben niet genoemd

* kan ook uitpakken een generator

Een voorbeeld van python3 Document

x = [1, 2, 3]
y = [4, 5, 6]
unzip_x, unzip_y = zip(*zip(x, y))

unzip_x zal zijn [1, 2, 3] wordt unzip_y zijn [4, 5, 6]

De zip () wordt meerdere keren iretable argumenten en retourneren een generator.

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

10

Voortbouwend op nickd antwoord

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)

Uitgang:

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

Kortom, een willekeurig aantal Positional Argumenten kan * args en elke genoemde argumenten (of kwargs aka trefwoord argumenten) gebruiken ** Kwargs.


11

TL; DR

IT-pakketten Argumenten die zijn doorgegeven aan de functie in listen dictrespectievelijk in de functie. Wanneer u een functiesignatuur als volgt definieert:

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

Het kan worden opgeroepen met een aantal argumenten en trefwoordargumenten. De niet-trefwoordargumenten worden verpakt in een lijst met de naam argsin de functie-instantie en de trefwoord argumenten worden ingepakt in een dict die kwdsin de functie-instantie wordt genoemd.

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

Nu in de functieklichaam, wanneer de functie wordt genoemd, zijn er twee lokale variabelen, argsdie een lijst is met waarde ["this", "is a list of", "non-keyword", "arguments"]en kwdsdie een dictmet waarde {"keyword" : "ligma", "options" : [1,2,3]}


Dit werkt ook in omgekeerde volgorde, d.w.z. van de bellerzijde. Bijvoorbeeld als u een functie hebt gedefinieerd als:

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

U kunt het bellen door iterables of toewijzingen die u in de roepingsscope hebt uitpakken:

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)

12

Naast functieaanroepen zijn *args en **kwargs nuttig in klassenhiërarchieën en voorkomen ze dat de methode __init__in Python moet worden geschreven. Vergelijkbaar gebruik kan worden gezien in frameworks zoals Django-code.

Bijvoorbeeld

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

Een subklasse kan dan zijn

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

De subklasse wordt dan geïnstantieerd als

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

Ook kan een subklasse met een nieuw attribuut dat alleen voor die subklasse-instantie zinvol is, de basisklasse __init__aanroepen om de attributen-instelling te ontlasten.
Dit gebeurt via *args en **kwargs. kwargs voornamelijk gebruikt zodat code leesbaar is met behulp van benoemde argumenten. Bijvoorbeeld,

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)

die kunnen worden geïnstalleerd als

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

De volledige code is hier


13

Gegeven een functie met 3 items als argument

sum = lambda x, y, z: x + y + z
sum(1,2,3) # sum 3 items
sum([1,2,3]) # error, needs 3 items, not 1 list
x = [1,2,3][0]
y = [1,2,3][1]
z = [1,2,3][2]
sum(x,y,z) # ok
sum(*[1,2,3]) # ok, 1 list becomes 3 items

Stel je dit speelgoed voor met een zak met een driehoek, een cirkel en een rechthoekig item. Die tas past niet direct. Je moet de tas uitpakken om die 3 items te nemen en nu passen ze. De Python * -operator doet dit uitpakken.


14

Een goed voorbeeld van het gebruik van zowel in een functie is:

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

15

Dit voorbeeld zou u kunnen herinneren *args, **kwargsen zelfs superen erfenis in Python tegelijk.

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

16

Context

  • python 3.x
  • uitpakken met **
  • Gebruik met string-formattering

Gebruik met string-opmaak

Naast de antwoorden in deze thread, is hier een ander detail dat niet elders werd genoemd. Dit breidt zich uit op de antwoord door Brad Solomon

Uitpakken met **is ook handig bij het gebruik van Python str.format.

Dit is enigszins vergelijkbaar met wat je kunt doen met python f-stringsf-stringmaar met de extra overhead van het declareren van een dictaat om de variabelen vast te houden (f-string vereist geen dictaat).

Snel voorbeeld

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

Antwoord 17

*args ( of *any ) betekent elke parameter

def any_param(*param):
    pass
any_param(1)
any_param(1,1)
any_param(1,1,1)
any_param(1,...)

OPMERKING: u kunt geen parameters doorgeven aan *args

def any_param(*param):
    pass
any_param() # will work correct

De *args is van het type tuple

def any_param(*param):
    return type(param)
any_param(1) #tuple
any_param() # tuple

gebruik voor toegang tot elementen geen *

def any(*param):
    param[0] # correct
def any(*param):
    *param[0] # incorrect

De **kwd

**kwd of **any
Dit is een dictaat

def func(**any):
    return type(any) # dict
def func(**any):
    return any
func(width="10",height="20") # {width="10",height="20")

Antwoord 18

  • def foo(param1, *param2):is een methode die een willekeurig aantal waarden kan accepteren voor *param2,
  • def bar(param1, **param2):is een methode die een willekeurig aantal waarden kan accepteren met sleutels voor *param2
  • param1is een eenvoudige parameter.

Bijvoorbeeld de syntaxis voor het implementeren van varargsin Java als volgt:

accessModifier methodName(datatype… arg) {
    // method body
}

Other episodes