Argumentos de Função Variádicos em Python

Beginner

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

Introdução

Esta seção aborda argumentos de função variádicos, às vezes descritos como *args e **kwargs.

Argumentos posicionais variáveis (*args)

Uma função que aceita qualquer número de argumentos diz-se que utiliza argumentos variáveis. Por exemplo:

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

Chamada da função.

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

Os argumentos extras são passados como uma tupla.

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

Argumentos variáveis de palavra-chave (**kwargs)

Uma função também pode aceitar qualquer número de argumentos de palavra-chave. Por exemplo:

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

Chamada da função.

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

As palavras-chave extras são passadas em um dicionário.

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

Combinando ambos

Uma função também pode aceitar qualquer número de argumentos variáveis de palavra-chave e não-palavra-chave.

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

Chamada da função.

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

Os argumentos são separados em componentes posicionais e de palavra-chave.

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

Esta função aceita qualquer combinação de argumentos posicionais ou de palavra-chave. É, por vezes, utilizada ao escrever wrappers ou quando se pretende passar argumentos para outra função.

Passando Tuplas e Dicionários

Tuplas podem ser expandidas em argumentos variáveis.

numbers = (2,3,4)
f(1, *numbers)      ## Same as f(1,2,3,4)

Dicionários também podem ser expandidos em argumentos de palavra-chave.

options = {
    'color' : 'red',
    'delimiter' : ',',
    'width' : 400
}
f(data, **options)
## Same as f(data, color='red', delimiter=',', width=400)

Exercício 7.1: Um exemplo simples de argumentos variáveis

Tente definir a seguinte função:

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

Note como o parâmetro *more coleta todos os argumentos extras.

Exercício 7.2: Passando tuplas e dicionários como argumentos

Suponha que você leu alguns dados de um arquivo e obteve uma tupla como esta:

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

Agora, suponha que você queira criar um objeto Stock a partir desses dados. Se você tentar passar data diretamente, não funciona:

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

Isso é facilmente corrigido usando *data em vez disso. Tente isto:

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

Se você tiver um dicionário, pode usar ** em vez disso. Por exemplo:

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

Exercício 7.3: Criando uma lista de instâncias

No seu programa report.py, você criou uma lista de instâncias usando código como este:

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and 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)

Você pode simplificar esse código usando Stock(**d) em vez disso. Faça essa alteração.

Exercício 7.4: Passagem de argumentos (Argument pass-through)

A função fileparse.parse_csv() tem algumas opções para alterar o delimitador de arquivo e para relatórios de erros. Talvez você queira expor essas opções para a função read_portfolio() acima. Faça esta alteração:

def read_portfolio(filename, **opts):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and 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)

Depois de fazer a alteração, tente ler um arquivo com alguns erros:

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

Agora, tente silenciar os erros:

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

Resumo

Parabéns! Você concluiu o laboratório de Argumentos Variáveis (Variable Arguments). Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.