Почему нельзя использовать оператор моржа в Python для установки атрибутов экземпляра?
Я только что узнал, что новый моржовый оператор (:=
) нельзя использовать для установки атрибутов экземпляра, это предположительно недопустимый синтаксис (вызывает
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 ответа
PEP 572 описывает цель этого (выделено мной):
Это предложение по созданию способа присвоения переменных в выражении с использованием нотации
NAME := expr
.
self.foo
не переменная, это атрибут объекта.
В разделе " Синтаксис и семантика " это дополнительно уточняется:
NAME
это идентификатор.
self.foo
не идентификатор, это два идентификатора, разделенных
.
оператор.
Хотя мы часто используем переменные и атрибуты аналогичным образом и иногда небрежно ссылаемся на
self.foo
как переменная они не совпадают. Назначение
self.foo
на самом деле просто сокращение для
setattr(self, 'foo', temp)
Это то, что позволяет вам определять геттеры и сеттеры для атрибутов. Это усложнило бы спецификацию и реализацию выражения присваивания, если бы ему пришлось работать с атрибутами, которые имеют настраиваемые установщики.
Например, если установщик преобразует присвоенное значение, должно ли значение выражения присваивания быть исходным или преобразованным значением?
С другой стороны, переменные не могут быть изменены. Присвоение переменной всегда имеет одну и ту же простую семантику, и выражение может легко оценить значение, которое было присвоено.
Точно так же вы не можете использовать оператор моржа с назначением срезов. Это неверно:
foo1[2:4] := foo2[1:3]
Интересно, что запрет на использование атрибутов object.attributes, похоже, присутствует только в парсере Python, который анализирует текстовый код в абстрактное синтаксическое дерево (ast), которое затем будет скомпилировано и выполнено. Если вы вручную создаете синтаксическое дерево ast с помощью
self.foo
заняв место
var
в
(var := temp)
а потом
compile
или же
exec
это дерево, оно компилируется и выполняется так, как вы интуитивно ожидали.
Таким образом, очевидно, что основная функциональность предназначена для того, чтобы разрешить назначение моржа для object.attributes, они просто решили не позволять нам его использовать, потому что боялись, что это заставит людей писать запутанный код или что-то в этом роде. Большое спасибо...
В любом случае, крайним (совсем не рекомендуемым!) Решением было бы для вас сделать небольшую предварительную компиляцию ast-gery, чтобы объединить целевые объекты object.attribute с вашими операторами моржа, и тогда он, вероятно, будет работать так, как вы ожидаете. .(Я обнаружил это, так как уже делал аст-хирургию, заменявшую простые переменные на object.attributes по другим причинам, и я был рад обнаружить, что назначение моржа все еще работает!)