Python関数パラメータタイプ*、**の違い

6641 ワード

pythonの勉強を始めたばかりで、pythonはjavaに比べて確かに簡潔で使いやすいです.メモリ回収はhotspotのような達成性分析、可変オブジェクトもjavaのIntegerタイプ、with関数は新しいバージョンのC++のような特性で、全体的に理解しやすい.ただ、関数部分のパラメータの「*」や「**」、閉パッケージなどの問題は、実に漠然としていて、概念を明らかにしてこの文を書いて記録し、他の初心者を助けることができることを望んでいます.
そこで本稿は学習ノートであり,使用の詳細と理解に重点を置き,まず関数の各種パラメータタイプの呼び出しと宣言時の違い,および混用時に注意すべきいくつかの詳細をそれぞれ紹介し,その後閉包に関する内容を述べた.間違ったところがあれば指摘を歓迎します.
関数パラメータに「*」を付けず、「*」と「**」の区別を理解するこの問題の鍵は、呼び出しと宣言文法の3つの区別を別々に理解することにある.
関数呼び出しの違い
1.異なるタイプのパラメータの簡単な説明#ここでpython関数呼び出しの構文を説明します.
 
  
func(positional_args, keyword_args,
 *tuple_grp_nonkw_args, **dict_grp_kw_args)
 
 # ,
 def test(a,b,c,d,e):
  print a,b,c,d,e

この4つの呼び出しの違いを例に挙げて説明します.
 
  
#-------------------------------
#positional_args
>>> test(1,2,3,4,5)
1 2 3 4 5

#
a,b,c,d,e = 1,2,3,4,5
print a,b,c,d,e

#-------------------------------
#keyword_args
>>> test(a=1,b=3,c=4,d=2,e=1)
1 3 4 2 1

#
a=1
b=3
c=4
d=2
e=1
print a,b,c,d,e

#-------------------------------
#*tuple_grp_nonkw_args
>>> x = 1,2,3,4,5
>>> test(*x)
1 2 3 4 5


#この方式の関数処理は
 
  
a,b,c,d,e = x
print a,b,c,d,e
# :x dict ,x dick
>>> y
{'a': 1, 'c': 6, 'b': 2, 'e': 1, 'd': 1}
>>> test(*y)
a c b e d

#---------------------------------
#**dict_grp_kw_args
>>> y
{'a': 1, 'c': 6, 'b': 2, 'e': 1, 'd': 1}
>>> test(**y)
1 2 6 1 1

#
a = y['a']
b = y['b']
... #c,d,e
print a,b,c,d,e


2.異なる種類のパラメータの混用に注意すべきいくつかの詳細は次に異なるパラメータの種類の混用の情況を説明して、異なるパラメータの混用の文法を理解するには以下のいくつかの方面の内容を理解する必要がある.
まず、関数呼び出しの使用パラメータのタイプは厳格に順序に従わなければならず、勝手に順序を変えることはできない.そうしないと、エラーが発生する.(a=1,2,3,4,5)(*x,2,3)も不法とみなされる.
次に、関数の異なる方式に対する処理の順序も上述のタイプの順序に従う.Args方式と**dict_grp_kw_args方式はパラメータを1つずつ指定するので順序は関係ない.したがって順序付与(positional_args)とリスト付与(*tuple_grp_nonkw_args)の順序のみを考慮する必要がある.したがって,#positional_Args方式、#*tuple_grp_nonkw_args方式には論理的前後順序がある.
最後に、パラメータは複数回の付与を許さない.
例を挙げると、順序付与(positional_args)とリスト付与(*tuple_grp_nonkw_args)の論理的前後関係が説明される.
 
  
# ,
# 1
>>> x = {3,4,5}
>>> test(1,2,*x)
1 2 3 4 5
# 2
>>> test(1,e=2,*x)
1 3 4 5 2

#
>>> test(1,b=2,*x)
Traceback (most recent call last):
  File "", line 1, in
TypeError: test() got multiple values for keyword argument 'b'

# 1,
a,b = 1,2 #
c,d,e = x #
print a,b,c,d,e

# 2,
a = 1 #
e = 2 #
b,c,d = x #

# ,
a = 1 #
b = 2 #
b,c,d = x #
# b ,


関数宣言の違い
関数呼び出しにおける異なるタイプのパラメータの違いを理解してから、関数宣言における異なるパラメータの違いを理解するのは簡単である.
1.関数宣言のパラメータタイプの説明
関数宣言は3種類しかありません.arg,*arg,*argは、関数呼び出しとは正反対の役割を果たします.呼び出し時*tuple_grp_nonkw_argsはリストを順序パラメータに変換し、宣言中の*argの役割は順序付与(positional_args)をリストに変換することである.呼び出し時*dict_grp_kw_argsは辞書をキーワードパラメータに変換するが、宣言中の*argは逆にキーワードパラメータ(keyword_args)を辞書に変換する.特に注意:*argと*argは空の値であってもよい.
次の例では、上記のルールを示します.
 
  
#arg, *arg **arg
def test2(a,*b,**c):
 print a,b,c
#---------------------------
#*arg **arg
>>> test2(1)
1 () {}
#arg
>>> test2()
Traceback (most recent call last):
  File "", line 1, in
TypeError: test2() takes at least 1 argument (0 given)

#----------------------------
#*arg positional_args
>>> test2(1,2,[1,2],{'a':1,'b':2})
1 (2, [1, 2], {'a': 1, 'b': 2}) {}
#
a = 1 #arg
b = 2,[1,2],{'a':1,'b':2} #*arg
c = dict() #**arg
print a,b,c

#-----------------------------
#**arg keyword_args
>>> test2(1,2,3,d={1:2,3:4}, c=12, b=1)
1 (2, 3) {'c': 12, 'b': 1, 'd': {1: 2, 3: 4}}
#
a = 1 #arg
b= 2,3 #*arg
#**arg
c = dict()
c['d'] = {1:2, 3:4}
c['c'] = 12
c['b'] = 1
print a,b,c


2.処理手順の問題
関数は常にargタイプのパラメータを先に処理し、*argと*argタイプのパラメータを処理する.*argと*argは呼び出しパラメータのタイプが異なるため、彼らの順序を考慮する必要はない.
 
  
def test2(a,*b,**c):
 print a,b,c
>>> test2(1, b=[1,2,3], c={1:2, 3:4},a=1)
Traceback (most recent call last):
  File "", line 1, in
TypeError: test2() got multiple values for keyword argument 'a'
# , arg
#
# arg :
a = 1
a = 1  # ,
#
...
print a,b,c

閉パッケージpythonの関数は、もともと2つの領域の変数:グローバル、ローカル(関数コンテキスト)にしかアクセスできません.実際には、関数自体もオブジェクトであり、独自の役割ドメインもあります.閉パッケージは、関数と参照集合の組み合わせによって、関数が定義された領域の外で実行できるようにします.この集合はfunc_closureはこの参照セットを取得します.これはpythonがグローバル変数を処理する方法と同じですが、グローバル変数は参照セットを__に格納します.globals__フィールド内の.func_closureはcellタイプを格納メタグループであり、各cellはコンテキスト変数を格納する.
また、旧バージョンのpythonの内部関数が他の役割ドメインで使用できない理由は、各役割ドメインの変数が厳密に互いに隔離されているためではなく、元の役割ドメインから離れた後、関数が元のコンテキストの参照を失ったためである.なお、閉パケットに格納コンテキスト情報は同様に浅いコピーであるため、内部関数に伝達される可変オブジェクトは、そのオブジェクトが参照する他の変数によって変更される.
例を挙げます.
 
  
>>> def foo(x,y):
...     def bar():
...             print x,y
...     return bar
...
# func_closure
>>> a = [1,2]
>>> b = foo(a,0)
>>> b.func_closure[0].cell_contents
[1, 2]
>>> b.func_closure[1].cell_contents
0
>>> b()
[1, 2] 0

#
>>> a.append(3)
>>> b.func_closure[0].cell_contents
[1, 2, 3]
>>> b()
[1, 2, 3] 0