>
> I just thought it looked better, but would you and others here like it
> better if the
> NEWLINE requirement was kept for all decorators? There is nothing in the
> original
> proposal that requires a single line.
> I also don't know what should happen for complicated assignments, and I
> think this
> has been the death of such variable decorator discussions in the past, so
> I would
> still push for only bare identifiers, with or without a type hint (but
> maybe it will be
> better received by more if the type hint is required?). I still think such
> a proposal is
> strong enough on its own to be of value to the language.
>
> So now the syntax would be:
>
> @decorator
> variable: Type
>
> @decorator("spam", eggs)
> variable: Type
>
> become
>
> variable = decorator("variable")
>
> variable = decorator("spam", eggs)("variable")
>
> I'm not sure that the type hint shouldn't be passed as an additional
> parameter,
> especially if one is always required. Yes it is still different from a
> function
> decorator in that you are not getting the variable object (which may or
> may not
> exist) but instead its name as a string. However, decorators that expect
> to be
> applied to variables should already be drastically different. Even if they
> did get
> the variable object, there would be not necessarily be a __code__ or
> __name__ or __dict__ attribute. They won't be callable (generally) where
> most
> current decorators attempt to call func, wrapped in an internal closure.
>

I think there's a fundamental difference between your original proposal and
the OPs proposal in this thread, which is that you seem to envision
variable decorators as granting access to just a name (and potentially a
type-hint?), whereas the OP wants the decorators extended to assignment in
general.

Basically, your proposal is a subset of the OPs proposal. Any
implementation of the OPs decorators would also allow us to do all the
things you want to be able to do with variable decorators (as a happy
side-effect), but would also offer a LOT more functionality.

My view is that variable decorators should be legal for:

1) assignment statements (so that the decorator can modify or replace the
object that is getting assigned)
2) bare type-hints, since these are arguably *a sort of* assignment
operation that still carries useful info a decorator might want to capture
(you're not assigning the name and its value to globals(), but rather the
name and its type to globals()['__annotations__'])

If there was huge pushback against point 2 I'd be happy to see it deferred
and revisit it at a later point, but as far as I'm concerned point 1 is
what actually interests me about this proposal.

Your point about complicated assignment being a problem seems solvable
using the following rules:

1) Variable decorators only capture the name (or names) on the LHS of a
true assignment statement (or bare type-hint). Expressions that happen to
bind names (such as the walrus operator, for loop, etc.) don't have their
names available for use in the decorator.
2) The proposed __decoration_call__ is given the value, name, and type-hint
from the decorated statement (and potentially the code object from the RHS,
as OP suggested). We could provide the names as a series of useful
pre-parsed parsed AST-like objects, like:

@decorate
some_obj.foo = first, _, third, *some_obj.rest = some_dict[(lost_name
:= ('ba' + 'r'))] = baz = (another_lost_name := [0, 1, 2, 3, 4])

such that __decoration_call__ receives:

def __decoration_call__(self, obj, names, annotation):
    print(obj)
    # [0, 1, 2, 3, 4]

    print(names)
    # ParsedNames(names=[
    #     ObjectAssignment(obj={reference_to_some_obj}, name='foo'),
    #     DestructuringAssignment(names=[
    #         BasicAssignment(name='first'),
    #         BasicAssignment(name='_'),
    #         BasicAssignment(name='third'),
    #         ObjectAssignment(obj={reference_to_some_obj}, name='*rest')
    #     ]),
    #     ItemAssignment(obj={ref_to_some_dict}, name='bar'),
    #     BasicAssignment(name='baz')
    # ])

    print(annotation)
    # NOTSET


Notice that as per point 1 above, `lost_name` and `another_lost_name` do
not get captured, because they are not part of the assignment statement.
They're only sub-expressions.
Also, notice that expressions like 'ba' + 'r' are evaluated before being
passed to the decorator, so that it actually receives 'bar' for the
__setitem__ assignment name.

3) Augmented assignment gets expanded out to its true meaning before being
passed to the decorator, so for example:

foo = 3

@decorate
foo += 2


behaves exactly the same as:

foo = 3

@decorate
foo = foo + 2



If there are still any issues given these rules that I can't think of I'd
be happy for people to raise them. There are so many edge-cases in python
assignment that I could very easily be forgetting about something. But I
think this covers 99% of cases.


class Colors(Enum):
>     @str
>     RED: str
>     @str
>     GREEN: str
>     @str
>     BLUE: str
>
> @namedtuple("x y z")
> Point: NamedTuple
>
> @os.getenv
> PATH: Optional[str]
>


With decorated assignments these examples could instead look something like:

class Color(Enum):
    @string_values
    RED, GREEN, BLUE = auto()


Here the decorator would return a tuple like: ('RED', 'GREEN', 'BLUE'),
which would be assigned instead of whatever is actually on the RHS

And for the namedtuple:

@namedtuple
Point = 'x', 'y', 'z'


The third one would look just like you suggested.



On Sat, May 29, 2021 at 3:28 AM micro codery <ucod...@gmail.com> wrote:

> Ah, I think you might be missing the context of the original proposal? I
> do mean bare unbound identifiers - at lease as they occur in this new
> syntax.
>
> # currently works
> spam = “eggs”
> spam: eggs
>
> # currently a NameError
> spam
>
> # proposed to work, currently illegal
>
> @spam
> eggs
>
> @spam(“eggs”)
> cheese
>
> @spam
> eggs: str
>
> But none of this would change the first three examples.
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/JETD7GGN2HKKL3E6A2XNRTCASAMIQQM5/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/54RQI7R46KSDB2KJPWQIUHUHPO55PIZT/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to