Arguments de fonction variadiques en Python

Beginner

This tutorial is from open-source community. Access the source code

Introduction

Cette section traite des arguments de fonction variadiques, parfois décrits comme *args et **kwargs.

Arguments variables positionnels (*args)

Une fonction qui accepte n'importe quel nombre d'arguments est dite utiliser des arguments variables. Par exemple :

def f(x, *args):
  ...

Appel de fonction.

f(1,2,3,4,5)

Les arguments supplémentaires sont passés sous forme de tuple.

def f(x, *args):
    ## x -> 1
    ## args -> (2,3,4,5)

Arguments variables de mot clé (**kwargs)

Une fonction peut également accepter un nombre quelconque d'arguments de mot clé. Par exemple :

def f(x, y, **kwargs):
 ...

Appel de fonction.

f(2, 3, flag=True, mode='fast', header='debug')

Les mots clés supplémentaires sont passés dans un dictionnaire.

def f(x, y, **kwargs):
    ## x -> 2
    ## y -> 3
    ## kwargs -> { 'flag': True,'mode': 'fast', 'header': 'debug' }

Combiner les deux

Une fonction peut également accepter un nombre quelconque d'arguments variables de mot clé et d'arguments non de mot clé.

def f(*args, **kwargs):
...

Appel de fonction.

f(2, 3, flag=True, mode='fast', header='debug')

Les arguments sont séparés en composants positionnels et de mot clé

def f(*args, **kwargs):
    ## args = (2, 3)
    ## kwargs -> { 'flag': True,'mode': 'fast', 'header': 'debug' }
  ...

Cette fonction prend toute combinaison d'arguments positionnels ou de mot clé. Elle est parfois utilisée lorsqu'on écrit des wrappers ou lorsqu'on veut passer des arguments à une autre fonction.

Passer des tuples et des dictionnaires

Les tuples peuvent être décomposés en arguments variables.

numbers = (2,3,4)
f(1, *numbers)      ## Identique à f(1,2,3,4)

Les dictionnaires peuvent également être décomposés en arguments de mot clé.

options = {
    'couleur' : 'rouge',
    'délimiteur' : ',',
    'largeur' : 400
}
f(data, **options)
## Identique à f(data, couleur='rouge', délimiteur=',', largeur=400)

Exercice 7.1 : Un exemple simple d'arguments variables

Essayez de définir la fonction suivante :

>>> def avg(x,*more):
        return float(x+sum(more))/(1+len(more))

>>> avg(10,11)
10.5
>>> avg(3,4,5)
4.0
>>> avg(1,2,3,4,5,6)
3.5
>>>

Remarquez comment le paramètre *more collecte tous les arguments supplémentaires.

Exercice 7.2 : Passer des tuples et des dictionnaires en tant qu'arguments

Supposons que vous lisez des données à partir d'un fichier et que vous obteniez un tuple comme celui-ci :

>>> data = ('GOOG', 100, 490.1)
>>>

Maintenant, supposons que vous vouliez créer un objet Stock à partir de ces données. Si vous essayez de passer data directement, cela ne fonctionne pas :

>>> from stock import Stock
>>> s = Stock(data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Stock.__init__() missing 2 required positional arguments:'shares' and 'price'
>>>

Cela est facilement corrigé en utilisant *data à la place. Essayez ceci :

>>> s = Stock(*data)
>>> s
Stock('GOOG', 100, 490.1)
>>>

Si vous avez un dictionnaire, vous pouvez utiliser ** à la place. Par exemple :

>>> data = { 'name': 'GOOG','shares': 100, 'price': 490.1 }
>>> s = Stock(**data)
Stock('GOOG', 100, 490.1)
>>>

Exercice 7.3 : Création d'une liste d'instances

Dans votre programme report.py, vous avez créé une liste d'instances en utilisant du code comme ceci :

def read_portfolio(filename):
    '''
    Lit un fichier de portefeuille d'actions dans une liste de dictionnaires avec les clés
    name, shares et price.
    '''
    with open(filename) as lines:
        portdicts = fileparse.parse_csv(lines,
                               select=['name','shares','price'],
                               types=[str,int,float])

    portfolio = [ Stock(d['name'], d['shares'], d['price'])
                  for d in portdicts ]
    return Portfolio(portfolio)

Vous pouvez simplifier ce code en utilisant Stock(**d) à la place. Apportez ce changement.

Exercice 7.4 : Passer à travers les arguments

La fonction fileparse.parse_csv() a quelques options pour changer le délimiteur de fichier et pour la notification d'erreurs. Peut-être que vous voudriez exposer ces options à la fonction read_portfolio() ci-dessus. Apportez ce changement :

def read_portfolio(filename, **opts):
    '''
    Lit un fichier de portefeuille d'actions dans une liste de dictionnaires avec les clés
    name, shares et price.
    '''
    with open(filename) as lines:
        portdicts = fileparse.parse_csv(lines,
                                        select=['name','shares','price'],
                                        types=[str,int,float],
                                        **opts)

    portfolio = [ Stock(**d) for d in portdicts ]
    return Portfolio(portfolio)

Une fois que vous avez apporté le changement, essayez de lire un fichier avec quelques erreurs :

>>> import report
>>> port = report.read_portfolio('missing.csv')
Row 4: Couldn't convert ['MSFT', '', '51.23']
Row 4: Reason invalid literal for int() with base 10: ''
Row 7: Couldn't convert ['IBM', '', '70.44']
Row 7: Reason invalid literal for int() with base 10: ''
>>>

Maintenant, essayez de silencer les erreurs :

>>> import report
>>> port = report.read_portfolio('missing.csv', silence_errors=True)
>>>

Sommaire

Félicitations ! Vous avez terminé le laboratoire sur les arguments variables. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.