原文:『実用的なPythonプログラミング』07_01_Variable_arguments

5811 ワード

目次|前節(6.4ジェネレータ式)|[次節(7.2匿名関数)]()
7.1可変パラメータ
このセクションでは、可変(variadic)パラメータについて説明します.可変パラメータは、*argsおよび**kwargsで表される場合がある.
可変位置パラメータ(*args)
1つの関数が任意の数の(位置)パラメータを受け入れる場合,この関数は可変パラメータ(variable arguments)を用いたと呼ぶ.例:
def f(x, *args):
    ...

関数呼び出し:
f(1,2,3,4,5)

追加のパラメータをタプルとして渡します.
def f(x, *args):
    # x -> 1
    # args -> (2,3,4,5)

可変キーワードパラメータ(**kwargs)
1つの関数は、任意の数のキーワードパラメータを受け入れることもできます.例:
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' }

可変位置パラメータと可変キーワードパラメータを組み合わせて使用
1つの関数は、可変非キーワードパラメータと可変キーワードパラメータを同時に受け入れることができます.
def f(*args, **kwargs):
    ...

関数呼び出し:
f(2, 3, flag=True, mode='fast', header='debug')

これらのパラメータは、位置パラメータとキーワードパラメータの2つの部分に分けられます.
def f(*args, **kwargs):
    # args = (2, 3)
    # kwargs -> { 'flag': True, 'mode': 'fast', 'header': 'debug' }
    ...

上記の関数は、任意の数の位置パラメータとキーワードパラメータを受け入れます.ラップ(wrappers)を作成したり、パラメータを別の関数に渡したりするときに使用します.
メタグループと辞書の転送
タプルは可変パラメータに拡張できます.
numbers = (2,3,4)
f(1, *numbers)      # Same as f(1,2,3,4)

辞書はキーワードパラメータに拡張することもできます.
options = {
    'color' : 'red',
    'delimiter' : ',',
    'width' : 400
}
f(data, **options)
# Same as 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 "", line 1, in 
TypeError: __init__() takes exactly 4 arguments (2 given)
>>>

この問題は簡単に解決できるので、*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('Data/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('Data/missing.csv', silence_errors=True)
>>>

目次|前節(6.4ジェネレータ式)|[次節(7.2匿名関数)]()
注:完全な翻訳はhttps://github.com/codists/practical-python-zhを参照