Аргументы переменной длины в функциях Python

Beginner

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

Введение

В этом разделе рассматриваются переменные аргументы функции, иногда называемые *args и **kwargs.

Позиционные переменные аргументы (*args)

Функция, которая принимает любое количество аргументов, считается, что использует переменные аргументы. Например:

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

Вызов функции.

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

Дополнительные аргументы передаются в виде кортежа.

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

Ключевые переменные аргументы (**kwargs)

Функция также может принимать любое количество ключевых аргументов. Например:

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

Вызов функции.

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

Дополнительные ключевые слова передаются в виде словаря.

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

Комбинирование обоих

Функция также может принимать любое количество переменных ключевых и неключевых аргументов.

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

Вызов функции.

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

Аргументы разделяются на позиционные и ключевые компоненты

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

Эта функция принимает любую комбинацию позиционных или ключевых аргументов. Она иногда используется при написании оберток или когда вы хотите передать аргументы в другую функцию.

Передача кортежей и словарей

Кортежи можно расширять в переменные аргументы.

numbers = (2,3,4)
f(1, *numbers)      ## То же, что и f(1,2,3,4)

Словари также можно расширять в ключевые аргументы.

options = {
    'color' : 'red',
    'delimiter' : ',',
    'width' : 400
}
f(data, **options)
## То же, что и f(data, color='red', delimiter=',', width=400)

Упражнение 7.1: Простой пример с переменными аргументами

Попробуйте определить следующую функцию:

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

Заметьте, как параметр *more собирает все дополнительные аргументы.

Упражнение 7.2: Передача кортежей и словарей в качестве аргументов

Предположим, что вы прочитали некоторые данные из файла и получили кортеж такого вида:

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

Теперь, предположим, что вы хотели создать объект Stock из этих данных. Если вы попытаетесь передать data напрямую, это не сработает:

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

Это легко исправить, используя *data вместо этого. Попробуйте это:

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

Если у вас есть словарь, вы можете использовать ** вместо этого. Например:

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

Упражнение 7.3: Создание списка экземпляров

В вашей программе report.py вы создавали список экземпляров с помощью кода такого вида:

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)

Вы можете упростить этот код, используя Stock(**d) вместо этого. Примените это изменение.

Упражнение 7.4: Пропуск аргументов

Функция fileparse.parse_csv() имеет некоторые параметры для изменения разделителя файла и для отчета об ошибках. Возможно, вы хотите предоставить эти параметры для функции read_portfolio() выше. Примените следующие изменения:

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)

После внесения изменений попробуйте прочитать файл с некоторыми ошибками:

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

Теперь, попробуйте подавить ошибки:

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

Резюме

Поздравляем! Вы завершили лабораторную работу по Переменным аргументам. Вы можете практиковаться в более многих лабораторных работах в LabEx, чтобы улучшить свои навыки.