【问题标题】:Why can't Python's walrus operator be used to set instance attributes?为什么不能使用 Python 的海象运算符来设置实例属性?
【发布时间】:2020-09-24 22:33:54
【问题描述】:

我刚刚了解到新的海象运算符 (:=) 不能用于设置实例属性,它应该是无效的语法(引发 SyntaxError)。

为什么会这样?(你能提供一个提到这个的官方文档的链接吗?)

我查看了 PEP 572,但找不到是否/在哪里记录了这一点。


研究

This answer 在没有解释或来源的情况下提到了这个限制:

您不能在对象属性上使用海象运算符


示例代码

class Foo:
    def __init__(self):
        self.foo: int = 0

    def bar(self, value: int) -> None:
        self.spam(self.foo := value)  # Invalid syntax

    def baz(self, value: int) -> None:
        self.spam(temp := value)
        self.foo = temp

    def spam(self, value: int) -> None:
        """Do something with value."""

尝试导入Foo 会导致SyntaxError

    self.spam(self.foo := value)
              ^
SyntaxError: cannot use assignment expressions with attribute

【问题讨论】:

  • @SuperStew 你能解释一下原因吗?
  • @SuperStew 有时坏事是两害相权取其轻。我发现 PEP 572 中的示例令人信服
  • @jtbandes 似乎与 python 的禅宗背道而驰
  • 我怀疑这是因为对属性的赋值实际上是变相的方法调用,并且可能具有隐藏的副作用。对名称的纯赋值是不行的。
  • “我不喜欢海象操作员”是一个公平的说法。 “海象操作员很糟糕并且你应该感觉很糟糕”是另一回事。我们不要忘记,海象运算符经过了许多 Python 专家的严格审查和讨论,他们对 Python 的禅宗对语言的意义有着强烈、完善的看法。不同意他们是好的,但告诉随机的人因为这种分歧而感到难过是不好的。

标签: python syntax-error python-3.8 walrus-operator


【解决方案1】:

PEP 572 描述了这个目的(强调我的):

这是一个提议,用于创建一种使用符号 NAME := expr 分配给表达式中的变量的方法。

self.foo 不是变量,它是对象的属性。

Syntax and semantics 部分进一步指定:

NAME 是一个标识符。

self.foo 不是标识符,它是由. 运算符分隔的两个标识符。

虽然我们经常类似地使用变量和属性,有时会草率地将self.foo 称为变量,但它们并不相同。赋值给self.foo其实只是一个简写形式

setattr(self, 'foo', temp)

这允许您为属性定义 getter 和 setter。如果它必须使用具有自定义设置器的属性,它将使赋值表达式的规范和实现变得复杂。

例如,如果 setter 转换了被赋值的值,那么赋值表达式的值应该是原始值还是转换后的值?

另一方面,变量不能自定义。分配给变量始终具有相同的简单语义,并且表达式很容易计算出所分配的值。

同样,您不能将海象运算符与切片分配一起使用。这是无效的:

foo1[2:4] := foo2[1:3]

【讨论】:

  • 谢谢,我已经在答案中添加了这一点以及更多细节。
【解决方案2】:

有趣的是,禁止 walrussing object.attributes 似乎只存在于 Python 的解析器中,该解析器将文本代码解析为抽象语法树 (ast),然后将被编译和执行。如果你手动创建一个 ast 语法树,用self.foo 代替(var := temp) 中的var,然后compileexec 那棵树,它会按照你的直觉编译和执行。

显然,底层功能是允许将海象分配给 object.attributes,他们只是选择不让我们使用它,因为他们担心这会使人们编写混乱的代码或其他东西。非常感谢...

所以无论如何,一个极端的(完全不推荐!)解决方案是让你做一些预编译 ast-surgery 将你的 object.attribute 目标拼接到你的海象运算符中,然后它可能会运行如你所料。 (我发现了这一点,因为我已经在做 ast-surgery,将简单的变量替换为 object.attributes 出于其他原因,我很高兴发现海象分配仍然有效!)

【讨论】:

  • Python 的大部分内容是“我们选择不给你这个能力~为了你好~”
猜你喜欢
  • 2011-07-24
  • 2020-07-02
  • 1970-01-01
  • 1970-01-01
  • 2014-09-22
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多