繁体   English   中英

从 Python 的内部装饰器中获取 function 或 class 方法名称

[英]Get function or class method name from inside decorator in Python

我有一个以下装饰器。

def allow_disable_in_tests(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        version = ??? # name of the func of method’s class name
        need_to_switch_off_in_tests = cache.get('switch_off_in_tests', version=version)

        if settings.IM_IN_TEST_MODE and need_to_switch_off_in_tests:
            return None

        value = func(*args, **kwargs)
        return value
    return wrapper

这个装饰器可以接受 2 种类型的对象作为func

  1. 独立 function。

  2. 类的方法(绑定方法,static 方法和 class 方法都可能)

问题是如何从内部装饰器名称中获取:

  1. function 在func的情况下是独立的 function。

  2. func的情况下,方法的 class 名称是 class 的方法

这将在version中使用。

装饰器应该能够处理这两种类型的对象。

谢谢

您可以使用__qualname____module__来获取此信息。 __qualname__将描述根据 class 或 function 在模块中定义 class 的位置。

但是,您将测试逻辑放入生产代码中,这有点代码味道。 在运行测试套件时,最好使用测试框架的猴子修补功能来修补这些功能。 例如,对于 pytest:

import pytest
from functools import wraps
from inspect import signature

class FuncPatch:
    def __init__(self, parent, name, retval=None):
        self.parent = parent
        self.name = name
        self.retval = retval

def get_things_to_patch():
    import mymodule
    return (
        FuncPatch(mymodule, 'my_func'),
        FuncPatch(mymodule.MyClass, 'method'),
        FuncPatch(mymodule.MyClass, 'static'),
        FuncPatch(mymodule.MyClass, 'class_', retval='special'),
    )

def create_test_function(func, retval, decorator=None):
    func = getattr(func, '__func__', func) # unwrap if classmethod or normal method
    sig = signature(func)
    @wraps(func)
    def f(*args, **kwargs):
        # check func was called with correct params raises TypeError if wrong
        sig.bind(*args, **kwargs)
        return retval
    if decorator:
        f = decorator(f)
    return f

@pytest.fixture
def patch_all_the_things(monkeypatch):
    for patch in get_things_to_patch():
        decorator = None
        if (isinstance(patch.parent, type)
                and not callable(patch.parent.__dict__[patch.name])
        ):
            # quick hack to detect staticmethod or classmethod
            decorator = type(patch.parent.__dict__[patch.name])

        to_patch = getattr(patch.parent, patch.name)
        func = create_test_function(to_patch, patch.retval, decorator)
        monkeypatch.setattr(patch.parent, patch.name, func)

# things to test
def my_func():
    return 'my_func'

class MyClass:
    @staticmethod
    def static():
        return 'static'
    @classmethod
    def class_(cls):
        return 'class'
    def method(self):
        return 'method'

# actual tests
def test_my_func(patch_all_the_things):
    assert my_func() is None

def test_my_class(patch_all_the_things):
    assert MyClass().method() is None
    assert MyClass.method(MyClass()) is None
    assert MyClass.static() is None
    assert MyClass.class_() == 'special'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM