Python C Extension Decoder

I apologize in advance for the long background information.

I recently met with the Python / C-API (Python 3.4) and got a dead end. My goal is to have a C extension that I can use as a function / method decorator. I have a fairly experienced prototype for the LRU cache in gist, https://gist.github.com/pbrady/916495198910e7d7c713 . Although the cache works and works very fast, there are two problems:

  • typereturned by my decorator does not work: ie

    >>> from lrucache import lrucache
    >>> @lrucache()
    ... def f(a, b):
    ...    return a+b
    ...
    >>> type(f)
    >>> <class 'lrucache.cache'>
    

    Because of this, the decorator does not work properly on methods - it seems to be selflost because Python does not create an instance method when it sees my class (which makes sense).

  • Copying __doc__from a decorated function to my cache class does not affect the message displayed help.

My idea to get around these problems was to simply return a user-defined function with several modifications, rather than with a new user-defined class. These changes

  • Add an attribute __wrapped__to the function and specify its function.

  • Overwrite attribute __call__so that function calls are routed to user C routine.

I was able to fulfill (1), but redefining the functions of the __call__method does nothing, since it is usually not used by the interpreter.

My question is (finally): How to create a Python function (i.e. PyFunctionObject) that will call the C function?

, , . / , Cython.

+4
1

(2), , , , :

In [1]: class Test:
   ...:     def __call__(self):
   ...:         print('Called class attribute!')
   ...:         

In [2]: t = Test()

In [3]: def new_call():
   ...:     print('Called instance attribute!')
   ...:     

In [4]: t.__call__ = new_call

In [5]: t()
Called class attribute!

function class __call__, python.

, PyFunctionObject, PyFunction_New. , PyCodeObject , :

, . , , - , .

:

  • lrucache a descriptor. , python , self , .

  • python, C ​​, :

    from functools import wraps
    
    from _lrucache import cache
    
    def lrucache(func):
        cached_func = cache(func)
    
        @wraps(func)
        def wrapper(*args, **kwargs):
            return cached_func(*args, **kwargs)
    
        return wrapper
    

    , python.

  • . , python , , , . , ...

+4
source

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


All Articles