web-dev-qa-db-ja.com

なぜx、y = Zip(* Zip(a、b))はPythonで動作するのですか?

OK、PythonのZip()関数が大好きです。常にそれを使用して、それは素晴らしいです。たびたびZip()の反対を行い、「それを行う方法を知っていた」と考え、次にgoogle python unzipしてから、この魔法の*タプルの圧縮リストを解凍します。このような:

x = [1,2,3]
y = [4,5,6]
zipped = Zip(x,y)
unzipped_x, unzipped_y = Zip(*zipped)
unzipped_x
    Out[30]: (1, 2, 3)
unzipped_y
    Out[31]: (4, 5, 6)

一体何が起こっているのですか?その魔法のアスタリスクは何をしていますか?他にどこに適用できますか?Pythonの他の驚くべき素晴らしいことは、神秘的でグーグルに難しいですか?

75
Mike Dewar

Pythonのアスタリスクは、Pythonチュートリアルの Unpacking Argument Lists に記載されています。

39

アスタリスクはapplyを実行します(LISPおよびSchemeで知られています)。基本的に、リストを受け取り、そのリストの内容を引数として関数を呼び出します。

18

複数の引数にも便利です:

def foo(*args):
  print args

foo(1, 2, 3) # (1, 2, 3)

# also legal
t = (1, 2, 3)
foo(*t) # (1, 2, 3)

また、キーワードの引数と辞書に二重アスタリスクを使用できます。

def foo(**kwargs):
   print kwargs

foo(a=1, b=2) # {'a': 1, 'b': 2}

# also legal
d = {"a": 1, "b": 2}
foo(**d) # {'a': 1, 'b': 2}

そしてもちろん、これらを組み合わせることができます:

def foo(*args, **kwargs):
   print args, kwargs

foo(1, 2, a=3, b=4) # (1, 2) {'a': 3, 'b': 4}

きれいで便利なもの。

8
bcherry

常に機能するとは限りません。

>>> x = []
>>> y = []
>>> zipped = Zip(x, y)
>>> unzipped_x, unzipped_y = Zip(*zipped)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack

おっとっと!私はそれを動作させるためにそれを怖がらせるために頭蓋骨が必要だと思う:

>>> unzipped_x, unzipped_y = Zip(*zipped) or ([], [])
>>> unzipped_x
[]
>>> unzipped_y
[]

Python3では、あなたが必要だと思う

>>> unzipped_x, unzipped_y = Tuple(Zip(*zipped)) or ([], [])

zipはFalse-yではないジェネレーター関数を返すようになりました。

6
BenAnhalt

私はPythonに非常に新しいので、これは最近私をつまずかせましたが、例がどのように提示され、何が強調されたかにより多くのことをしなければなりませんでした。

Zipの例を理解する上で問題を引き起こしたのは、Zip呼び出しの戻り値の処理の非対称性でした。つまり、最初にZipが呼び出されると、戻り値が単一の変数に割り当てられ、リスト参照(作成されたタプルリストを含む)が作成されます。 2回目の呼び出しでは、リスト(またはコレクション?)の戻り値を複数の変数参照に自動的にアンパックするPythonの機能を利用します。各参照は個々のタプルです。誰かがPythonでそれがどのように機能するかに慣れていない場合、実際に何が起こっているのか迷ってしまいやすくなります。

>>> x = [1, 2, 3]
>>> y = "abc"
>>> zipped = Zip(x, y)
>>> zipped
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> z1, z2, z3 = Zip(x, y)
>>> z1
(1, 'a')
>>> z2
(2, 'b')
>>> z3
(3, 'c')
>>> rezipped = Zip(*zipped)
>>> rezipped
[(1, 2, 3), ('a', 'b', 'c')]
>>> rezipped2 = Zip(z1, z2, z3)
>>> rezipped == rezipped2
True
2
user3447701

(x, y) == Tuple(Zip(*Zip(x,y)))は、次の2つのステートメントが真である場合にのみ真です。

  • xyは同じ長さです
  • xyはタプルです

何が起こっているのかを理解する良い方法の1つは、各ステップで印刷することです。

x = [1, 2, 3]
y = ["a", "b", "c", "d"]

print("1) x, y = ", x, y)
print("2) Zip(x, y) = ", list(Zip(x, y)))
print("3) *Zip(x, y) = ", *Zip(x, y))
print("4) Zip(*Zip(x,y)) = ", list(Zip(*Zip(x,y))))

どの出力:

1) x, y =            [1, 2, 3] ['a', 'b', 'c', 'd']
2) Zip(x, y) =       [(1, 'a'), (2, 'b'), (3, 'c')]
3) *Zip(x, y) =       (1, 'a')  (2, 'b')  (3, 'c')
4) Zip(*Zip(x,y)) =  [(1, 2, 3), ('a', 'b', 'c')]

基本的にこれが起こることです:

  1. xyのアイテムは、それぞれのインデックスに従ってペアになります。
  2. ペアは3つの異なるオブジェクト(タプル)に展開されます
  3. ペアはZipに渡されます。Zipは、インデックスに基づいてすべてのアイテムをペアリングします。
    • すべての入力からの最初の項目がペアになります:(1, 2, 3)
    • すべての入力からの2番目のアイテムはペアになります:('a', 'b', 'c')

この場合、(x, y) == Tuple(Zip(*Zip(x,y)))がfalseである理由を理解できます。

  • yxより長いため、最初のZip操作でyから余分なアイテムが削除されたため(ペアリングできなかったため)、この変更は2番目に明らかに再実行されます。ファスナー操作
  • 型は異なります。最初は2つのリストがありましたが、Zipはリストではなくタプル内のアイテムをペアリングするため、2つのタプルがあります。

Zipがどのように機能するかを100%確信できない場合は、この質問に対する答えをここに書きました: Unzipping and the * operator

0
cglacet

@bcherryの回答の補遺:

>>> def f(a2,a1):
...  print a2, a1
... 
>>> d = {'a1': 111, 'a2': 222}
>>> f(**d)
222 111

そのため、キーワード引数( この厳密な意味 )だけでなく、名前付き引数(別名positional引数)でも機能します。

0
Evgeni Sergeev