Variable decorators have been suggested here before, as have new statements
that could also achieve the same level of access to the binding name. However
I propose a much more restricted syntax that would make for less edge cases
where what is actually passed to the decorator callable may be ambiguous.

Basically this would add syntax to python that would transform
@decorator("spam this") variable
into
variable = decorator("variable", "spam this")

The decorator would be limited to being on the same line as the variable name.
Additionally, the variable can not also be assigned to on the same line, so
@decorator("spam this") variable = eggs
would be a SyntaxError. Annotating these variable would be allowed
@decoratopr("spam this") variable: Food
The actual decorator would follow the same rules as current decorators in that
the parentheses can be omitted if no other arguments are required to the
function and any arbitrary expression can be used, however the same restraint
should be cautioned as is for current decorators post PEP 614.

The most straightforward use of this decorating would be that str() could be
used without change to declare variables that are strings of the same name,
generally cutting down on repeating yourself when declaring constants.

#instead of GREEN = "GREEN"
@str GREEN

The classic example of a factory that needs its target name as a string value
is namedtuple. I don't think this example is enough alone to sway this list but
I bring it up as it has also been at the front of past ideas to allow variable
decorating.

#instead of Point = namedtuple("Point", "x y z")
@namedtuple("x y z") Point

I have sometimes heard that dataclasses make this no longer an issue, implying
that dataclasses can be used in place of namedtuple in any new code. Putting
aside that dataclasses are not a strict replacement for namedtuple, the
dataclasses module continues this factory design with the make_dataclass
function.

#instead of Point = make_dataclass("Point", [("x", int), ("y", int), ("z", int)])
@make_dataclass([("x", int), ("y", int), ("z", int)]) Point

Enum is one more case where there is a factory equivalent to the class
declaration.

#instead of Colors = Enum("Colors", "RED GREEN BLUE")
@Enum("RED GREEN BLUE") Colors

If you want each enum member value to match its name there is even more
repetition, however by using the original example for decorated variables, this
can be reduced when using the more common class style.

class Colors(Enum):
    @str RED
    @str GREEN
    @str BLUE

One final standard library module that I will mention because it seems to keep
adding similar factory functions is typing. It already has the factory functions
NewType, TypeVar, ParamSpec, TypedDict, NamedTuple. Their use with the new
variable decorator would look much the same as earlier examples, but here would
be one case where type hinting the variable in such a statement could aid the
decorator function

#instead of UUIDType = NewType("UUIDType", str)
@NewType UUIDType: str

If adopted, no change to these functions would be necessary to allow their use
as a variable decorators as they all already take the name as a string in the
first argument. Additionally, as variable decorators are actually callables just like
the current decorators, no new restrictions are being forced on users of the language.
If a user really wants to create a namedtuple with a typename of Foo but assign
the result to a variable named ___trippleS33cret___name__here_ the language
will not stop them.


I would very much like to know if any module maintainers are interested in this
syntax. Convincing arguments from the standard lib (whether you consider the
above convincing or not) are probably not enough to get a syntax change into
python. But if enough third party modules want to use this functionality I
believe that would be the real push to get it done.

Specifically this idea first started growing when I read on another ideas
message that using the module sympy would often start with a line like
x = symbol('x')
which, with no change, could be used as a variable decorator
@symbol x
Now what may be even more typical (I really have never used the module myself)
is defining all needed symbols on one line with
x, y, z = symbol('x y z')
which could conceivably be rewritten like
@symbol x, y, z
However I have not yet been able to decide if multi-assignment would be overall
beneficial to this new syntax. Probably not, at least at this stage. It would
not be hard for a decorator function to return multiple values, but how would
the multiple names be passed in? A string with whitespace like this original,
and namedtuple's field_names, is possible as no valid identifier can have a
space in it. However, it forces any would-be variable decorator to know this
and check if a space is in its first argument, even if it cannot produce
multiple values. Another option is to pass in an iterable, but the same
additional effort would be placed on decorators that otherwise don't want to
deal with multi-assignment. Unpacking the names as the first n arguments would
mean that decorators that just want one variable can get just that and those
that may want more will also get them, but then practically no variable decorator
could take additional non-keyword arguments.

Regards
~ Jeremiah