関数(5)--可変パラメータ

4779 ワード

第18条:可変数の位置パラメータで視覚雑音を減少する
まず、このような関数を見てみましょう.
def log(message, values):
    if not values:
        print(message)
    else:
        values_str = ''.join(str(x) for x in values)
        print('%s: %s' % (message, values_str))

log('My number are', [1, 2])
log('No number', [])
>>>
My number are: 12
No number

この関数は文字列とリストを受け入れ、印刷に使用します.ただし、リストに値がない場合は、2番目のパスのように空のリストを送信します.これは,log関数のパラメータが固定されており,固定されたパラメータに従ってしか値を伝達できないためである.
使用する場合は、もちろん2番目のパラメータが空の値であれば、リストを空にする必要がなく、関数も正常に動作することが望ましい.Pythonでは,後の位置パラメータに*を付けると実現できる.
def log(message, *values):  #       *
    if not values:
        print(message)
    else:
        values_str = ''.join(str(x) for x in values)
        print('%s: %s' % (message, values_str))

log('My number are', [1, 2])
log('No number')  #            
>>>
My number are: 12
No number

変長パラメータを持つ関数を使用する場合は、常にメタグループに変換されます.したがって、変長パラメータに対応するパラメータの個数は十分に少ないはずです.そうしないと、メモリが大量に消費されます.特に、入力された可変パラメータが*番のジェネレータである場合です.もう1つの問題は、可変パラメータの前に新しいパラメータを追加する場合、関数を変更する必要があります.そうしないと、混乱します.
第19条:オプションの動作をキーワードパラメータで表現する
Python関数は、パラメータを指定してパラメータを渡すときにキーワードを使用します.
def remainer(number, divisor):
    return number % divisor
assert remainer(20, 7) == 6

remainer(20, divisor=7)
remainer(number=20, divisor=7)
remainer(divisor=7, number=20)

直接値を渡すことも、キーワードを指定して値を伝えることもできます.ただし、キーワードパラメータの前に位置パラメータを置くことはできません.
remainer(number=20, 7)
>>>
SyntaxError: positional argument follows keyword argument

各パラメータは1回しか指定できませんが、
remainer(20, number=7)
>>>
TypeError: remainer() got multiple values for argument 'number'

第20条:動的デフォルトパラメータ
関数のパラメータにダイナミックなデフォルト値が必要な場合は、パラメータにデフォルト値を指定するのは当然だと思います.
def log(message, when=datetime.now()):
    print('%s: %s' % (message, when))

log('first time')
sleep(1)
log('second time')

>>>
first time: 2018-05-21 07:54:09.361192
second time: 2018-05-21 07:54:09.361192

運行結果は私たちが考えているものと違い、時間は一秒も違わず、全く同じであることがわかります!
ここではPythonコードの実行に関し、Pythonでは、パラメータのデフォルト値は各モジュールのロード時に求められ、モジュールはまたプログラムの起動時にロードされるので、パラメータのデフォルト値はモジュールのロード時に固定されている.
def log(message, when=None):
    when=datetime.now() if when is None else when
    print('%s: %s' % (message, when))

log('first time')
sleep(1)
log('second time')

>>>
first time: 2018-05-21 08:00:44.378427
second time: 2018-05-21 08:00:45.378766

以上のようにPythonではパラメータの動的デフォルト値を実現するには関数でしか実現できない.パラメータをデフォルトでNoneに設定し、関数でパラメータの値に基づいてNoneかどうかを判断して評価します.パラメータがリスト、辞書などの可変タイプの場合は、Noneを使用して入力する必要があります.そうしないと、同じ可変タイプのオブジェクトが使用されます.
第21条:キーワード形式でしか指定できないパラメータを使用して、コードが明確であることを確保する
Python 3では、キーワード形式でしか指定できないパラメータを定義することができ、これらのパラメータはキーワードで提供されなければならず、位置で提供されない.
def safe_division(number, divisor, *, ignore_overflow=False, ignore_zero_division=False):
    try:
        return number / divisor
    except OverflowError:
        if ignore_overflow:
            return 0
        else:
            raise
    except ZeroDivisionError:
        if ignore_zero_division:
            return 0
        else:
            raise 
            
safe_division(5, 3, True, False)
>>>
TypeError: safe_division() takes 2 positional arguments but 4 were given

上記の例では、パラメータリストに*番を使用して位置パラメータが終了したことを示し、後続パラメータはキーワードでのみ指定できます.キーワードパラメータを指定しなかった場合、位置パラメータを使用するとエラーが表示されます.
print(safe_division(1, 10*500, ignore_overflow=True, ignore_zero_division=False))

>>>
0.0

指定したキーパラメータを使用して正常に動作します.
Python 2では、この方法はありませんが、指定したキーワードパラメータしか使用できないことを別の方法で実現することができます.
def safe_division_d(number, divisor, **kwargs):
    ignore_overflow = kwargs.pop('ignore_overflow', False)
    ignore_zero_division = kwargs.pop('ignore_zero_division', False)
    if kwargs:
        raise TypeError('Unexcepted **kwargs')
    try:
        return number / divisor
    except OverflowError:
        if ignore_overflow:
            return 0
        else:
            raise
    except ZeroDivisionError:
        if ignore_zero_division:
            return 0
        else:
            raise
            
print(safe_division_d(1, 10**500000, True, False))
print(safe_division_d(1, 10**500000, ignore_overflow=True, ignore_zero_division=False))
print(safe_division_d(1, 10**500000, unexpected=True))

>>>
TypeError: safe_division_d() takes 2 positional arguments but 4 were given
0.0
TypeError: Unexcepted **kwargs
**kwargsというパラメータを用いると,指定された方法でパラメータが正しいか否かを容易に判断できる.