O que ** (estrela dupla / asterisco) e * (estrela / asterisco) fazem para os parâmetros?

2351

Nas definições de método a seguir, o que o *e **faz param2?

def foo(param1, *param2):
def bar(param1, **param2):
Todd
fonte
4
veja também stackoverflow.com/questions/6967632/…
Aaron Hall
Veja também stackoverflow.com/questions/14301967/… para obter um asterisco
vazio
24
Essa pergunta é um destino duplicado muito popular, mas infelizmente é frequentemente usado incorretamente. Lembre-se de que esta pergunta é sobre definir funções com varargs ( def func(*args)). Para uma pergunta perguntando o que significa em chamadas de função ( func(*[1,2])), veja aqui . Para uma pergunta sobre como descompactar listas de argumentos, consulte aqui . Para uma pergunta perguntando o que *significa em literais ( [*[1, 2]]), veja aqui .
22719 Aran-Fey
Você pode aprender sobre a sua utilização na definição de função e chamada de função aqui: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Respostas:

2237

O *argse **kwargsé um idioma comum para permitir que um número arbitrário de argumentos funcione, conforme descrito na seção mais sobre como definir funções na documentação do Python.

O *argsvai lhe dar todos os parâmetros de função como uma tupla :

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

foo(1)
# 1

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

O **kwargsvai lhe dar todas argumentos chave , exceto para aqueles que corresponde a um parâmetro formal como um dicionário.

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

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

Ambos os idiomas podem ser misturados com argumentos normais para permitir um conjunto de argumentos fixos e alguns variáveis:

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

Também é possível usar isso ao contrário:

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

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

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

Outro uso do *lidioma é descompactar listas de argumentos ao chamar uma função.

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

l = [1,2]

foo(*l)
# 1 2

No Python 3, é possível usar *lno lado esquerdo de uma atribuição ( descompactação iterável estendida ), apesar de fornecer uma lista em vez de uma tupla neste contexto:

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

Além disso, o Python 3 adiciona uma nova semântica (consulte PEP 3102 ):

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

Essa função aceita apenas três argumentos posicionais e tudo o que se segue *só pode ser passado como argumento de palavra-chave.

Peter Hoffmann
fonte
9
A saída de [6] está na ordem inversa. name one age 27
thanos.a
54
@ thanos.a Os dicionários Python, usados ​​semanticamente para a passagem de argumentos de palavras-chave, são ordenados arbitrariamente. No entanto, no Python 3.6, os argumentos das palavras-chave são garantidos para lembrar a ordem de inserção. "A ordem dos elementos **kwargsagora corresponde à ordem na qual os argumentos das palavras-chave foram passados ​​para a função." - docs.python.org/3/whatsnew/3.6.html De fato, todos os ditados no CPython 3.6 lembram a ordem de inserção como um detalhe de implementação; isso se torna padrão no Python 3.7.
Aaron Hall
13
Muito preciso, limpo e fácil de entender. Eu aprecio que você notou que é um "operador de descompactação", para que eu pudesse diferenciar de passagem por referência em C. 1
bballdave025
Como testar a última função com o PEP 3102? Eu o chamo com func (1,2,3, name = "me", age = 10) e gera uma exceção:got an unexpected keyword argument 'name'
Kok How Teh
@KokHowTeh Você precisa passar os kwargs nomeados como eles são na função: func (1, 2, 3, kwarg1 = 'eu', kwarg2 = 10)
John Aaron
622

Também é importante notar que você pode usar *e **ao chamar funções também. Este é um atalho que permite passar vários argumentos para uma função diretamente usando uma lista / tupla ou um dicionário. Por exemplo, se você tiver a seguinte função:

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

Você pode fazer coisas como:

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

Nota: As teclas mydictdevem ser nomeadas exatamente como os parâmetros da função foo. Caso contrário, ele lançará um 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'
Lorin Hochstein
fonte
175

O único * significa que pode haver qualquer número de argumentos posicionais extras. foo()pode ser invocado como foo(1,2,3,4,5). No corpo de foo (), param2 é uma sequência contendo 2-5.

O duplo ** significa que pode haver qualquer número de parâmetros nomeados extras. bar()pode ser invocado como bar(1, a=2, b=3). No corpo de bar (), param2 é um dicionário que contém {'a': 2, 'b': 3}

Com o seguinte código:

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)

a saída é

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}
nickd
fonte
5
Talvez foobar(param1, *param2, **param3)seja necessário um exemplo adicional com para completar esta resposta.
Aniket Thakur
1
@AniketThakur adicionou a parte restante aqui .
Raj
148

O que **(estrela dupla) e *(estrela) fazem pelos parâmetros

Eles permitem que funções sejam definidas para aceitar e que os usuários passem qualquer número de argumentos, posicional ( *) e palavra-chave ( **).

Definindo Funções

*argspermite qualquer número de argumentos posicionais opcionais (parâmetros), que serão atribuídos a uma tupla chamada args.

**kwargspermite qualquer número de argumentos opcionais de palavra-chave (parâmetros), que estarão em um ditado chamado kwargs.

Você pode (e deve) escolher qualquer nome apropriado, mas se a intenção é que os argumentos sejam de semântica não específica argse kwargssejam nomes padrão.

Expansão, passando qualquer número de argumentos

Você também pode usar *argse **kwargspassar parâmetros de listas (ou qualquer iterável) e dictos (ou qualquer mapeamento), respectivamente.

A função que recebe os parâmetros não precisa saber que eles estão sendo expandidos.

Por exemplo, o xrange do Python 2 não espera explicitamente *args, mas como ele usa 3 números inteiros como argumentos:

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

Como outro exemplo, podemos usar a expansão dict em str.format:

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

Novo no Python 3: Definindo funções com argumentos apenas de palavras-chave

Você pode ter argumentos apenas de palavras-chave depois de *args- por exemplo, aqui, kwarg2deve ser fornecido como um argumento de palavras-chave - não em posição:

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

Uso:

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

Além disso, *pode ser usado por si só para indicar que somente os argumentos de palavra-chave seguem, sem permitir argumentos posicionais ilimitados.

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

Aqui, kwarg2novamente , deve haver um argumento de palavra-chave explicitamente nomeado:

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

E não podemos mais aceitar argumentos posicionais ilimitados porque não temos *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

Mais uma vez, de forma mais simples, aqui precisamos kwargser nomeados, não posicionalmente:

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

Neste exemplo, vemos que, se tentarmos passar kwargposicionalmente, obtemos um erro:

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

Devemos passar explicitamente o kwargparâmetro como um argumento de palavra-chave.

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

Demonstrações compatíveis com Python 2

*args(tipicamente dito "star-args") e **kwargs(estrelas podem ser implícitas dizendo "kwargs", mas seja explícito com "starwar kwargs") são expressões comuns do Python para usar a notação *e **. Esses nomes de variáveis ​​específicos não são necessários (por exemplo, você pode usar *foose **bars), mas uma saída da convenção provavelmente enfurecerá seus colegas codificadores Python.

Normalmente, usamos isso quando não sabemos o que nossa função receberá ou quantos argumentos podemos estar passando e, às vezes, mesmo ao nomear cada variável separadamente, fica muito confuso e redundante (mas este é um caso em que geralmente é explícito). melhor que implícito).

Exemplo 1

A função a seguir descreve como eles podem ser usados ​​e demonstra comportamento. Observe que o bargumento nomeado será consumido pelo segundo argumento posicional antes:

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

Podemos verificar a ajuda online da assinatura da função, com help(foo), o que nos diz

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

Vamos chamar essa função com foo(1, 2, 3, 4, e=5, f=6, g=7)

que imprime:

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}

Exemplo 2

Também podemos chamá-lo usando outra função, na qual apenas fornecemos 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) impressões:

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}

Exemplo 3: uso prático em decoradores

OK, então talvez ainda não estejamos vendo o utilitário. Imagine que você tenha várias funções com código redundante antes e / ou depois do código de diferenciação. As seguintes funções nomeadas são apenas pseudocódigo para fins ilustrativos.

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

Podemos ser capazes de lidar com isso de maneira diferente, mas certamente podemos extrair a redundância com um decorador; portanto, nosso exemplo abaixo demonstra como *argse **kwargspode ser muito útil:

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

E agora todas as funções agrupadas podem ser escritas de maneira muito mais sucinta, como consideramos a redundância:

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

E, considerando o nosso código, o que *argse o **kwargsque nos permite fazer, reduzimos as linhas de código, melhoramos a legibilidade e a capacidade de manutenção e temos únicos locais canônicos para a lógica do nosso programa. Se precisarmos alterar qualquer parte dessa estrutura, teremos um lugar para fazer cada alteração.

Aaron Hall
fonte
48

Vamos primeiro entender o que são argumentos posicionais e argumentos de palavras-chave. Abaixo está um exemplo de definição de função com argumentos posicionais.

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

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

Portanto, esta é uma definição de função com argumentos posicionais. Você também pode chamá-lo com argumentos de palavra-chave / nomeados:

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

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

Agora vamos estudar um exemplo de definição de função com argumentos de palavra - chave :

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

Você também pode chamar essa função com argumentos posicionais:

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

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

Portanto, agora conhecemos as definições de função com argumentos posicionais e de palavras-chave.

Agora vamos estudar o operador '*' e o operador '**'.

Observe que esses operadores podem ser usados ​​em 2 áreas:

a) chamada de função

b) definição de função

O uso do operador '*' e do operador '**' na chamada de função.

Vamos direto a um exemplo e depois discutimos.

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.

Então lembre

quando o operador '*' ou '**' é usado em uma chamada de função -

O operador '*' descompacta a estrutura de dados, como uma lista ou tupla, nos argumentos necessários para a definição da função.

O operador '**' descompacta um dicionário nos argumentos necessários para a definição da função.

Agora vamos estudar o uso do operador '*' na definição de função . Exemplo:

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

Na definição da função, o operador '*' agrupa os argumentos recebidos em uma tupla.

Agora vamos ver um exemplo de '**' usado na definição de função:

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

Na definição da função O operador '**' agrupa os argumentos recebidos em um dicionário.

Então lembre:

Em uma chamada de função, o '*' descompacta a estrutura de dados da tupla ou da lista em argumentos posicionais ou de palavras-chave a serem recebidos pela definição da função.

Em uma chamada de função, o '**' descompacta a estrutura de dados do dicionário em argumentos posicionais ou de palavras-chave a serem recebidos pela definição da função.

Em uma definição de função, o '*' agrupa argumentos posicionais em uma tupla.

Em uma definição de função, o '**' agrupa os argumentos da palavra-chave em um dicionário.

Karan Ahuja
fonte
Realmente limpo, passo a passo e fácil de seguir explicação!
Aleksandar
obrigado Mantenha as votações chegando. [Também para mais anotações minhas, estou no @mrtechmaker no twitter]
Karan Ahuja
32

Esta tabela é útil para usar *e **na construção de funções e chamada de função :

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

Isso realmente serve apenas para resumir a resposta de Lorin Hochstein, mas acho útil.

De maneira semelhante: os usos para os operadores estrela / splat foram expandidos no Python 3

Brad Solomon
fonte
22

*e **tem uso especial na lista de argumentos da função. * implica que o argumento é uma lista e **implica que o argumento é um dicionário. Isso permite que as funções recebam um número arbitrário de argumentos

ronak
fonte
17

Para aqueles de vocês que aprendem por exemplos!

  1. O objetivo de * é fornecer a capacidade de definir uma função que pode receber um número arbitrário de argumentos fornecidos como uma lista (por exemplo f(*myList)).
  2. O objetivo de **é fornecer a capacidade de alimentar os argumentos de uma função, fornecendo um dicionário (por exemplo f(**{'x' : 1, 'y' : 2})).

Vamos mostrar isso definindo uma função que leva duas variáveis normais x, ye pode aceitar mais argumentos como myArgs, e pode aceitar ainda mais argumentos como myKW. Mais tarde, mostraremos como alimentar yusando 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   = {}
# ----------------------------------------------------------------------

Ressalvas

  1. ** está reservado exclusivamente para dicionários.
  2. A atribuição de argumento não opcional acontece primeiro.
  3. Você não pode usar um argumento não opcional duas vezes.
  4. Se aplicável, **deve vir depois *, sempre.
Miladiouss
fonte
14

Na documentação do Python:

Se houver mais argumentos posicionais do que espaços de parâmetros formais, uma exceção TypeError será gerada, a menos que um parâmetro formal usando a sintaxe "* identificador" esteja presente; nesse caso, esse parâmetro formal recebe uma tupla contendo os argumentos posicionais em excesso (ou uma tupla vazia se não houver argumentos posicionais em excesso).

Se algum argumento de palavra-chave não corresponder a um nome formal de parâmetro, uma exceção TypeError será gerada, a menos que um parâmetro formal usando a sintaxe "** identificador" esteja presente; nesse caso, esse parâmetro formal recebe um dicionário que contém os argumentos de excesso de palavras-chave (usando as palavras-chave como chaves e os valores de argumento como valores correspondentes) ou um (novo) dicionário vazio se não houver argumentos de excesso de palavras-chave.

Chris Upchurch
fonte
10

* significa receber argumentos variáveis ​​como tupla

** significa receber argumentos variáveis ​​como dicionário

Usado como o seguinte:

1) solteiro *

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

foo("two", 3)

Resultado:

two
3

2) Agora **

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

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

Resultado:

dic1 two
dic2 3
ishandutta2007
fonte
8

Eu quero dar um exemplo que outros não mencionaram

* também pode desembalar um gerador

Um exemplo do documento Python3

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

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

unzip_x será [1, 2, 3], unzip_y será [4, 5, 6]

O zip () recebe vários argumentos irretáveis ​​e retorna um gerador.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))
Lochu'an Chang
fonte
7

Em Python 3.5, você também pode usar essa sintaxe em list, dict, tuplee setexibe (também às vezes chamados de literais). Consulte PEP 488: Generalizações adicionais de desempacotamento .

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

Ele também permite que vários iteráveis ​​sejam descompactados em uma única chamada de função.

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

(Obrigado a mgilson pelo link do PEP.)

leewz
fonte
1
Não tenho certeza se isso é uma violação de "só há uma maneira de fazer isso". Não há outra maneira de inicializar uma lista / tupla a partir de várias iteráveis ​​- você atualmente precisa encadeá-las em uma única iterável, o que nem sempre é conveniente. Você pode ler sobre o racional em PEP-0448 . Além disso, este não é um recurso python3.x, é um recurso python3.5 + :-).
mgilson
@ mgilson, isso explicaria por que não foi mencionado antes.
leewz
6

Além das chamadas de função, * args e ** kwargs são úteis nas hierarquias de classes e também evitam a necessidade de escrever o __init__método no Python. Uso semelhante pode ser visto em estruturas como o código Django.

Por exemplo,

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

Uma subclasse pode então ser

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

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

A subclasse será instanciada como

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

Além disso, uma subclasse com um novo atributo que faça sentido apenas para essa instância da subclasse pode chamar a classe Base __init__para descarregar a configuração de atributos. Isso é feito através de * args e ** kwargs. kwargs usado principalmente para que o código seja legível usando argumentos nomeados. Por exemplo,

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)

que pode ser instatado como

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

O código completo está aqui

quiet_penguin
fonte
1
1. Basicamente, init é um método, portanto (neste contexto) não é realmente diferente. 2. Use # para comentários, não """, que apenas marca strings literais 3. Usando Super deve ser a forma preferida, especialmente para o seu exemplo com a herança multi-nível..
0xc0de
4

Com base na resposta de nickd ...

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)

Resultado:

1
(2, 3, 4, 5)

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

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

Basicamente, qualquer número de argumentos posicionais pode usar * args e qualquer argumento nomeado (ou kwargs, também conhecido como argumento de palavra-chave) pode usar ** kwargs.

Raj
fonte
3

*argse **kwargs: permitem passar um número variável de argumentos para uma função.

*args: é usado para enviar uma lista de argumentos de comprimento variável sem palavra-chave para a função:

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

Vai produzir:

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*

**kwargspermite que você passe o comprimento variável de argumentos com palavras-chave para uma função. Você deve usar **kwargsse desejar manipular argumentos nomeados em uma função.

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

Vai produzir:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
Harvey
fonte
2

Este exemplo ajudaria você a se lembrar *args, **kwargse mesmo supere herança no Python de uma só vez.

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
thanhtang
fonte
1

Um bom exemplo de uso de ambos em uma função é:

>>> 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')
{}
amir jj
fonte
1

TL; DR

Abaixo estão 6 casos de uso diferentes para *e **na programação python:

  1. Para aceitar qualquer número de argumentos posicionais usando *args: def foo(*args): pass , aqui fooaceita qualquer número de argumentos posicionais, ou seja, as seguintes chamadas são válidos foo(1),foo(1, 'bar')
  2. Para aceitar qualquer número de argumentos de palavra-chave usando **kwargs: def foo(**kwargs): pass , aqui 'foo' aceita qualquer número de argumentos de palavra-chave, ou seja, as seguintes chamadas são válidos foo(name='Tom'),foo(name='Tom', age=33)
  3. Para aceitar qualquer número de argumentos posicionais e usando *args, **kwargs: def foo(*args, **kwargs): pass , aqui fooaceita qualquer número de argumentos posicionais e, ou seja, as seguintes chamadas são válidos foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Para reforçar palavra-chave únicos argumentos usando *: def foo(pos1, pos2, *, kwarg1): pass , aqui *significa que foo só aceitam argumentos nomeados após pos2, portanto, foo(1, 2, 3)levanta TypeError mas foo(1, 2, kwarg1=3)é ok.
  5. Para expressar nenhum interesse adicional em mais argumentos posicionais usando *_(Nota: esta é apenas uma convenção): def foo(bar, baz, *_): pass significa (por convenção) fooapenas usa bare bazargumentos em seu funcionamento e ignorará outros.
  6. Para expressar nenhum interesse adicional em mais argumentos de palavras-chave usando \**_(Nota: esta é apenas uma convenção): def foo(bar, baz, **_): pass significa (por convenção) fooapenas usa bare bazargumentos em seu funcionamento e ignorará outros.

BÔNUS: A partir do python 3.8 em diante, pode-se usar /na definição de funções para aplicar apenas parâmetros posicionais. No exemplo a seguir, os parâmetros aeb são apenas posicionais , enquanto c ou d podem ser posicionais ou palavra-chave, e e ou f devem ser palavras-chave:

def f(a, b, /, c, d, *, e, f):
    pass
Meysam Sadeghi
fonte
0

TL; DR

Empacota os argumentos passados ​​para a função dentro liste dictrespectivamente dentro do corpo da função. Quando você define uma assinatura de função como esta:

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

pode ser chamado com qualquer número de argumentos e argumentos de palavras-chave. Os argumentos que não são de palavra-chave são compactados em uma lista chamada argsdentro do corpo da função e os argumentos de palavra-chave são compactados em um ditado chamado kwdsdentro do corpo da função.

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

agora dentro do corpo da função, quando a função é chamada, há duas variáveis ​​locais, args que é uma lista com valor ["this", "is a list of", "non-keyword", "arguments"]e kwdsque é um dictvalor com{"keyword" : "ligma", "options" : [1,2,3]}


Isso também funciona ao contrário, ou seja, do lado do chamador. por exemplo, se você tiver uma função definida como:

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

você pode chamá-lo descompactando iterables ou mapeamentos existentes no escopo da chamada:

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)
RBF06
fonte
0

Contexto

  • python 3.x
  • desembalar com **
  • use com formatação de string

Use com formatação de string

Além das respostas neste tópico, aqui está outro detalhe que não foi mencionado em nenhum outro lugar. Isso se expande no resposta de Brad Solomon

Descompactar **também é útil ao usar pythonstr.format .

Isso é um pouco semelhante ao que você pode fazer com o python f-strings f-string mas com a sobrecarga adicional de declarar um dict para conter as variáveis ​​(a string f não exige um dict).

Exemplo rápido

  ## 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])
dreftymac
fonte
-2
  • def foo(param1, *param2):é um método que pode aceitar um número arbitrário de valores para *param2,
  • def bar(param1, **param2): é um método que pode aceitar um número arbitrário de valores com chaves para *param2
  • param1 é um parâmetro simples.

Por exemplo, a sintaxe para implementar varargs em Java da seguinte maneira:

accessModifier methodName(datatype arg) {
    // method body
}
Premraj
fonte