Python 从装饰器中的名称获取装饰类?

Python 从装饰器中的名称获取装饰类?,python,python-decorators,introspection,Python,Python Decorators,Introspection,我用@bot\u thinking修饰了一些方法,它在函数属性中存储了一些关于修饰方法的信息。 其中一条信息是“class_name”,但我的程序需要类类型作为变量,例如RandomBot。我想上这门课 以下是一些示例代码: class DepthPrunedMinimaxAgent(Agent): @bot_thinking(associated_name="minimax profondeur") def select_move(self, game_state: GameS

我用
@bot\u thinking
修饰了一些方法,它在
函数
属性中存储了一些关于修饰方法的信息。 其中一条信息是“class_name”,但我的程序需要类类型作为变量,例如
RandomBot
。我想上这门课

以下是一些示例代码:

class DepthPrunedMinimaxAgent(Agent):
    @bot_thinking(associated_name="minimax profondeur")
    def select_move(self, game_state: GameState):
上面是代码的装饰部分

装饰师:

functions = {}

def bot_thinking(associated_name, active=True):
    def _(func):
        if active:
            class_name = func.__qualname__.rsplit('.')[-2]
            import sys
            # class_name_2=getattr(sys.modules[__name__], class_name)
            # module=importlib.import_module('sources.agent')

            functions[associated_name] = (associated_name, class_name,
                                          globals()[class_name], func)
        else:
            functions.pop(associated_name)

    return _
bot\u thinking
不是一个真正的装饰师,它是一个装饰师工厂。 从
func
函数中,我得到了
类的名称,但是我不能使用by@m.kocikowski来找到正确的类,因为这个类是修饰的,所以它已经导入了注释模块,所以从注释模块导入注释模块将导致循环导入,python似乎不允许这样做

您看到一个从类的名称获取类的方法了吗

附言: 附言:
更清楚的是:代码的注释部分需要导入到注释类(从其名称检索类),这也需要导入注释(注释才能工作)。

问题是当
bot\u thinking()
装饰器工厂(以及装饰器本身)时,类还没有定义我们正在执行。我能想到的唯一解决方法是在定义类后修补问题,如下所示:

from pprint import pprint, pformat

functions = {}

def bot_thinking(associated_name, active=True):
    def _(func):
        if active:
            class_name = func.__qualname__.split(".")[-2]
            functions[associated_name] = (associated_name, class_name, class_name, func)
        else:
            functions.pop(associated_name, None)

        return func # Decorators must return a callable.

    return _


class Agent: pass
class GameState: pass

class DepthPrunedMinimaxAgent(Agent):
    @bot_thinking(associated_name="minimax profondeur")
    def select_move(self, game_state: GameState):
        pass

# After class is defined, update data put into functions dictionary.
for associated_name, info in functions.items():
    functions[associated_name] = (info[0], info[1], globals()[info[2]], info[3])

pprint(functions)
输出:

{'minimax profondeur':('minimax profondeur',
“DepthPrunedMinimaxAgent”,
,
)}

问题在于,当执行
bot\u thinking()
装饰器工厂(以及装饰器本身)时,类尚未定义。我能想到的唯一解决方法是在定义类后修补问题,如下所示:

from pprint import pprint, pformat

functions = {}

def bot_thinking(associated_name, active=True):
    def _(func):
        if active:
            class_name = func.__qualname__.split(".")[-2]
            functions[associated_name] = (associated_name, class_name, class_name, func)
        else:
            functions.pop(associated_name, None)

        return func # Decorators must return a callable.

    return _


class Agent: pass
class GameState: pass

class DepthPrunedMinimaxAgent(Agent):
    @bot_thinking(associated_name="minimax profondeur")
    def select_move(self, game_state: GameState):
        pass

# After class is defined, update data put into functions dictionary.
for associated_name, info in functions.items():
    functions[associated_name] = (info[0], info[1], globals()[info[2]], info[3])

pprint(functions)
输出:

{'minimax profondeur':('minimax profondeur',
“DepthPrunedMinimaxAgent”,
,
)}

如果您使用描述符类而不是函数作为装饰器,您可以随心所欲,至少如果您使用的是Python 3.6或更高版本。这是因为描述符协议中添加了一个新方法。当描述符对象保存为类变量时,将调用它。虽然大多数描述符将使用它来记录它们保存为的名称,但您可以使用它来获取您所在的类

您确实需要让decorator对象包装真正的函数(实现调用和描述符查找方法),而不是返回您正在装饰的未修改的函数。下面是我尝试快速而肮脏的实现。我真的不明白你在用
函数做什么,所以我可能没有在里面放正确的数据,但它应该足够近,可以让人理解(
owner
是方法存储的类)


如果您使用描述符类而不是函数作为装饰器,那么您可以做您想做的事情,至少如果您使用的是Python 3.6或更新版本。这是因为描述符协议中添加了一个新方法。当描述符对象保存为类变量时,将调用它。虽然大多数描述符将使用它来记录它们保存为的名称,但您可以使用它来获取您所在的类

您确实需要让decorator对象包装真正的函数(实现调用和描述符查找方法),而不是返回您正在装饰的未修改的函数。下面是我尝试快速而肮脏的实现。我真的不明白你在用
函数做什么,所以我可能没有在里面放正确的数据,但它应该足够近,可以让人理解(
owner
是方法存储的类)


为了确保我理解:这个想法是当你装饰
选择_move
时,就像在第一个例子中一样,你希望装饰器能够查找包含
DepthPrunedMinimaxAgent
(你试图确定它的字符串名,并在
globals()
中查找,这不起作用)?可以如果装饰过的函数不在类内,你会怎么做?谢谢观看。这不会发生,因为注释涉及代理子类的特定方法。为了确保我理解:这个想法是,当您像第一个示例中那样装饰
选择\u move
时,您希望装饰器能够查找包含
DepthPrunedMinimaxAgent
(您正试图确定它的字符串名称,并在
globals()
中查找该名称,但该名称不起作用)?好的…如果修饰的函数不在类中,你会怎么做?谢谢你的关注。这不会发生,因为注释涉及代理子类的特定方法。好吧,我理解答案,这是可能的,但有点烦人,因为@bot_思想的目的是摆脱所有沉重和危险的元代码,好吗这不是机器人声明或机器人攻击。你谈到了其他答案,它们是什么?洛维利:这可能不是唯一的解决办法,只是我能想到的唯一一个-当然,这并不一定意味着没有任何其他的。核心问题是
定义在Python中是可执行的,这使得它成为im可能(AFAIK)在该过程完成之前引用它们)。好吧,我理解答案,这是可能的,但有点烦人,因为@bot_思维的目的是摆脱所有沉重和危险的元代码,而不是机器人声明或机器人攻击。你谈到了其他答案,它们是什么?洛维利:这可能不是唯一的解决办法,只是我能想到的唯一一个——当然,这并不一定意味着没有其他答案。核心问题是
class
定义在Python中是可执行的,这使得(AFAIK)fo不可能实现