Another problem I have with this proposal is the new dunder method. Why 
do we need a new dunder? We're probably never going to "decorate" a 
variable and function with the same callable, the two use-cases are very 
different. But even if we do, we can easily distinguish the two cases.

Let's dump the `__decorate_call__` dunder and just use normal call 
syntax. That will be a HUGE win for useability: any function, class or 
callable object can be used as the decorator, it doesn't have to be a 
custom object with a custom class that defines a special dunder.

We can distinguish the two contexts by using different signatures. The 
signature used depends entirely on the call site, not the decorator, so 
it is easy for the interpreter to deal with.

If the decorator is called on a function or class statement, a single 
argument is always passed, no exceptions:

    # always calls decorate with one argument
    @decorate
    def func():  # or class
        pass

    # --> func = decorate(func)

If called on a variable, the number of arguments depends on whether it 
is a bare name, or a value and annotation are provided. There are 
exactly four cases:

    # bare name
    @decorate
    var
    # --> var = decorate('var')

    # name with annotation
    @decorate
    var: annot
    # --> var = decorate('var', annotation=annot)

    # name bound to value
    @decorate
    var = x
    # --> var = decorate('var', value=x)

    # name with annotation and value
    @decorate
    var: annot = x
    # --> var = decorate('var', annotation=annot, value=x)


Keyword arguments are used because one or both of the value and the 
annotation may be completely missing. The decorator can either provide 
default values or collect keyword arguments with `**kwargs`.

The only slightly awkward case is the bare variable case. Most of the 
time there will be no overlap between the function/class decorators and 
the bare variable decorator, but in the rare case that we need to use a 
single function in both cases, we can easily distinguish the two cases:

    def mydecorator(arg, **kwargs):
        if isinstance(arg, str):
            # must be decorating a variable
            ...
        else:
            # decorating a function or class
            assert kwarg == {}

So it is easy to handle both uses in a single function, but I emphasise 
that this would be rare. Normally a single decorator would be used in 
the function/class case, or the variable case, but not both.


-- 
Steve
_______________________________________________
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/3VAC7Y6DYL77EPB6X6XS3AGIAZX22MOG/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to