【问题标题】:Unpacking: [x,y], (x,y), x,y - what is the difference?拆包:[x,y], (x,y), x,y - 有什么区别?
【发布时间】:2020-10-29 13:03:18
【问题描述】:

在 Python 中使用 []() 或什么都不打包函数调用有什么区别?

def f():
    return 0, 1

a, b = f() # 1
[a, b] = f() # 2
(a, b) = f() # 3

【问题讨论】:

  • 完全没有区别。如果需要更有说服力,可以使用dis模块对包含各个版本的函数进行反汇编,观察它们的字节码是否相同。
  • 唯一的区别是如果你调用 type( thing ).__name__
  • 不确定是否重复,肯定相关:stackoverflow.com/questions/6967632/…
  • @reece 不过,没有什么可以打电话给type;括号在这里纯粹是句法。 [a, b] = f() 不会在此处创建任何类型的列表。
  • 对于这种情况,所有都是多余的。但是括号对于解包嵌套的东西很有用:a, (b, c) = [[0, 1], [2, 3]] 导致 a = [0, 1]b = 2c = 3

标签: python iterable-unpacking


【解决方案1】:

没有区别。不管你使用什么样的句法序列,都会生成相同的字节码。

>>> def f():
...   return 0, 1
...
>>> import dis
>>> dis.dis('[a,b] = f()')
  1           0 LOAD_NAME                0 (f)
              2 CALL_FUNCTION            0
              4 UNPACK_SEQUENCE          2
              6 STORE_NAME               1 (a)
              8 STORE_NAME               2 (b)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis('(a,b) = f()')
  1           0 LOAD_NAME                0 (f)
              2 CALL_FUNCTION            0
              4 UNPACK_SEQUENCE          2
              6 STORE_NAME               1 (a)
              8 STORE_NAME               2 (b)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis('a, b = f()')
  1           0 LOAD_NAME                0 (f)
              2 CALL_FUNCTION            0
              4 UNPACK_SEQUENCE          2
              6 STORE_NAME               1 (a)
              8 STORE_NAME               2 (b)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE

在任何情况下,您只需调用f,然后使用UNPACK_SEQUENCE 生成要分配给ab 的值。


即使你想争辩说字节码是 CPython 的一个实现细节,链式赋值的定义不是。给定

x = [a, b] = f()

意思是一样的

tmp = f()
x = tmp
[a, b] = tmp

x 被分配了f()(一个元组)的结果,而不是“列表”[a, b]


最后,这里是赋值语句的语法:

assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target

可以说,"[" [target_list] "]" 可以并且应该已经在 Python 3 中删除。鉴于声明的偏好是避免未来对 Python 进行任何 2 到3 过渡。

【讨论】:

  • 另外,我相信赋值运算符:= 的定义排除了(x := [a,b]) = f() 之类的任何技巧。 (至少,这绝对是一个语法错误。)
【解决方案2】:

正如另一个答案所解释的,没有语义差异。喜欢一种形式而不是另一种形式的唯一原因是视觉清晰。 x, y = f() 通常更整洁,但有时可能会编写类似[(id,)] = do_sql_query() 的内容来表示结果应该是包含元组的列表。赋值目标[(id,)] 在语义上等同于(id,),,但它向人类读者传达了更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 1970-01-01
    • 2021-06-07
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多