Question Que fait ** (double étoile / astérisque) et * (étoile / astérisque) pour les paramètres?


Dans les définitions de méthodes suivantes, que fait le * et ** faire pour param2?

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

1574
2017-08-31 15:04


origine


Réponses:


le *args et **kwargs est un idiome commun pour permettre le nombre arbitraire d'arguments à des fonctions comme décrit dans la section plus sur la définition des fonctions dans la documentation Python.

le *args vous donnera tous les paramètres de la fonction en tant que tuple:

In [1]: def foo(*args):
   ...:     for a in args:
   ...:         print a
   ...:         
   ...:         

In [2]: foo(1)
1


In [4]: foo(1,2,3)
1
2
3

le **kwargs vous donnera tout arguments clés sauf pour ceux correspondant à un paramètre formel en tant que dictionnaire.

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

In [6]: bar(name='one', age=27)
age 27
name one

Les deux idiomes peuvent être mélangés avec des arguments normaux pour permettre un ensemble d'arguments fixes et variables:

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

Un autre usage de la *l idiome est de déballer les listes d'arguments lors de l'appel d'une fonction.

In [9]: def foo(bar, lee):
   ...:     print bar, lee
   ...:     
   ...:     

In [10]: l = [1,2]

In [11]: foo(*l)
1 2

En Python 3, il est possible d'utiliser *l sur le côté gauche d'une affectation (Déballage étendu itératif), bien qu'il donne une liste au lieu d'un tuple dans ce contexte:

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

Python 3 ajoute également une nouvelle sémantique PEP 3102):

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

Une telle fonction accepte seulement 3 arguments de position, et tout après * peut seulement être passé en tant qu'argument mot-clé.


1550
2017-08-31 15:17



Il est également intéressant de noter que vous pouvez utiliser * et ** lors de l'appel de fonctions aussi. C'est un raccourci qui vous permet de passer directement plusieurs arguments à une fonction en utilisant une liste / un tuple ou un dictionnaire. Par exemple, si vous avez la fonction suivante:

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

Vous pouvez faire des choses comme:

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

Note: Les clés de mydict doivent être nommés exactement comme les paramètres de la fonction foo. Sinon, il va jeter un 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'

448
2017-08-31 15:47



Le simple * signifie qu'il peut y avoir n'importe quel nombre d'arguments positionnels supplémentaires. foo() peut être invoqué comme foo(1,2,3,4,5). Dans le corps de foo (), param2 est une séquence contenant 2-5.

Le double ** signifie qu'il peut y avoir n'importe quel nombre de paramètres supplémentaires nommés. bar() peut être invoqué comme bar(1, a=2, b=3). Dans le corps de la barre (), param2 est un dictionnaire contenant {'a': 2, 'b': 3}

Avec le code suivant:

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)

la sortie est

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

128
2017-08-31 15:20



Qu'est-ce que ** (double étoile) et * (étoile) faire pour les paramètres

Ils permettent fonctions à définir pour accepter et pour les utilisateurs à passer un nombre quelconque d'arguments, positionnels (*) et mot-clé (**).

Définir des fonctions

*args permet un nombre illimité d'arguments positionnels (paramètres), qui seront assignés à un tuple nommé args.

**kwargs permet un nombre quelconque d'arguments (paramètres) optionnels, qui seront dans une dict nommée kwargs.

Vous pouvez (et devez) choisir n'importe quel nom approprié, mais si l'intention est que les arguments soient de sémantique non spécifique, args et kwargs sont des noms standards.

Expansion, Passage d'un nombre quelconque d'arguments

Vous pouvez aussi utiliser *args et **kwargs transmettre des paramètres à partir de listes (ou d'itérables) et de dicts (ou de toute correspondance), respectivement.

La fonction recevant les paramètres n'a pas besoin de savoir qu'ils sont en cours d'extension.

Par exemple, xrange de Python 2 n'attend pas explicitement *args, mais puisqu'il prend 3 entiers comme arguments:

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

Comme un autre exemple, nous pouvons utiliser l'expansion dict dans str.format:

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

Nouveau dans Python 3: Définition de fonctions avec des arguments uniquement pour les mots clés

Vous pouvez avoir Mots clés uniquement après le *args - Par exemple, ici, kwarg2 doit être donné comme un argument mot-clé - pas positionnellement:

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

Usage:

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

Aussi, * peut être utilisé par lui-même pour indiquer que les arguments du seul mot clé suivent, sans autoriser les arguments positionnels illimités.

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

Ici, kwarg2 à nouveau doit être un argument explicitement nommé, mot-clé:

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

Et nous ne pouvons plus accepter des arguments positionnels illimités parce que nous n'avons pas *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

Encore une fois, plus simplement, nous exigeons ici kwarg à donner par nom, pas de position:

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

Dans cet exemple, nous voyons que si nous essayons de passer kwarg positionnellement, nous obtenons une erreur:

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

Nous devons explicitement passer le kwarg paramètre en tant qu'argument mot-clé.

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

Démonstrations compatibles avec Python 2

*args (généralement dit "étoiles-args") et **kwargs (les étoiles peuvent être impliquées en disant "kwargs", mais être explicite avec "kwargs double-star") sont des idiomes courants de Python pour l'utilisation du * et ** notation. Ces noms de variables spécifiques ne sont pas obligatoires (par exemple, vous pouvez utiliser *foos et **bars), mais une dérogation à la convention risque d'irriter vos codeurs Python.

Nous les utilisons typiquement quand nous ne savons pas ce que notre fonction va recevoir ou le nombre d'arguments que nous pouvons transmettre, et parfois même lorsque nommer chaque variable séparément devient très désordonné et redondant (mais c'est un cas où généralement explicite est mieux qu'implicite).

Exemple 1

La fonction suivante décrit comment ils peuvent être utilisés et démontre un comportement. Notez le nom b argument sera consommé par le second argument positionnel avant:

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

Nous pouvons vérifier l'aide en ligne pour la signature de la fonction, avec help(foo), qui nous dit

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

Appelons cette fonction avec foo(1, 2, 3, 4, e=5, f=6, g=7) 

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

Exemple 2

Nous pouvons également l'appeler en utilisant une autre fonction, dans laquelle nous venons de fournir 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) impressions:

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}

Exemple 3: utilisation pratique dans les décorateurs

OK, alors peut-être que nous ne voyons pas l'utilité pour le moment. Alors imaginez que vous avez plusieurs fonctions avec un code redondant avant et / ou après le code de différenciation. Les fonctions nommées suivantes sont juste du pseudo-code à des fins d'illustration.

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

Nous pourrions être en mesure de gérer cela différemment, mais nous pouvons certainement extraire la redondance avec un décorateur, et ainsi notre exemple ci-dessous montre comment *args et **kwargs peut être très utile:

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

Et maintenant, chaque fonction enveloppée peut être écrite beaucoup plus succinctement, car nous avons pris en compte la redondance:

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

Et en prenant en compte notre code, qui *args et **kwargs nous permet de le faire, nous réduisons les lignes de code, améliorons la lisibilité et la maintenabilité, et avons des emplacements canoniques uniques pour la logique de notre programme. Si nous avons besoin de changer une partie de cette structure, nous avons un endroit où faire chaque changement.


105
2017-10-14 16:34



Laissez-nous d'abord comprendre ce que sont les arguments de position et les arguments de mot-clé. Voici un exemple de définition de fonction avec Arguments de position.

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

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

Donc, ceci est une définition de fonction avec des arguments positionnels. Vous pouvez également l'appeler avec des mots-clés / arguments nommés:

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

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

Maintenant, étudions un exemple de définition de fonction avec arguments clés:

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

Vous pouvez également appeler cette fonction avec des arguments positionnels:

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

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

Nous connaissons maintenant les définitions de fonctions avec des arguments positionnels et des mots-clés.

Maintenant étudions l'opérateur '*' et l'opérateur '**'.

Veuillez noter que ces opérateurs peuvent être utilisés dans deux domaines:

une) appel de fonction

b) définition de la fonction

L'utilisation de l'opérateur '*' et de l'opérateur '**' dans appel de fonction. 

Laissez-nous aller directement à un exemple et ensuite en discuter.

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.

Alors souviens-toi

lorsque l'opérateur '*' ou '**' est utilisé dans un appel de fonction -

L'opérateur '*' décompose la structure de données telle qu'une liste ou un tuple en arguments nécessaires à la définition de la fonction.

L'opérateur '**' décompresse un dictionnaire en arguments nécessaires à la définition de la fonction.

Maintenant, étudions l'utilisation de l'opérateur '*' dans définition de la fonction. Exemple:

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

En fonction définition l'opérateur '*' emballe les arguments reçus dans un tuple.

Voyons maintenant un exemple de '**' utilisé dans la définition de la fonction:

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

En fonction définition L'opérateur '**' regroupe les arguments reçus dans un dictionnaire.

Alors souviens-toi:

Dans un appel de fonction la '*' déballer structure de données de tuple ou liste dans des arguments de position ou de mot-clé à recevoir par définition de fonction.

Dans un appel de fonction la '**' déballer structure de données du dictionnaire en arguments de position ou de mot-clé à recevoir par définition de fonction.

Dans un définition de la fonction la '*' packs arguments positionnels dans un tuple.

Dans un définition de la fonction la '**' packs les mots-clés dans un dictionnaire.


37
2018-01-20 11:40



* et ** avoir une utilisation spéciale dans la liste des arguments de la fonction. * implique que l'argument est une liste et ** implique que l'argument est un dictionnaire. Cela permet aux fonctions de prendre un nombre arbitraire de arguments


20
2017-09-11 04:33



De la documentation Python:

S'il existe plus d'arguments positionnels que d'emplacements de paramètres formels, une exception TypeError est déclenchée, sauf si un paramètre formel utilisant la syntaxe "* identifier" est présent; dans ce cas, ce paramètre formel reçoit un tuple contenant les arguments positionnels en excès (ou un tuple vide s'il n'y a pas d'arguments positionnels en excès).

Si un argument mot-clé ne correspond pas à un nom de paramètre formel, une exception TypeError est déclenchée, sauf si un paramètre formel utilisant la syntaxe "** identifier" est présent; dans ce cas, ce paramètre formel reçoit un dictionnaire contenant les arguments de mots-clés en excès (en utilisant les mots-clés comme clés et les valeurs d'argument comme valeurs correspondantes), ou un (nouveau) dictionnaire vide s'il n'y a pas de mots-clés en excès.


11
2017-08-31 15:07



Je veux donner un exemple que d'autres n'ont pas mentionné

* peut également déballer un Générateur

Un exemple de Python3 Document

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

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

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

Le fichier zip () reçoit plusieurs arguments pouvant être mis en cache et renvoie un générateur.

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

7
2017-11-08 16:50



En Python 3.5, vous pouvez également utiliser cette syntaxe dans list, dict, tuple, et set affiche (également parfois appelé littéraux). Voir PEP 488: Généralisations supplémentaires de déballage.

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

Il permet également de décompresser plusieurs itérations dans un seul appel de fonction.

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

(Merci à mgilson pour le lien PEP.)


6
2017-12-08 21:38



Alors que les utilisations pour les opérateurs star / splat ont été étendu en Python 3, j'aime le tableau suivant en ce qui concerne l'utilisation de ces opérateurs avec des fonctions. Le ou les opérateurs splat peuvent être utilisés à la fois dans la fonction construction et dans la fonction appel:

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

Cela sert juste à résumer Lorin Hochstein répondre mais je trouve cela utile.


6
2017-11-30 18:28



En plus des appels de fonction, * args et ** kwargs sont utiles dans les hiérarchies de classe et évitent également d'avoir à écrire __init__ méthode en Python. Un usage similaire peut être vu dans des frameworks comme le code Django.

Par exemple,

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

Une sous-classe peut alors être

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

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

La sous-classe est ensuite instanciée

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

En outre, une sous-classe avec un nouvel attribut qui n'a de sens que pour cette instance de sous-classe peut appeler la classe Base __init__ pour décharger le paramètre d'attributs. Ceci est fait par * args et ** kwargs. kwargs est principalement utilisé pour que le code soit lisible en utilisant des arguments nommés. Par exemple,

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)

qui peut être institué comme

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

Le code complet est ici


3
2017-08-16 04:23