Question

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

def foo(param1, *param2):
def bar(param1, **param2):
Était-ce utile?

La solution

Le *args et **kwargs est un idiome courant pour autoriser un nombre arbitraire d'arguments aux fonctions comme décrit dans la section en savoir plus sur la définition des fonctions dans la documentation Python.

Le *args vous donnera tous les paramètres de fonction comme un 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 je te donnerai toutarguments de mots-clés sauf ceux correspondant à un paramètre formel comme un 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

Une autre utilisation du *l l'idiome est de décompresser 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 itérable étendu), 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 (voir PEP 3102):

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

Une telle fonction n'accepte que 3 arguments de position, et tout ce qui suit * ne peuvent être transmis que comme arguments de mot-clé.

Autres conseils

Il convient également de noter que vous pouvez utiliser * et ** lors de l'appel de fonctions également.Il s'agit d'un raccourci qui vous permet de transmettre plusieurs arguments à une fonction directement en utilisant soit une liste/tuple, soit 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 dans mydict doivent être nommés exactement comme les paramètres de la fonction foo.Sinon, il lancera 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'

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

Le double ** signifie qu'il peut y avoir n'importe quel nombre de paramètres nommés supplémentaires. bar() peut être invoqué comme bar(1, a=2, b=3).Dans le corps de bar(), param2 se trouve 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}

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

Ils permettent fonctions à définir pour accepter et pour les utilisateurs doivent passer n'importe quel nombre d'arguments, positionnels (*) et le mot-clé (**).

Définir des fonctions

*args autorise n'importe quel nombre d'arguments de position facultatifs (paramètres), qui seront attribués à un tuple nommé args.

**kwargs autorise n'importe quel nombre d'arguments de mots-clés facultatifs (paramètres), qui seront dans un dict nommé kwargs.

Vous pouvez (et devez) choisir n'importe quel nom approprié, mais si l'intention est que les arguments aient une 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 pour transmettre les paramètres des listes (ou de tout itérable) et des dicts (ou de tout mappage), respectivement.

La fonction qui reçoit les paramètres n'a pas besoin de savoir qu'ils sont développés.

Par exemple, xrange de Python 2 n'attend pas explicitement *args, mais comme 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 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éfinir des fonctions avec des arguments de mots clés uniquement

Vous pouvez avoir arguments de mot-clé uniquement après le *args - par exemple, ici, kwarg2 doit être donné comme argument de mot-clé - et non de manière positionnelle :

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é seul pour indiquer que seuls les arguments de mots clés suivent, sans autoriser des arguments de position illimités.

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

Ici, kwarg2 encore une fois, il doit s'agir d'un argument de mot-clé explicitement nommé :

>>> 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 avons besoin ici kwarg à donner par son nom, et non par sa position :

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

Dans cet exemple, on voit que si on essaie 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 comme argument de mot-clé.

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

Démos compatibles Python 2

*args (généralement appelé "star-args") et **kwargs (les étoiles peuvent être sous-entendues en disant "kwargs", mais soyez explicite avec "kwargs à double étoile") sont des idiomes courants de Python pour utiliser le * et ** notation.Ces noms de variables spécifiques ne sont pas obligatoires (par ex.tu pourrais utiliser *foos et **bars), mais une dérogation aux conventions risque de faire enrager vos collègues codeurs Python.

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

Exemple 1

La fonction suivante décrit comment elles peuvent être utilisées et démontre leur comportement.Notez le nom b L'argument sera consommé par le deuxième 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 consulter l'aide en ligne pour la signature de la fonction, avec help(foo), ce 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 fournissons simplement 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) tirages :

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 chez les décorateurs

OK, alors peut-être que nous ne voyons pas encore l'utilitaire.Imaginez donc que vous ayez plusieurs fonctions avec du code redondant avant et/ou après le code différenciateur.Les fonctions nommées suivantes ne sont que 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 peut-être gérer cela différemment, mais nous pouvons certainement extraire la redondance avec un décorateur, et notre exemple ci-dessous montre donc 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 encapsulée peut être écrite de manière beaucoup plus succincte, 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 factorisant 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 disposons d'emplacements canoniques uniques pour la logique dans notre programme.Si nous devons modifier une partie de cette structure, nous disposons d’un seul endroit où effectuer chaque modification.

Comprenons d'abord ce que sont les arguments de position et les arguments de mots-clés.Ci-dessous un exemple de définition de fonction avec Arguments positionnels.

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

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

Il s'agit donc d'une définition de fonction avec des arguments de position.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

Étudions maintenant un exemple de définition de fonction avec arguments de mots-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 de position :

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 donc maintenant les définitions de fonctions avec des arguments de position ainsi que des mots-clés.

Etudions maintenant l'opérateur '*' et l'opérateur '**'.

Attention, ces opérateurs peuvent être utilisés dans 2 domaines :

un) appel de fonction

b) définition de fonction

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

Passons directement à un exemple et discutons-en ensuite.

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écompresse 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.

Etudions maintenant l'utilisation de l'opérateur '*' dans définition de 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 '*' regroupe les arguments reçus dans un tuple.

Voyons maintenant un exemple de '**' utilisé dans la définition de 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 le '*' déballe structure de données d'un tuple ou d'une liste en arguments de position ou de mot-clé à recevoir par définition de fonction.

Dans un appel de fonction le '**' déballe 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 fonction le '*' paquets arguments de position dans un tuple.

Dans un définition de fonction le '**' paquets arguments de mots-clés dans un dictionnaire.

* et ** ont 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 d'arguments

Alors que les utilisations des opérateurs étoile/éclaboussure ont été étendu en Python 3, j'aime le tableau suivant car il 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 ne sert en réalité qu'à résumer le discours de Lorin Hochstein répondre mais je trouve cela utile.

Pour ceux d'entre vous qui apprennent par des exemples !

  1. Le but de * est de vous donner la possibilité de définir une fonction qui peut prendre un nombre arbitraire d'arguments fournis sous forme de liste (par ex. f(*myList) ).
  2. Le but de ** est de vous donner la possibilité d'alimenter les arguments d'une fonction en fournissant un dictionnaire (par ex. f(**{'x' : 1, 'y' : 2}) ).

Montrons cela en définissant une fonction qui prend deux variables normales x, y, et peut accepter plus d'arguments comme myArgs, et peut accepter encore plus d'arguments comme myKW.Plus tard, nous montrerons comment nourrir y en utilisant 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   = {}
# ----------------------------------------------------------------------

Mises en garde

  1. ** est exclusivement réservé aux dictionnaires.
  2. L'attribution d'arguments non facultatifs se produit en premier.
  3. Vous ne pouvez pas utiliser deux fois un argument non facultatif.
  4. Le cas échéant, ** doit venir après *, toujours.

Extrait de la documentation Python :

S'il y a plus d'arguments de position qu'il n'y a d'emplacements de paramètres formels, une exception TypeError est levée, à moins qu'un paramètre formel utilisant la syntaxe "*identifier" ne soit présent ;dans ce cas, ce paramètre formel reçoit un tuple contenant les arguments de position en excès (ou un tuple vide s'il n'y avait pas d'arguments de position en excès).

Si un argument de mot-clé ne correspond pas à un nom de paramètre formel, une exception TypeError est levée, à moins qu'un paramètre formel utilisant la syntaxe "**identifier" ne soit présent ;dans ce cas, ce paramètre formel reçoit un dictionnaire contenant les arguments de mot-clé 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 avait pas d'arguments de mot-clé en excès.

Dans Python 3.5, vous pouvez également utiliser cette syntaxe dans list, dict, tuple, et set affichages (également parfois appelés littéraux).Voir PEP 488 :Généralisations supplémentaires sur le 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érables en un seul appel de fonction.

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

(Merci à mgilson pour le lien PEP.)

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

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

Un exemple du document Python3

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 zip() reçoit plusieurs arguments iretable et renvoie un générateur.

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

En plus des appels de fonction, *args et **kwargs sont utiles dans les hiérarchies de classes et évitent également d'avoir à écrire __init__ méthode en Python.Une utilisation similaire peut être observée 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 sera alors instanciée comme

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

De plus, 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.Cela se fait via *args et **kwargs.kwargs est principalement utilisé pour que le code soit lisible à l'aide d'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 instauré 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

* signifie recevoir des arguments variables sous forme de liste

** signifie recevoir des arguments variables sous forme de dictionnaire

Utilisé comme suit :

1) célibataire *

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

foo("two", 3)

Sortir:

two
3

2) Maintenant **

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

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

Sortir:

dic1 two
dic2 3

Un bon exemple d’utilisation des deux dans une fonction est :

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

Cet exemple vous aiderait à vous souvenir *args, **kwargs et même super et l'héritage en Python à la fois.

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

TL;DR

Il regroupe les arguments passés à la fonction dans list et dict respectivement à l’intérieur du corps de fonction.Lorsque vous définissez une signature de fonction comme celle-ci :

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

il peut être appelé avec n'importe quel nombre d'arguments et d'arguments de mots-clés.Les arguments non-mots-clés sont regroupés dans une liste appelée args à l'intérieur du corps de la fonction et les arguments des mots-clés sont regroupés dans un dict appelé kwds à l'intérieur du corps de fonction.

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

maintenant, à l'intérieur du corps de la fonction, lorsque la fonction est appelée, il y a deux variables locales, args qui est une liste ayant une valeur ["this", "is a list of", "non-keyword", "arguments"] et kwds qui est un dict ayant de la valeur {"keyword" : "ligma", "options" : [1,2,3]}


Cela fonctionne également à l'envers, c'est-à-diredu côté de l'appelant.par exemple si vous avez une fonction définie comme :

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

vous pouvez l'appeler en décompressant les itérables ou les mappages que vous avez dans la portée appelante :

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)

*args et **kwargs:permettent de passer un nombre variable d'arguments à une fonction.

*args:est utilisé pour envoyer une liste d'arguments de longueur variable sans mot-clé à la fonction :

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

Produira:

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*

**kwargs vous permet de transmettre des arguments de longueur variable avec mots-clés à une fonction.Tu devrais utiliser **kwargs si vous souhaitez gérer des arguments nommés dans une fonction.

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

Produira:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
  • def foo(param1, *param2): est une méthode qui peut accepter un nombre arbitraire de valeurs pour *param2,
  • def bar(param1, **param2): est une méthode qui peut accepter un nombre arbitraire de valeurs avec des clés pour *param2
  • param1 est un paramètre simple.

Par exemple, la syntaxe pour implémenter varargs en Java comme suit :

accessModifier methodName(datatype… arg) {
    // method body
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top