【问题标题】:How to configure a decorator in Python如何在 Python 中配置装饰器
【发布时间】:2019-09-05 12:57:43
【问题描述】:

我正在尝试使用 Thespian (https://thespianpy.com/doc/),这是一个用于演员模型的 Python 库,特别是我正在尝试使用“剧团”功能。据我了解,troupe 装饰器充当调度程序,以运行多个 actor 直到指定的 max_count,每个 actor 并行运行。剧团功能用作我的演员类的装饰器:

@troupe(max_count = 4, idle_count = 2)
class Calculation(ActorTypeDispatcher):
    def receiveMsg_CalcMsg(self, msg, sender):
        self.send(sender, long_process(msg.index, msg.value, msg.status_cb))

我想在运行时而不是设计时配置 max_count。我承认我对装饰器的基础知识很薄弱。

如何在运行时将值传递给 max_count?

我已经经历了这些,但我仍然在黑暗中:

Does python allow me to pass dynamic variables to a decorator at runtime?

http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/

根据到目前为止的答案,我尝试了这个,但没有应用装饰器(即它表现得好像没有装饰器)。我注释掉了类上方的@troupe 实现,该方法(包括变量)工作正常。这种方法不是:

# @troupe(max_count=cores, idle_count=2)
class Calculation(ActorTypeDispatcher):
    def receiveMsg_CalcMsg(self, msg, sender):
        self.send(sender, long_process(msg.index, msg.value, msg.status_cb))

def calculate(asys, calc_values, status_cb):
    decorated_class = troupe(max_count=5, idle_count=2)(Calculation)
    calc_actor = asys.createActor(decorated_class)

calculate 函数中还有其他内容,但这几乎只是一些记账。

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    装饰器语法只是将函数应用于类的快捷方式。 一旦知道max_count 的值,您就可以自己调用该函数。

    class Calculation(ActorTypeDispatcher):
        ...
    
    # Time passes
    
    c = input("Max count: ")
    Calculation = troupe(max_count=int(c), idle_count=2)(Calculation)
    

    (或者,等到您确实拥有c,然后再将Calculation定义为shown by @brunns。)

    【讨论】:

    • 哦,我记得看到过这种格式的装饰器应用程序,但是你的插图非常具体和有用。我不认为我可以访问被调用的类,但我可以:calc_actor = asys.createActor(Calculation)
    • 哦,我刚刚注意到一些事情,不确定是否是故意的……类名需要左右相同吗?在我的代码中,我说decorated_class= troupe()(Calculation)。必须如您所说明的那样,Calculation = troupe()(Calculation) 吗?当我这样做时,我得到UnboundLocalError: local variable 'Calculation' referenced before assignment。是的,我的 Calculation 类是在我尝试调用之前定义的。
    • 可以使用不同的名称;也许您想要原始类 由装饰器创建的类。如果您在 another 函数中调用 troupe,则分配给 Calculation 的事实使其成为函数中的局部变量 anywhere,因此装饰器 不是 引用原始类的全局名称。如果是这种情况,您可能需要使用 global 语句来确保 global 变量绑定到新类,或者您确实需要使用不同的名称。
    • troupe 在我导入的模块中定义。我的Calculation 类是在我试图使用此方法应用装饰器的函数的正上方定义的。我修改后的问题末尾的代码不起作用,但如果我省略 Calculation 例如,装饰器会抱怨它没有提供。是不是这个装饰器不支持这种应用方式?
    • 我删除了之前的评论; troupe 返回一个基本上采用类的函数,并用包装旧方法的新方法替换该类的 receiveMessage 方法。因此,在这种情况下,您确实 获得了对 已修改的原始类的引用。 (在这一点上,我对thespian 库的了解还不够,无法说明它是如何工作的。)
    【解决方案2】:

    应该很简单:

    
    my_max = get_max_from_config_or_wherever()
    
    @troupe(max_count = my_max, idle_count = 2)
    class Calculation(ActorTypeDispatcher):
        ...
    

    要记住的是classdef 语句本身会被执行。

    【讨论】:

    • 我猜 my_max 需要是某种全局变量或模块变量?
    • 一个模块变量会很好,是的 - 但你也可以内联函数调用。
    • @troupe(max_count=get_max_from_config_or_wherever(), idle_count=2) 可以。
    • 我猜这些都与确保您在调用装饰器之前或调用装饰器时定义变量有关,而我很难想象这一点。很有帮助,谢谢。
    • 在我的实验中,my_max 的值是在导入时评估的,而不是在运行时...有没有办法改变这种行为,以便我可以改变 my_max 的值运行时间?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    • 2011-11-20
    • 2023-02-08
    • 1970-01-01
    相关资源
    最近更新 更多