📜 ⬆️ ⬇️

Add a little more reflection: decorators

Recently, you have to work quite a bit with Python. Solving one of the current tasks, it became necessary within the function decorator to check whether the decorated method was decoded by another decorator. Unfortunately, the standard means of reflection of the language do not allow it. More precisely, using, for example, the inspect module from the standard library can do this, but it really didn’t like this approach.

Under the cut is your own method for solving a problem that has resulted in a small library available for general use.

So, it was decided to create and use some special register of decorators. Those. register any decorator function in this registry before using it as a decorator. After that, using the registry API, you can simply track the use of registered decorators on methods, functions and modules.

Nevertheless, there are a few rules to remember. Registering built-in decorators will not work. That is, unfortunately, it is impossible to track decorators such as @staticmethod , @classmethod and the like (if someone can find a solution to this problem, I will be very grateful). And most importantly, decorators must be registered before they are used .
')
In fact, the mechanics of the registry is quite simple. By registering a decorator, you actually get a decorated source decorator which, in addition to its original functionality, also records information about itself in the attribute "__annotations__" of the function being decorated.

If a function (or method) is decorated by several decorators, it is important only to register all decorators before using them and all decorators will be correctly taken into account. Ie, the construction of the form:

 @decorator_one @decorator_two @decorator_three def some_function(): pass 


will work successfully.

The library “regd” (as I called it) is compatible with both Python 2.x and version 3.x (we use both branches on our projects, so compatibility has been tested).

The source code is available on Github , the license, as always - MIT, so do whatever you want.

Documentation is here .

You can install it just through PyPI:

 $ pip install regd 


Below are a few words about the functionality.

1. Registration decorators.

“Ordinary” and “parameterized” decorators should be registered using different methods:

 from regd import DecoratorRegistry as dreg #  ""  simple_decorator = dreg.decorator( mydecorator) #  ""  param_decorator = dreg.parametrized_decorator( param_decorator) 


2. Reflection API

To make the API functions more understandable, let's first create and register a simple decorator, which in fact does nothing, but simply exists.

 from regd import DecoratorRegistry as dreg #   def mydecorator( fn) : #    -  ... def wrapper( *args, **kwargs) # ...   -  ... return fn( *args, **kwargs) return wrapper #    mydecorator = dreg.decorator( mydecorator) 


Remember - register decorators need to use them .

Now, after registering, we can use our decorator as usual:

 @mydecorator def myfunc() : pass 


Now, at any time from any place in the code, we can find out whether the function has been decorated by the decorator:
 print( dreg.is_decorated_with( myfunc, mydecorator)) 


Some more useful methods:



I hope someone will come in handy or seem useful. All comments and suggestions are welcome.

Source: https://habr.com/ru/post/178017/


All Articles