Int*_*rer 12 python syntax-error python-3.8 walrus-operator
我刚刚了解到新的 walrus 运算符 ( :=) 不能用于设置实例属性,它应该是无效的语法(引发 a SyntaxError)。
为什么是这样? (你能提供一个提到这个的官方文档的链接吗?)
我查看了PEP 572,找不到是否/在哪里记录了这一点。
研究
这个答案在没有解释或来源的情况下提到了这个限制:
您不能在对象属性上使用 walrus 运算符
示例代码
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."""
Run Code Online (Sandbox Code Playgroud)
尝试导入Foo结果为SyntaxError:
self.spam(self.foo := value)
^
SyntaxError: cannot use assignment expressions with attribute
Run Code Online (Sandbox Code Playgroud)
PEP 572 描述了这个目的(强调我的):
这是创建一种使用符号为表达式中的变量赋值的方法的提议
NAME := expr。
self.foo 不是变量,而是对象的属性。
在语法和语义部分进一步规定它:
NAME是一个标识符。
self.foo不是标识符,它是由.运算符分隔的两个标识符。
虽然我们经常类似地使用变量和属性,有时会草率地将其self.foo称为变量,但它们并不相同。分配给self.foo实际上只是一个简写
setattr(self, 'foo', temp)
Run Code Online (Sandbox Code Playgroud)
这允许您为属性定义 getter 和 setter。如果它必须使用具有自定义 setter 的属性,则会使赋值表达式的规范和实现复杂化。
例如,如果 setter 转换了被赋值的值,赋值表达式的值应该是原始值还是转换后的值?
另一方面,变量不能自定义。分配给变量总是具有相同的简单语义,并且表达式很容易评估为分配的值。
同样,您不能将 walrus 运算符与切片赋值一起使用。这是无效的:
foo1[2:4] := foo2[1:3]
Run Code Online (Sandbox Code Playgroud)
有趣的是,对 walrussing object.attributes 的禁止似乎只存在于 Python 的解析器中,该解析器将文本代码解析为抽象语法树(ast),然后编译和执行该抽象语法树。如果您手动创建一个 ast 语法树并self.foo替换varin (var := temp)and thencompile或exec该树,它会按照您直观的预期进行编译和执行。
显然,底层功能是允许海象对 object.attributes 进行赋值,他们只是选择不让我们使用它,因为他们担心这会让人们编写令人困惑的代码或其他东西。多谢...
所以无论如何,一个极端的(完全不推荐!)解决方案是你做一些预编译 ast-surgery 将你的 object.attribute 目标拼接到你的海象运算符中,然后它可能会按照你的预期运行。(我发现这一点是因为我已经在做 ast-surgery,出于其他原因用 object.attributes 替换了简单变量,而且我很高兴发现海象分配仍然有效!)
| 归档时间: |
|
| 查看次数: |
1455 次 |
| 最近记录: |