[Python-ideas] Python Decorator Improvement Idea

Brian Allen Vanderburg II brianvanderburg2 at aim.com
Fri Jun 15 23:54:42 EDT 2018


Just a small idea that could possibly be useful for python decorators.

An idea I had is that it could be possible for a decorator function to
declare a parameter which, when the function is called as a decorator,
the runtime can fill in various information in the parameters for the
decorator to use.  Some of the information would be available in all
contexts, while other information may only be available in certain
contexts.The parameter's value cannot be explicitly specified, defaults
to Null except when called as a decorator, and can only be specified
once in the function's parameter list.

Called as a decorator implies:

	@decorator
	def decorated():
	    pass

These are not called as a decorator.  The first item's return value
would be called as a decorator, thus if it has a decorator parameter, it
would be used.

	@decorator(...)
	def decorated():
	    pass

	def decorated():
	    pass
	decorated = decorator(decorated)

Any declared callable (function, class instance with __call__, etc) can
have an explicitly declared parameter called a decorator information
parameter. The syntax could be as follows.  "info" is just a name I've
chosen and could be any legal name.

	def decorator(..., @info):
	    pass

	def wrapper(..., @info):
	    def decorator(obj, @info):
	        ...
	        return obj
	    if info:
	        called directly as decorator, do something
	    else:
		return decorator


Rules:

1. It is not possible for the parameter's value to be directly
specified. You can't call fn(info=...)
2. The parameters value is Null except in the cases where it is invoked
(the callable called a a decorator).  If used in a partial, the
decorator parameter would be Null. etc.


Information that could be contained in the parameters for all contexts:

Variable name
Module object declared in
Module globals (useful for @export/@public style decorators)
Etc

Using the decorator in a class context, pass the class object.  While
the class object hasn't been fully created yet, this could allow
accessing attributes of the class (like a registry or such)

	def decorator(fn, @info):
	    if hasattr(info, "class_obj"):
	        registry = info.class_obj.__dict__.setdefault("_registry", [])

	    registry.append(fn)
	    return fn

	class MyClass(Base):

	    # Add "method" to the MyClass._registry list
	    @decorator
	    def method(...):
        	pass

	    def call_all(cls):
	        for method in self._registry:
	            method(self)


This could also make it possible to use decorators on assignments.
Information could be passed to the decorator by the runtime:

    script_vars = {}
    def expose(obj, @info):
        script_vars[info.name] = obj
        return obj

    def load(filename):
        # load script and compile
        exec(code, script_vars)  

    @expose
    def script_function(...):
        pass

    # This will call the decorator passing in 200 as the object, as well as info.name as the variable being assigned.
    @expose
    SCRIPT_CONSTANT = 200

    # If stacked, only the first would be used as info.name, in this case SCRIPT_CONSTANT2
    @expose
    SCRIPT_CONSTANT2 = A_VAR = 300

    def default(obj, @info):
        if info.name in info.ctx.vars:
	    return info.ctx.vars[info.name]
        if info.name in info.globals:
            return info.globals[info.name]
	return obj

    @default
    X = 12

    @default
    X = 34

    print(X) # print 12 since during the second call, X existed and it's value was returned instead of 34, and was assigned to X


The two potential benefits I see from this are:

1. The runtime can pass certain information to the decorator, some
information in all contexts, and some information in specific contexts
such as when decorating a class member, decorating a function defined
within another function, etc
2. It would be possible to decorate values directly, as the runtime can
pass relevant information such as the variables name

This was just an idea I had that may have some use.

Thanks,

Brian Vanderburg II

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180615/2048ba77/attachment-0001.sig>


More information about the Python-ideas mailing list