You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python装饰器内获取函数或类方法名称的实现方案

Solution for Getting Function/Class Name in Decorator

Got it, let's tackle this problem step by step. The core challenge is to reliably distinguish between standalone functions and class methods (including instance, class, and static methods) and extract the correct name for your version variable. Here's a robust implementation that handles all cases:

Full Decorator Code

import functools

def allow_disable_in_tests(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        def get_version():
            # Case 1: Bound methods (already attached to an instance or class)
            if hasattr(func, '__self__'):
                # For class methods, __self__ is the class itself
                if isinstance(func.__self__, type):
                    return func.__self__.__name__
                # For instance methods, get the class from the instance
                return func.__self__.__class__.__name__
            
            # Case 2: Unbound methods/static methods defined in a class
            elif '.' in func.__qualname__:
                parts = func.__qualname__.split('.')
                # Grab the direct class name (handles nested classes too)
                return parts[-2] if len(parts) >= 2 else func.__name__
            
            # Case 3: Standalone function
            else:
                return func.__name__
        
        version = get_version()
        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
        
        return func(*args, **kwargs)
    return wrapper

How It Works

Let's break down each case in the get_version helper:

  • Bound Methods: When the decorated function is already bound to an instance (e.g., my_obj.instance_method) or class (e.g., MyClass.class_method), it has a __self__ attribute. We check if __self__ is a class (for class methods) or an instance (for instance methods) to get the correct class name.
  • Unbound Class/Static Methods: When you apply the decorator directly to a method inside a class definition (before it's bound to an instance/class), the __qualname__ attribute holds the full path like ClassName.method_name (or OuterClass.InnerClass.method for nested classes). We split this string to grab the direct class name.
  • Standalone Functions: If none of the above conditions are met, we're dealing with a standalone function, so we just use its __name__.

Test Cases

Here's how this works with different function types:

# Standalone function → version = "my_standalone_func"
@allow_disable_in_tests
def my_standalone_func():
    return "Hello from standalone"

class MyService:
    # Instance method → version = "MyService"
    @allow_disable_in_tests
    def process_data(self):
        return "Processing data"
    
    # Class method → version = "MyService"
    @classmethod
    @allow_disable_in_tests
    def cleanup(cls):
        return "Cleaning up"
    
    # Static method → version = "MyService"
    @staticmethod
    @allow_disable_in_tests
    def validate_input(data):
        return data is not None

# Nested class example → version = "NestedService"
class OuterService:
    class NestedService:
        @allow_disable_in_tests
        def run(self):
            return "Running nested service"

Notes

  • This relies on __qualname__, which was added in Python 3.3. If you need to support older versions, you'd need a fallback (though most modern codebases use 3.3+ now).
  • For nested classes, this grabs the direct containing class name (e.g., NestedService instead of OuterService.NestedService). If you need the full class path, replace parts[-2] with '.'.join(parts[:-1]).

内容的提问来源于stack exchange,提问作者Aleksei Khatkevich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 08:02:38