Co oznacza ** (podwójna gwiazdka / gwiazdka) i * (gwiazdka / gwiazdka) dla parametrów?


2347

W poniższych definicjach metod do czego służy *i **do czego służy param2?

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



Zobacz także stackoverflow.com/questions/14301967/..., aby zobaczyć gwiazdkę
naught101

23
To pytanie jest bardzo popularnym zduplikowanym celem, ale niestety jest często używane nieprawidłowo. Pamiętaj, że to pytanie dotyczy definiowania funkcji za pomocą varargs ( def func(*args)). Aby dowiedzieć się, co to znaczy w wywołaniach funkcji ( func(*[1,2])), zobacz tutaj . Aby dowiedzieć się, jak rozpakować listę argumentów, zobacz tutaj . W przypadku pytania dotyczącego *znaczenia literałów ( [*[1, 2]]) patrz tutaj .
Aran-Fey

Możesz dowiedzieć się o jego zastosowaniu w definicji funkcji i wywołaniu funkcji tutaj: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Odpowiedzi:


2234

*argsI **kwargsjest wspólny idiom, aby umożliwić dowolną liczbę argumentów do funkcji opisanych w sekcji więcej na temat definiowania funkcji w dokumentacji Pythona.

*argsDaje wszystkie parametry funkcyjne jak krotki :

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

foo(1)
# 1

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

**kwargsDaje wszystkie argumenty słów kluczowych z wyjątkiem tych, co odpowiada parametru formalnego jako słownika.

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

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

Oba idiomy można łączyć z normalnymi argumentami, aby umożliwić zestaw stałych i niektórych zmiennych argumentów:

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

Można również użyć tego na odwrót:

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

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

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

Innym zastosowaniem tego *lidiomu jest rozpakowywanie list argumentów podczas wywoływania funkcji.

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

l = [1,2]

foo(*l)
# 1 2

W Pythonie 3 można używać *lpo lewej stronie zadania ( Extended Iterable Unpacking ), chociaż w tym kontekście daje listę zamiast krotki:

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

Również Python 3 dodaje nowy semantyczny (patrz PEP 3102 ):

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

Taka funkcja przyjmuje tylko 3 argumenty pozycyjne, a wszystko później *można przekazać tylko jako argumenty słów kluczowych.


9
Wyjście [6] jest w odwrotnej kolejności.
wymień

53
@ thanos.a Dykty w języku Python, używane semantycznie do przekazywania argumentów słów kluczowych, są uporządkowane arbitralnie. Jednak w Pythonie 3.6 argumenty słów kluczowych gwarantują zapamiętanie kolejności wstawiania. „Kolejność elementów **kwargsodpowiada teraz kolejności, w której argumenty słów kluczowych zostały przekazane do funkcji.” - docs.python.org/3/whatsnew/3.6.html W rzeczywistości wszystkie nagrania w CPython 3.6 zapamiętują kolejność wstawiania jako szczegół implementacji, co staje się standardem w Pythonie 3.7.
Aaron Hall

13
Bardzo precyzyjny, czysty i łatwy do zrozumienia. Doceniam to, że zauważyłeś, że jest to „operator rozpakowywania”, dzięki czemu mogłem odróżnić od
podania

Jak przetestować ostatnią funkcję za pomocą PEP 3102? Nazywam to func (1,2,3, name = "me", age = 10) i rzuca wyjątek:got an unexpected keyword argument 'name'
Kok How Teh

@KokHowTeh Musisz przekazać kwargi o takiej nazwie, jak są w funkcji: func (1, 2, 3, kwarg1 = „ja”, kwarg2 = 10)
John Aaron

622

Warto również zauważyć, że możesz używać *i **podczas wywoływania funkcji. Jest to skrót, który pozwala przekazać wiele argumentów do funkcji bezpośrednio przy użyciu listy / krotki lub słownika. Na przykład, jeśli masz następującą funkcję:

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

Możesz robić takie rzeczy jak:

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

Uwaga: Klucze w mydictmuszą być nazwane dokładnie tak, jak parametry funkcji foo. W przeciwnym razie wyrzuci 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

Pojedyncza * oznacza, że ​​może istnieć dowolna liczba dodatkowych argumentów pozycyjnych. foo()można wywołać jak foo(1,2,3,4,5). W treści foo () param2 jest sekwencją zawierającą 2-5.

Podwójna ** oznacza, że ​​może istnieć dowolna liczba dodatkowych nazwanych parametrów. bar()można wywołać jak bar(1, a=2, b=3). W treści bar () param2 znajduje się słownik zawierający {'a': 2, 'b': 3}

Z następującym kodem:

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)

wyjście jest

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

4
Być może foobar(param1, *param2, **param3)potrzebny jest dodatkowy przykład z kompletnością tej odpowiedzi.
Aniket Thakur,

1
@AniketThakur dodał tutaj pozostałą część .
Raj

147

Co robi **(podwójna gwiazda) i *(gwiazda) dla parametrów

Umożliwiają zdefiniowanie funkcji do zaakceptowania, a użytkownikom przekazanie dowolnej liczby argumentów, pozycyjnej ( *) i słowa kluczowego ( **).

Definiowanie funkcji

*argsdopuszcza dowolną liczbę opcjonalnych argumentów pozycyjnych (parametrów), które zostaną przypisane do krotki o nazwie args.

**kwargsdopuszcza dowolną liczbę opcjonalnych argumentów (parametrów) słowa kluczowego, które będą w nazwie o nazwie kwargs.

Możesz (i powinieneś) wybrać dowolną odpowiednią nazwę, ale jeśli intencją jest, aby argumenty miały nieswoistą semantykę argsi kwargsbyły standardowymi nazwami.

Rozbudowa, przekazanie dowolnej liczby argumentów

Możesz także użyć *argsi **kwargsdo przekazania parametrów odpowiednio z list (lub dowolnej iterowalnej) i dykt (lub dowolnego odwzorowania).

Funkcja odbierająca parametry nie musi wiedzieć, że są one rozszerzane.

Na przykład xrange w Pythonie 2 nie oczekuje wprost *args, ale ponieważ jako argument przyjmuje 3 liczby całkowite:

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

Jako kolejny przykład możemy użyć rozszerzenia dict w str.format:

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

Nowość w Python 3: Definiowanie funkcji za pomocą argumentów zawierających tylko słowa kluczowe

Możesz mieć tylko słowa kluczowe jako argumenty - po, *argsna przykład, tutaj kwarg2musisz podać jako słowo kluczowe - nie pozycjonować:

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

Stosowanie:

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

Ponadto, *może być stosowany przez siebie słów kluczowych, aby wskazać, że tylko argumenty naśladowania, nie pozwalając na nieograniczone pozycyjnych argumentów.

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

Tutaj kwarg2znowu musi być jawnie nazwany argument słowa kluczowego:

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

Nie możemy dłużej akceptować nieograniczonej liczby argumentów pozycyjnych, ponieważ nie mamy *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

Ponownie, prościej, tutaj wymagamy kwargpodania imienia, a nie pozycji:

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

W tym przykładzie widzimy, że jeśli spróbujemy przekazać kwargpozycję, otrzymujemy błąd:

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

Musimy jawnie przekazać kwargparametr jako argument słowa kluczowego.

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

Dema kompatybilne z Python 2

*args(zwykle mówi się „star-args”) i **kwargs(gwiazdy można sugerować, mówiąc „kwargs”, ale wyraźne w przypadku „podwójnej gwiazdy kwargs”) są powszechnymi idiomami Pythona do używania *i **notacji. Te specyficzne nazwy zmiennych nie są wymagane (np. Możesz użyć *foosi **bars), ale odejście od konwencji prawdopodobnie rozwścieczy innych koderów Pythona.

Zazwyczaj używamy ich, gdy nie wiemy, co otrzyma nasza funkcja lub ile argumentów możemy przekazać, a czasami nawet gdy nazewnictwo każdej zmiennej osobno byłoby bardzo nieporządne i zbędne (ale jest to przypadek, w którym zwykle jawne jest lepszy niż dorozumiany).

Przykład 1

Poniższa funkcja opisuje, w jaki sposób można ich używać, i pokazuje zachowanie. Uwaga: nazwany bargument zostanie wykorzystany przez drugi argument pozycyjny przed:

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

Możemy sprawdzić pomoc online dla podpisu funkcji, za pomocą help(foo), który nam to mówi

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

Nazwijmy tę funkcję za pomocą foo(1, 2, 3, 4, e=5, f=6, g=7)

który drukuje:

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}

Przykład 2

Możemy również wywołać go za pomocą innej funkcji, w której zapewniamy 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) drukuje:

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}

Przykład 3: praktyczne zastosowanie w dekoratorach

OK, więc może jeszcze nie widzimy narzędzia. Wyobraź sobie, że masz kilka funkcji z kodem nadmiarowym przed i / lub po kodzie różnicującym. Poniższe nazwane funkcje to tylko pseudo-kod do celów ilustracyjnych.

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

Możemy być w stanie poradzić sobie z tym inaczej, ale z pewnością możemy wydobyć nadmiarowość za pomocą dekoratora, dlatego nasz poniższy przykład pokazuje, jak *argsi **kwargsmoże być bardzo przydatny:

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

A teraz każdą zawiniętą funkcję można napisać o wiele bardziej zwięźle, ponieważ uwzględniliśmy redundancję:

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

Oraz faktoringu nasz kod, który *argsi **kwargspozwala nam zrobić, to zmniejszyć linii kodu, poprawiają czytelność i łatwość konserwacji i mają wyłączne kanoniczne lokalizacje dla logiki w naszym programie. Jeśli potrzebujemy zmienić dowolną część tej struktury, mamy jedno miejsce, w którym można dokonać każdej zmiany.


48

Najpierw zrozumiemy, czym są argumenty pozycyjne i argumenty słów kluczowych. Poniżej znajduje się przykład definicji funkcji z argumentami Pozycyjnymi.

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

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

To jest definicja funkcji z argumentami pozycyjnymi. Możesz to również wywołać za pomocą argumentów słowo kluczowe / nazwane:

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

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

Przeanalizujmy teraz przykład definicji funkcji z argumentami słów kluczowych :

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

Możesz wywołać tę funkcję również z argumentami pozycyjnymi:

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

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

Znamy więc definicje funkcji z argumentami pozycyjnymi i słowami kluczowymi.

Przyjrzyjmy się teraz operatorowi „*” i operatorowi „**”.

Uwaga: tych operatorów można używać w 2 obszarach:

a) wywołanie funkcji

b) definicja funkcji

Zastosowanie operatora „*” i operatora „**” w wywołaniu funkcji.

Przejdźmy od razu do przykładu, a następnie go omówmy.

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.

Więc pamiętaj

gdy w wywołaniu funkcji używany jest operator „*” lub „**” -

Operator „*” rozpakowuje strukturę danych, na przykład listę lub krotkę, na argumenty potrzebne do definicji funkcji.

Operator „**” rozpakowuje słownik na argumenty potrzebne do definicji funkcji.

Przeanalizujmy teraz użycie operatora „*” w definicji funkcji . Przykład:

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

W definicji funkcji operator „*” pakuje otrzymane argumenty do krotki.

Zobaczmy teraz przykład „**” zastosowany w definicji funkcji:

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

W definicji funkcji Operator „**” pakuje odebrane argumenty do słownika.

Więc pamiętaj:

W wywołaniu funkcji „*” rozpakowuje strukturę danych krotki lub listy na argumenty pozycyjne lub słowa kluczowe, które mają zostać odebrane przez definicję funkcji.

W wywołaniu funkcji „**” rozpakowuje strukturę danych słownika na argumenty pozycyjne lub słowa kluczowe, które mają zostać odebrane przez definicję funkcji.

W definicji funkcji „*” pakuje argumenty pozycyjne w krotkę.

W definicji funkcji „**” pakuje argumenty słów kluczowych do słownika.


Naprawdę czyste, krok po kroku i łatwe do naśladowania wyjaśnienie!
Aleksandar,

dzięki Zachowaj przychodzące głosy. [Również dla dalszych notatek ode mnie, jestem na @mrtechmaker na Twitterze]
Karan Ahuja

32

Ta tabela jest przydatna do używania *oraz **w budowie funkcji i wywołaniu funkcji :

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

To tak naprawdę służy do podsumowania Lorina Hochstein za odpowiedź , ale uważam, że pomocne.

Odpowiednio: zastosowania dla operatorów gwiazda / ikona zostały rozszerzone w Pythonie 3


22

*i **mają specjalne zastosowanie na liście argumentów funkcji. * implikuje, że argument jest listą i **implikuje, że argument jest słownikiem. Umożliwia to funkcjom przyjmowanie dowolnej liczby argumentów


17

Dla tych z was, którzy uczą się na przykładach!

  1. Celem * jest umożliwienie zdefiniowania funkcji, która może przyjąć dowolną liczbę argumentów podanych jako lista (np f(*myList).).
  2. Ma **to na celu umożliwienie podawania argumentów funkcji przez udostępnienie słownika (np f(**{'x' : 1, 'y' : 2}).).

Pokażmy to definiując funkcję, która pobiera dwa normalne zmienne x, yi może przyjąć więcej argumentów, jak myArgsi może przyjąć jeszcze więcej argumentów jak myKW. Później pokażemy, jak karmić yza pomocą 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   = {}
# ----------------------------------------------------------------------

Ostrzeżenia

  1. ** jest zarezerwowane wyłącznie dla słowników.
  2. Opcjonalne przypisywanie argumentów następuje w pierwszej kolejności.
  3. Nie można dwa razy użyć opcjonalnego argumentu.
  4. Jeśli dotyczy, **musi *zawsze nastąpić później .

14

Z dokumentacji Python:

Jeśli jest więcej argumentów pozycyjnych niż formalnych przedziałów parametrów, zgłaszany jest wyjątek TypeError, chyba że występuje formalny parametr wykorzystujący składnię „* identyfikator”; w tym przypadku ten parametr formalny otrzymuje krotkę zawierającą nadmiar argumentów pozycyjnych (lub pustą krotkę, jeśli nie było nadmiaru argumentów pozycyjnych).

Jeśli dowolny argument słowa kluczowego nie odpowiada formalnej nazwie parametru, zgłaszany jest wyjątek TypeError, chyba że występuje formalny parametr wykorzystujący składnię „** identyfikator”; w tym przypadku ten parametr formalny otrzymuje słownik zawierający nadmiar argumentów słowa kluczowego (używając słów kluczowych jako kluczy i wartości argumentów jako odpowiednich wartości) lub (nowy) pusty słownik, jeśli nie było nadmiaru argumentów słowa kluczowego.


10

* oznacza odbieranie zmiennych argumentów jako krotki

** oznacza odbieranie zmiennych argumentów jako słownik

Używany w następujący sposób:

1) pojedynczy *

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

foo("two", 3)

Wynik:

two
3

2) Teraz **

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

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

Wynik:

dic1 two
dic2 3

8

Chcę podać przykład, o którym inni nie wspominali

* można również rozpakować generator

Przykład z dokumentu Python3

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

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

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

Zip () odbiera wiele możliwych do zapisania argumentów i zwraca generator.

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

7

W Pythonie 3.5, można również użyć tej składni w list, dict, tuplei setwyświetlenia (zwany też czasami literałów). Zobacz PEP 488: Dodatkowe uogólnienia dotyczące rozpakowywania .

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

Umożliwia także rozpakowanie wielu iteracji w jednym wywołaniu funkcji.

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

(Podziękowania dla mgilson za link PEP.)


1
Nie jestem pewien, czy jest to naruszenie „jest tylko jeden sposób, aby to zrobić”. Nie ma innego sposobu na zainicjowanie listy / krotki z wielu iteracji - obecnie musisz połączyć je w jedną iterację, co nie zawsze jest wygodne. Możesz przeczytać o racjonalności w PEP-0448 . Ponadto nie jest to funkcja python3.x, jest to funkcja python3.5 + :-).
mgilson,

@mgilson, to wyjaśniałoby, dlaczego nie wspomniano wcześniej.
leewz

6

Oprócz wywołań funkcji, * args i ** kwargs są przydatne w hierarchiach klas, a także unikają konieczności pisania __init__metod w Pythonie. Podobne użycie można zobaczyć w ramach takich jak kod Django.

Na przykład,

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

Wówczas może być podklasa

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

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

Następnie należy utworzyć instancję podklasy jako

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

Ponadto podklasa z nowym atrybutem, która ma sens tylko dla tej instancji podklasy, może wywoływać klasę Base w __init__celu odciążenia ustawienia atrybutów. Odbywa się to za pomocą * args i ** kwargs. kwargs używane głównie, aby kod był czytelny przy użyciu nazwanych argumentów. Na przykład,

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)

który może być zaimplementowany jako

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

Pełny kod jest tutaj


1
1. Zasadniczo init jest metodą, więc (w tym kontekście) tak naprawdę nie jest inaczej. 2. Użyj # dla komentarzy, a nie „” ”, który oznacza tylko dosłowne ciągi znaków. 3. Używanie super powinno być preferowanym sposobem, szczególnie w twoim przykładzie z dziedziczeniem wielopoziomowym.
0xc0de 21.02.18

4

Opierając się na odpowiedzi Nickda ...

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)

Wynik:

1
(2, 3, 4, 5)

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

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

Zasadniczo dowolna liczba argumentów pozycyjnych może używać * argumentów, a dowolne nazwane argumenty (lub argumenty kwargs zwane również argumentami słów kluczowych) mogą używać ** kwargs.


3

*argsi **kwargs: pozwala przekazać zmienną liczbę argumentów do funkcji.

*args: służy do wysłania listy argumentów o zmiennej długości bez słów kluczowych do funkcji:

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

Będzie produkować:

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*

**kwargspozwala na przekazanie funkcji zmiennej o zmiennej długości argumentów. Powinieneś użyć, **kwargsjeśli chcesz obsługiwać nazwane argumenty w funkcji.

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

Będzie produkować:

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

2

Ten przykład pomoże ci zapamiętać *args, **kwargsa nawet superodziedziczyć w Pythonie naraz.

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

Dobrym przykładem użycia obu funkcji jest:

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

Poniżej 6 różnych przypadków użycia dla *i **w programowaniu Pythona:

  1. Aby przyjąć dowolną liczbę argumentów pozycyjnych używając *args: def foo(*args): pass tu fooprzyjmuje dowolną liczbę argumentów pozycyjnych, czyli następujące połączenia są prawidłowe foo(1),foo(1, 'bar')
  2. Aby zaakceptować dowolną liczbę argumentów słów kluczowych za pomocą **kwargs: def foo(**kwargs): pass tutaj „foo” akceptuje dowolną liczbę argumentów słów kluczowych, tj. Prawidłowe są następujące wywołania foo(name='Tom'),foo(name='Tom', age=33)
  3. Aby przyjąć dowolną liczbę argumentów pozycyjnych i używając słów kluczowych *args, **kwargs: def foo(*args, **kwargs): pass , tutaj fooprzyjmuje dowolną liczbę argumentów pozycyjnych i słów kluczowych, czyli następujące połączenia są prawidłowe foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Aby wymusić tylko argumenty za pomocą słów kluczowych *: def foo(pos1, pos2, *, kwarg1): pass tutaj *oznacza, że foo akceptować tylko argumenty słów kluczowych po pos2, stąd foo(1, 2, 3)podnosi TypeError ale foo(1, 2, kwarg1=3)jest w porządku.
  5. Aby nie wyrażać dalszego zainteresowania bardziej argumentami pozycyjnymi za pomocą *_(Uwaga: to tylko konwencja): def foo(bar, baz, *_): pass oznacza (zgodnie z konwencją) footylko użycie bari bazargumenty w działaniu i zignoruje inne.
  6. Aby nie wyrażać dalszego zainteresowania większą liczbą argumentów słów kluczowych za pomocą \**_(Uwaga: jest to tylko konwencja): def foo(bar, baz, **_): pass oznacza (zgodnie z konwencją) footylko użycie bari bazargumenty w działaniu i zignoruje inne.

BONUS: Począwszy od Pythona 3.8, można używać /definicji funkcji do wymuszania parametrów tylko pozycyjnych. W poniższym przykładzie parametry aib są tylko pozycyjne , podczas gdy c lub d może być pozycyjne lub słowo kluczowe, a e lub f muszą być słowami kluczowymi:

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

0

TL; DR

Pakuje argumenty przekazane do funkcji do listi dictodpowiednio wewnątrz treści funkcji. Po zdefiniowaniu podpisu funkcji w ten sposób:

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

można go wywołać z dowolną liczbą argumentów i argumentów słów kluczowych. Argumenty niebędące słowami kluczowymi są pakowane w listę wywoływaną argsw treści funkcji, a argumenty słów kluczowych są pakowane w dykt wywoływany kwdsw treści funkcji.

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

teraz w ciele funkcji, gdy funkcja jest wywoływana, istnieją dwie zmienne lokalne, argsktóra jest listą o wartości ["this", "is a list of", "non-keyword", "arguments"]i kwdsktóra dictma wartość{"keyword" : "ligma", "options" : [1,2,3]}


Działa to również w odwrotnej kolejności, tj. Po stronie dzwoniącego. na przykład, jeśli masz funkcję zdefiniowaną jako:

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

możesz to wywołać przez rozpakowanie iteracji lub mapowań, które masz w zakresie wywoływania:

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

Kontekst

  • python 3.x
  • rozpakowywanie za pomocą **
  • używać z formatowaniem ciągów

Używaj z formatowaniem ciągów

Oprócz odpowiedzi w tym wątku, oto kolejny szczegół, który nie został wymieniony w innym miejscu. Rozszerza to odpowiedź Brada Solomona

Rozpakowywanie za pomocą **jest również przydatne w przypadku używania Pythona str.format.

Jest to nieco podobne do tego, co można zrobić z ciągiem f Pythonaf-strings ale z dodatkowym obciążeniem wynikającym z deklarowania, że ​​dict przechowuje zmienne (ciąg f nie wymaga dyktowania).

Szybki przykład

  ## 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):to metoda może zaakceptować dowolną liczbę wartości dla *param2,
  • def bar(param1, **param2): to metoda może zaakceptować dowolną liczbę wartości za pomocą kluczy *param2
  • param1 jest prostym parametrem.

Na przykład składnia do implementacji varargs w Javie jest następująca:

accessModifier methodName(datatype arg) {
    // method body
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.