Python Language
関数
サーチ…
前書き
Pythonの関数は、一連の特定のアクションを実行するための、組織化された再利用可能なモジュラーコードを提供します。関数はコーディングプロセスを簡素化し、冗長ロジックを防止し、コードを簡単にフォローします。このトピックでは、Pythonでの関数の宣言と利用について説明します。
Pythonには、 print()
、 input()
、 len()
などの組み込み関数が多数あります。組み込み関数の他に、独自の関数を作成してより特定のジョブを実行することもできます。これはユーザー定義関数と呼ばれます 。
構文
- def function_name ( arg1、... argN、* args、kw1、kw2 =デフォルト、...、** kwargs ): ステートメント
- ラムダarg1、... argN、* args、kw1、kw2 =デフォルト、...、** kwargs : 式
パラメーター
パラメータ | 詳細 |
---|---|
arg1 、...、 argN | 通常の議論 |
* args | 無名の定位置引数 |
kw1 、...、 kwN | キーワードのみの引数 |
** kwargs | 残りのキーワード引数 |
備考
関数でできる5つの基本的なこと:
変数に関数を割り当てる
def f(): print(20) y = f y() # Output: 20
他の関数内の関数を定義する( 入れ子関数 )
def f(a, b, y): def inner_add(a, b): # inner_add is hidden from outer code return a + b return inner_add(a, b)**y
関数は他の関数を返すことができる
def f(y): def nth_power(x): return x ** y return nth_power # returns a function squareOf = f(2) # function that returns the square of a number cubeOf = f(3) # function that returns the cube of a number squareOf(3) # Output: 9 cubeOf(2) # Output: 8
関数は他の関数にパラメータとして渡すことができます
def a(x, y): print(x, y) def b(fun, str): # b has two arguments: a function and a string fun('Hello', str) b(a, 'Sophia') # Output: Hello Sophia
内部関数は、囲みスコープ( Closure )にアクセスできます。
def outer_fun(name): def inner_fun(): # the variable name is available to the inner function return "Hello "+ name + "!" return inner_fun greet = outer_fun("Sophia") print(greet()) # Output: Hello Sophia!
その他のリソース
単純な関数の定義と呼び出し
def
文を使用するのは、Pythonで関数を定義する最も一般的な方法です。この文は、以下の構文を持つ、いわゆる単一節複合文です。
def function_name(parameters):
statement(s)
function_name
は、関数の識別子として知られています。関数定義は実行可能なステートメントなので、関数名を関数オブジェクトにバインドします。関数オブジェクトは後でその識別子を使用して呼び出すことができます。
parameters
は、関数が呼び出されたときに引数として指定された値にバインドされる識別子のオプションのリストです。関数は、コンマで区切られた任意の数の引数を持つことができます。
statement(s)
関数本体とも呼ばれます)は、関数が呼び出されるたびに実行される文の空でないシーケンスです。つまり、 インデントされたブロックと同様に、関数本体を空にすることはできません。
次に、呼び出されるたびにHello
を出力する単純な関数定義の例を示します。
def greet():
print("Hello")
次に、定義されたgreet()
関数を呼び出しましょう:
greet()
# Out: Hello
これは関数定義のもう1つの例で、関数が呼び出されるたびに1つの引数をとり、渡された値を表示します。
def greet_two(greeting):
print(greeting)
その後、引数を指定してgreet_two()
関数を呼び出す必要があります。
greet_two("Howdy")
# Out: Howdy
また、その関数の引数にデフォルト値を与えることもできます:
def greet_two(greeting="Howdy"):
print(greeting)
これで、値を与えずに関数を呼び出すことができます:
greet_two()
# Out: Howdy
他の多くの言語とは異なり、関数の戻り値の型を明示的に宣言する必要はありません。 Python関数は、 return
キーワードで任意の型の値を返すことができます。 1つの関数は、任意の数の異なる型を返すことができます!
def many_types(x):
if x < 0:
return "Hello!"
else:
return 0
print(many_types(1))
print(many_types(-1))
# Output:
0
Hello!
これが呼び出し元によって正しく処理されている限り、これは完全に有効なPythonコードです。
return文なしで実行の最後に到達する関数は、常にNone
返します。
def do_nothing():
pass
print(do_nothing())
# Out: None
前述のように、関数定義には関数本体、つまり空でない一連のステートメントが必要です。したがって、 pass
文は関数本体として使用されます。これはnull操作です。実行されると何も起こりません。それが意味することは、それはスキップします。文が構文的に必要なときにプレースホルダとして有用ですが、コードを実行する必要はありません。
関数からの戻り値
関数は、直接使用できる値をreturn
ことができます。
def give_me_five():
return 5
print(give_me_five()) # Print the returned value
# Out: 5
または後で使用するために値を保存します。
num = give_me_five()
print(num) # Print the saved returned value
# Out: 5
任意の操作に値を使用します。
print(give_me_five() + 10)
# Out: 15
ファンクションでreturn
が発生した場合、ファンクションは即座に終了し、後続のオペレーションは評価されません。
def give_me_another_five():
return 5
print('This statement will not be printed. Ever.')
print(give_me_another_five())
# Out: 5
タプルの形で複数の値をreturn
こともできます:
def give_me_two_fives():
return 5, 5 # Returns two 5
first, second = give_me_two_fives()
print(first)
# Out: 5
print(second)
# Out: 5
return
文がない関数は、暗黙的にNone
返します。同様に、 return
文を持ち、戻り値も変数もない関数は、 None
返します。
引数を持つ関数を定義する
引数は、関数名の後のカッコ内に定義されています。
def divide(dividend, divisor): # The names of the function and its arguments
# The arguments are available by name in the body of the function
print(dividend / divisor)
関数名とその引数リストは、関数の署名と呼ばれます。各名前付き引数は事実上関数のローカル変数です。
関数を呼び出すときは、引数を順番に並べて指定します
divide(10, 2)
# output: 5
関数定義の名前を使用して任意の順序で指定することができます。
divide(divisor=2, dividend=10)
# output: 5
オプションの引数を持つ関数を定義する
オプションの引数は、argument-nameに( =
を使用して)デフォルト値を代入することで定義できます。
def make(action='nothing'):
return action
この関数を呼び出す方法は3つあります。
make("fun")
# Out: fun
make(action="sleep")
# Out: sleep
# The argument is optional so the function will use the default value if the argument is
# not passed in.
make()
# Out: nothing
警告
変更可能な型(
list
、dict
、set
など)は、 デフォルト属性として与えられたときには注意が必要です。デフォルトの引数を変更すると永続的に変更されます。 オプションの可変引数を使用した関数の定義を参照してください。
複数の引数を持つ関数を定義する
1つの関数は、必要な数の引数を与えることができます。唯一の固定された規則は、各引数名が一意でなければならず、省略可能な引数は、
def func(value1, value2, optionalvalue=10):
return '{0} {1} {2}'.format(value1, value2, optionalvalue1)
関数を呼び出すと、名前のない各キーワードを与えることができますが、順序は重要です。
print(func(1, 'a', 100))
# Out: 1 a 100
print(func('abc', 14))
# abc 14 10
あるいは、引数をnameとwithoutを組み合わせて組み合わせます。それで名前のついたものは、それらのものに従わなくてはならないが、名前のついたものの順序は問題ではない。
print(func('This', optionalvalue='StackOverflow Documentation', value2='is'))
# Out: This is StackOverflow Documentation
任意の数の引数を持つ関数を定義する
任意の数の位置引数:
任意の数の引数を取ることができる関数を定義するには、引数の1つに*
付けるか、
def func(*args):
# args will be a tuple containing all values that are passed in
for i in args:
print(i)
func(1, 2, 3) # Calling it with 3 arguments
# Out: 1
# 2
# 3
list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values) # Calling it with list of values, * expands the list
# Out: 1
# 2
# 3
func() # Calling it without arguments
# No Output
func(*args=[1, 2, 3])
ようにfunc(*args=[1, 2, 3])
args
デフォルトを指定することはできません (コンパイルされなくても)。
関数を呼び出すときにこれらの名前を指定することはできません。たとえばfunc(*args=[1, 2, 3])
はTypeError
ます。
しかし、配列(または他のIterable
)に引数をすでに持っている場合は、 func(*my_stuff)
ように関数を呼び出すことができます。
これらの引数( *args
)は、インデックスによってアクセスできます。例えば、 args[0]
は最初の引数を返します
キーワード引数の任意の数
名前のついた任意の数の引数を取ることができます。その引数の前に2つの *
を付けた定義の引数を定義します。
def func(**kwargs):
# kwargs will be a dictionary containing the names as keys and the values as values
for name, value in kwargs.items():
print(name, value)
func(value1=1, value2=2, value3=3) # Calling it with 3 arguments
# Out: value1 1
# value2 2
# value3 3
func() # Calling it without arguments
# No Out put
my_dict = {'foo': 1, 'bar': 2}
func(**my_dict) # Calling it with a dictionary
# Out: foo 1
# bar 2
名前を指定せずにこれらを指定することはできません。たとえば、 func(1, 2, 3)
はTypeError
ます。
kwargs
は単純なネイティブのpython辞書です。たとえば、 args['value1']
は引数value1
値をvalue1
ます。そのような引数があるか、 KeyError
がKeyError
することを事前に確認してください。
警告
これらを他のオプションと必要な引数と混在させることはできますが、定義内の順序は重要です。
位置/キーワード引数が最初に来ます。 (必須の引数)。
そして、 任意の *arg
引数が来ます。 (オプション)。
次に、 キーワードのみの引数が次に来る。 (必須)。
最後に任意のキーワード **kwargs
が来る。 (オプション)。
# |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
pass
-
arg1
必要があります。そうでない場合は、TypeError
がTypeError
されます。それは、位置(func(10)
)またはキーワード引数(func(arg1=10)
)として与えることができます。 -
kwarg1
もkwarg1
必要がありますが、キーワード引数:func(kwarg1=10)
としてのみ指定できます。 -
arg2
とkwarg2
はオプションです。値を変更する場合は、arg1
(位置またはキーワードのいずれか)およびkwarg1
(キーワードのみ)と同じルールが適用されます。 -
*args
追加の位置パラメータを捕捉します。しかし、*args
:func(1, 1, 1, 1)
*args
引数を渡すためには、arg1
とarg2
を定位置引数として指定する必要があります。 -
**kwargs
すべての追加のキーワードパラメータをキャッチします。この場合、arg1
、arg2
、kwarg1
またはkwarg2
。例:func(kwarg3=10)
。 - Python 3では、
*
のみを使用して、それ以降のすべての引数をキーワードとして指定する必要があることを示すことができます。たとえば、Python 3.5math.isclose
関数は、def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0)
を使用して定義されています。つまり、最初の2つの引数は位置指定できますが、第3および第4のパラメータはキーワード引数としてのみ提供することができる。
Python 2.xはキーワードのみのパラメータをサポートしていません。この動作はkwargs
でエミュレートできます:
def func(arg1, arg2=10, **kwargs):
try:
kwarg1 = kwargs.pop("kwarg1")
except KeyError:
raise TypeError("missing required keyword-only argument: 'kwarg1'")
kwarg2 = kwargs.pop("kwarg2", 2)
# function body ...
名前付けに関する注意
オプションの位置引数の命名の規則args
とオプションのキーワード引数kwargs
も 、あなたはあなたが好きな名前を使用することができるだけの規約ですが 、他の人があなたが何をしているか知っているように、規則に従うことに有用である、 または自分が後でそうしてください。
一意性に関する注意
任意の関数は、 noneまたは1つの *args
、 noneまたは **kwargs
で定義することができますが、複数の関数では定義できません。また、 *args
最後の位置引数でなければならず 、 **kwargs
最後のパラメータでなければなりません。いずれかの複数を使用しようとすると、構文エラーの例外が発生します 。
オプションの引数を持つ入れ子関数に関する注意
このような関数をネストすることは可能ですが、コードがすでに処理した項目を削除するのが通常の方法ですが、パラメータを渡す場合は、オプションの位置引数に*
接頭辞を、オプションのキーワードargsに**
接頭辞を渡す必要がありますそうでなければ、argsはリストまたはタプルとして渡され、kwargsは単一の辞書として渡されます。例えば:
def fn(**kwargs):
print(kwargs)
f1(**kwargs)
def f1(**kwargs):
print(len(kwargs))
fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2
オプションの可変引数を使用して関数を定義する
オプションの引数を変更可能なデフォルトの型 ( オプションの引数を持つ関数の定義を参照)で使用すると、予期しない動作につながる可能性があります。
説明
この問題は、関数のデフォルト引数が関数が定義された時点で一度だけ初期化され 、関数が呼び出されたとき(他の多くの言語のように)初期化され ないために発生します。デフォルト値は、関数オブジェクトの__defaults__
メンバ変数内に格納されます。
def f(a, b=42, c=[]):
pass
print(f.__defaults__)
# Out: (42, [])
不変型の場合( 引数の受け渡しと可変性を参照)、変数を変更する方法がないため、これは問題ではありません。元の値を変更せずに再割り当てすることができます。したがって、後続は同じデフォルト値を持つことが保証されます。しかし、 可変型の場合、さまざまなメンバー関数を呼び出すことによって、元の値を変更することができます。したがって、関数への連続呼び出しは、初期のデフォルト値を持つことが保証されていません。
def append(elem, to=[]):
to.append(elem) # This call to append() mutates the default variable "to"
return to
append(1)
# Out: [1]
append(2) # Appends it to the internally stored list
# Out: [1, 2]
append(3, []) # Using a new created list gives the expected result
# Out: [3]
# Calling it again without argument will append to the internally stored list again
append(4)
# Out: [1, 2, 4]
注意: PyCharmのような一部のIDEでは、変更可能な型がデフォルトの属性として指定されているときに警告が発行されます。
溶液
デフォルトの引数は、常にあなたが関数定義で指定した1つであることを確認したい場合は、解決策は、 常にデフォルトの引数として不変の型を使用することです。
可変タイプがデフォルトとして必要とされるときにこれを達成するための一般的なイディオムは、使用しないことであるNone
デフォルト引数として(不変)を、次いでそれが等しい場合、引数の変数に実際のデフォルト値を割り当てNone
。
def append(elem, to=None):
if to is None:
to = []
to.append(elem)
return to
ラムダ(インライン/匿名)関数
lambda
キーワードは、単一の式を含むインライン関数を作成します。この式の値は、呼び出されたときに関数が返す値です。
次の関数を考えてみましょう。
def greeting():
return "Hello"
それは、と呼ばれるとき:
print(greeting())
プリントする:
Hello
これは次のようにラムダ関数として書くことができます:
greet_me = lambda: "Hello"
ラムダの変数への割り当てについては、このセクションの最後の注を参照してください。一般的には、しないでください。
Hello
を返すgreet_me
という名前のインライン関数を作成します。ラムダで関数を作成するときには、 return
書かないことに注意してください。 after :
の値が自動的に返されます。
ひとたび変数に代入されると、それは通常の関数のように使うことができます:
print(greet_me())
プリントする:
Hello
lambda
も引数を取ることができます:
strip_and_upper_case = lambda s: s.strip().upper()
strip_and_upper_case(" Hello ")
次の文字列を返します。
HELLO
通常の関数のように、任意の数の引数/キーワード引数を取ることもできます。
greeting = lambda x, *args, **kwargs: print(x, args, kwargs)
greeting('hello', 'world', world='world')
プリントする:
hello ('world',) {'world': 'world'}
lambda
は、呼び出されるポイントで定義するのが便利な短い関数(通常sorted
、 filter
、 map
)によく使用されます。
例えば、この行は文字列のリストをソートして大文字と小文字を無視し、先頭と末尾の空白を無視します。
sorted( [" foo ", " bAR", "BaZ "], key=lambda s: s.strip().upper())
# Out:
# [' bAR', 'BaZ ', ' foo ']
ソートリストは空白を無視するだけです:
sorted( [" foo ", " bAR", "BaZ "], key=lambda s: s.strip())
# Out:
# ['BaZ ', ' bAR', ' foo ']
map
例:
sorted( map( lambda s: s.strip().upper(), [" foo ", " bAR", "BaZ "]))
# Out:
# ['BAR', 'BAZ', 'FOO']
sorted( map( lambda s: s.strip(), [" foo ", " bAR", "BaZ "]))
# Out:
# ['BaZ', 'bAR', 'foo']
数値リストの例:
my_list = [3, -4, -2, 5, 1, 7]
sorted( my_list, key=lambda x: abs(x))
# Out:
# [1, -2, 3, -4, 5, 7]
list( filter( lambda x: x>0, my_list))
# Out:
# [3, 5, 1, 7]
list( map( lambda x: abs(x), my_list))
# Out:
[3, 4, 2, 5, 1, 7]
ラムダ関数の中から他の関数(引数の有無)を呼び出すことができます。
def foo(msg):
print(msg)
greet = lambda x = "hello world": foo(x)
greet()
プリントする:
hello world
lambda
は1つの式だけが含まれ、補助関数を使用することで複数のステートメントを実行できるので、これは便利です。
注意
PEP-8 (公式のPythonスタイルのガイド)では、ラムダを変数に割り当てることはお勧めしません(最初の2つの例で行ったように):
ラムダ式を識別子に直接バインドする代入文ではなく、常にdef文を使用してください。
はい:
def f(x): return 2*x
いいえ:
f = lambda x: 2*x
最初の形式は、結果の関数オブジェクトの名前が汎用の
<lambda>
ではなくf
であることを意味します。これは一般的にトレースバックや文字列の表示に役立ちます。代入文を使用すると、ラムダ式が明示的なdef
文で提供できる唯一の利点(つまり、より大きな式の中に埋め込むことができる)を排除します。
引数の受け渡しと変更
まず、いくつかの用語:
- 引数( 実際のパラメータ):関数に渡される実際の変数。
- パラメータ( 仮パラメータ):関数で使用される受信変数。
Pythonでは、引数は代入によって渡されます (他の言語とは異なり、引数は値/参照/ポインタによって渡されます)。
パラメータを変更すると、引数が変更されます(引数の型が変更可能な場合)。
def foo(x): # here x is the parameter x[0] = 9 # This mutates the list labelled by both x and y print(x) y = [4, 5, 6] foo(y) # call foo with y as argument # Out: [9, 5, 6] # list labelled by x has been mutated print(y) # Out: [9, 5, 6] # list labelled by y has been mutated too
パラメータを再割り当てしても、引数は再割り当てされません。
def foo(x): # here x is the parameter, when we call foo(y) we assign y to x x[0] = 9 # This mutates the list labelled by both x and y x = [1, 2, 3] # x is now labeling a different list (y is unaffected) x[2] = 8 # This mutates x's list, not y's list y = [4, 5, 6] # y is the argument, x is the parameter foo(y) # Pretend that we wrote "x = y", then go to line 1 y # Out: [9, 5, 6]
Pythonでは、実際には変数に値を代入するのではなく、変数( 名前と見なす)をオブジェクトにバインド (つまり割り当て、アタッチ)します。
- 不変:整数、文字列、タプルなど。すべての操作でコピーが作成されます。
- 変更可能:リスト、辞書、セットなど。操作は突然変異してもしなくてもよい。
x = [3, 1, 9]
y = x
x.append(5) # Mutates the list labelled by x and y, both x and y are bound to [3, 1, 9]
x.sort() # Mutates the list labelled by x and y (in-place sorting)
x = x + [4] # Does not mutate the list (makes a copy for x only, not y)
z = x # z is x ([1, 3, 9, 4])
x += [6] # Mutates the list labelled by both x and z (uses the extend function).
x = sorted(x) # Does not mutate the list (makes a copy for x only).
x
# Out: [1, 3, 4, 5, 6, 9]
y
# Out: [1, 3, 5, 9]
z
# Out: [1, 3, 5, 9, 4, 6]
閉鎖
Pythonのクロージャは、関数呼び出しによって作成されます。ここで、 makeInc
の呼び出しは、関数inc
内で参照されるx
バインディングを作成します。 makeInc
を呼び出すたびにこの関数の新しいインスタンスが作成されますが、各インスタンスにはx
異なるバインディングへのリンクがあります。
def makeInc(x):
def inc(y):
# x is "attached" in the definition of inc
return y + x
return inc
incOne = makeInc(1)
incFive = makeInc(5)
incOne(5) # returns 6
incFive(5) # returns 10
通常のクロージャでは、囲まれた関数はその囲む環境からすべての変数を完全に継承しますが、この構造では、囲まれた関数は継承された変数への読み取りアクセスのみを持ちますが、
def makeInc(x):
def inc(y):
# incrementing x is not allowed
x += y
return x
return inc
incOne = makeInc(1)
incOne(5) # UnboundLocalError: local variable 'x' referenced before assignment
Python 3では、ネストされた関数を使って完全閉包を実現する非 nonlocal
文( Nonlocal Variables )を提供しています。
def makeInc(x):
def inc(y):
nonlocal x
# now assigning a value to x is allowed
x += y
return x
return inc
incOne = makeInc(1)
incOne(5) # returns 6
再帰関数
再帰関数は、その定義の中で自身を呼び出す関数です。たとえば、 factorial(n) = n*(n-1)*(n-2)*...*3*2*1
で定義される数学関数、階乗。次のようにプログラムすることができます
def factorial(n):
#n here should be an integer
if n == 0:
return 1
else:
return n*factorial(n-1)
ここでの出力は次のとおりです。
factorial(0)
#out 1
factorial(1)
#out 1
factorial(2)
#out 2
factorial(3)
#out 6
予想通り。この関数は再帰的であることに注意してください。なぜなら、第2のreturn factorial(n-1)
は、関数がその定義で自分自身を呼び出すからです。
いくつかの再帰関数はlambdaを使用して実装できますが、lambdaを使用する階乗関数は次のようになります。
factorial = lambda n: 1 if n == 0 else n*factorial(n-1)
この関数は上記と同じ結果を出力します。
再帰制限
可能な再帰の深さには限界があります。これはPythonの実装に依存します。制限に達すると、RuntimeError例外が発生します。
def cursing(depth):
try:
cursing(depth + 1) # actually, re-cursing
except RuntimeError as RE:
print('I recursed {} times!'.format(depth))
cursing(0)
# Out: I recursed 1083 times!
使用して、再帰の深さの制限を変更することが可能であるsys.setrecursionlimit(limit)
によってこの制限をチェックsys.getrecursionlimit()
sys.setrecursionlimit(2000)
cursing(0)
# Out: I recursed 1997 times!
Python 3.5からの例外は、 RuntimeError
から派生したRecursionError
RuntimeError
。
ネストされた関数
Pythonの関数はファーストクラスのオブジェクトです。それらは任意のスコープで定義することができます
def fibonacci(n):
def step(a,b):
return b, a+b
a, b = 0, 1
for i in range(n):
a, b = step(a, b)
return a
囲みスコープをキャプチャする関数は、他のあらゆる種類のオブジェクトと同様に渡すことができます
def make_adder(n):
def adder(x):
return n + x
return adder
add5 = make_adder(5)
add6 = make_adder(6)
add5(10)
#Out: 15
add6(10)
#Out: 16
def repeatedly_apply(func, n, x):
for i in range(n):
x = func(x)
return x
repeatedly_apply(add5, 5, 1)
#Out: 26
反復可能な辞書解凍
関数では、位置、名前、変数の位置、キーワードargs(kwargs)のようなパラメータのタイプを指定できます。ここでは、それぞれのタイプの明快で簡潔な使い方があります。
def unpacking(a, b, c=45, d=60, *args, **kwargs):
print(a, b, c, d, args, kwargs)
>>> unpacking(1, 2)
1 2 45 60 () {}
>>> unpacking(1, 2, 3, 4)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, c=3)
1 2 3 4 () {}
>>> pair = (3,)
>>> unpacking(1, 2, *pair, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, *pair, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, c=3, *pair)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> args_list = [3]
>>> unpacking(1, 2, *args_list, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, *args_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, *args_list, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> pair = (3, 4)
>>> unpacking(1, 2, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *pair)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *pair)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *pair, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> args_list = [3, 4]
>>> unpacking(1, 2, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *args_list)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *args_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *args_list, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> arg_dict = {'c':3, 'd':4}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'d':4, 'c':3}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'c':3, 'd':4, 'not_a_parameter': 75}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, *pair, **arg_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, 3, 4, **arg_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
# Positional arguments take priority over any other form of argument passing
>>> unpacking(1, 2, **arg_dict, c=3)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, 3, **arg_dict, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
名前付きパラメータの使用を強制する
関数シグニチャーの最初のアスタリスクの後に指定されたすべてのパラメーターはキーワードのみです。
def f(*a, b):
pass
f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'
Python 3では、関数のシグネチャにアスタリスクを1つ入れて残りの引数をキーワード引数で渡すことができます。
def f(a, b, *, c):
pass
f(1, 2, 3)
# TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)
# No error
割り当てられた変数を使用する再帰ラムダ
再帰ラムダ関数を作成する1つの方法は、関数に変数を代入し、関数自体の中でその変数を参照することです。これの一般的な例は、次のコードに示すように、数値の階乗を再帰的に計算することです。
lambda_factorial = lambda i:1 if i==0 else i*lambda_factorial(i-1)
print(lambda_factorial(4)) # 4 * 3 * 2 * 1 = 12 * 2 = 24
コードの説明
ラムダ関数は、その変数の割り当てを介して、それが0であるか、またはそうでなければ現在の値(返した場合、それは1を評価し、戻り値(4)を通過さi
)*値のラムダ関数によって別の計算- 1( i-1
)。これは、渡された値が0( return 1
)にデクリメントされるまで続きます。次のように可視化できるプロセス: