为了账号安全,请及时绑定邮箱和手机立即绑定

为什么Python的walrus运算符不能用来设置实例属性?

为什么Python的walrus运算符不能用来设置实例属性?

喵喵时光机 2023-09-05 20:33:45
我刚刚了解到新的海象运算符 ( :=) 不能用于设置实例属性,它被认为是无效语法(引发 a SyntaxError)。为什么是这样? (您能提供提到这一点的官方文档的链接吗?)我浏览了PEP 572,但找不到是否/在哪里记录了这一点。研究这个答案提到了这个限制,但没有解释或来源:您不能对对象属性使用海象运算符示例代码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
查看完整描述

2 回答

?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

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

这是一个建议,旨在创建一种使用符号 为表达式中的变量赋值的方法NAME := expr

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

语法和语义部分进一步指定它:

NAME是一个标识符。

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

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

setattr(self, 'foo', temp)

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

例如,如果 setter 转换所分配的值,则赋值表达式的值应该是原始值还是转换后的值?

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

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

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


查看完整回答
反对 回复 2023-09-05
?
RISEBY

TA贡献1856条经验 获得超5个赞

有趣的是,对 walrussing object.attributes 的禁止似乎只存在于 Python 的解析器中,该解析器将文本代码解析为抽象语法树(ast),然后编译和执行该抽象语法树。如果您手动创建一个 ast 语法树并self.foo替换varin (var := temp)and thencompileexec该树,它会按照您直观的预期进行编译和执行。

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

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


查看完整回答
反对 回复 2023-09-05
  • 2 回答
  • 0 关注
  • 108 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信