Python 装饰器早期解析破坏了前向声明

Python decorator early parsing breaks a forward declaration

我在系统中有一些对象需要知道他们的下一个对象是谁。每个都有一个 do_process() 函数,完成后必须 return 下一个 class。

class A():
    def do_process(self):
        # dosomestuff
        return B(self)

class B():
    def do_process(self):
        # dosomestuff
        return C(self)

class C():
    def do_process(self):
        # dosomestuff
        return A(self)

a = A()
b = a.do_process()
c = b.do_process()
a2 = c.do_process()

然后我注意到我的所有函数在 return 时都做同样的事情,我真的应该为此编写一个装饰器。为了清楚起见,我想整理 do_process 中的最后一行,以明确表示它将 return 使用装饰器,因此它看起来像这样:

@next_process(B) # tell the reader up front that the next object is a B thing
def do_process
   # do some stuff
   # next_process decorator returns an instance of B for us

在我的实现中,构造函数接受了一些参数,但它始终是相同的参数,因为 A、B、C 在我的代码中覆盖了一个基数 class。 classic Factory 模式问题。但是,我立即 运行 陷入困境,因为装饰器开始在 class A 中解析它,而 B 尚未声明。我也是垃圾写装饰器,所以我写了一个工厂希望用字符串“B”替换B,让工厂在运行时提供下一个对象给装饰器。但这变坏了,因为我只能在 B 完全声明后将 class B 添加到我的工厂。然而,装饰器已经想要获得 B 的副本,它实际上在解析 A 的同时调用了我的工厂,所以它在工厂之前调用了我的工厂,或者任何人实际上知道 B(class A 本身,甚至没有注册此时也可以在工厂中)。

class A()
   @next_decorate(next=factory("B"))  # <= blows up because the factory has not yet got a way to return class B
   def do_process(self)
      # do some stuff

我对为什么这在 C++ 中有效不感兴趣,我已经忘记了如何在 C++ 中编写宏和工厂。我想知道,我是否应该坚持我的手艺,为了可维护性而保留工厂,然后学习编写更复杂的装饰器。或者我是否缺少像这样的紧密耦合的更 Pythonic 解决方案?

你真的应该停止用 C++ 术语思考。你几乎不需要写一个工厂,通常,一个简单的映射就可以了。编写您的装饰器 up-front,将字符串版本作为参数,但在内部使用映射。

def next_process(next_):
    def deco(func):
        def wrapper(self, *args, **kwargs):
            func(self, *args, **kwargs)
            return MAP[next_](self)
        return wrapper
    return deco

class Process:
    def __init__(self, prev_process):
        self.prev_process = prev_process

class A(Process):
    @next_process('B')
    def do_process(self):
        # dosomestuff
        return B(self)

class B(Process):
    @next_process('C')
    def do_process(self):
        # dosomestuff
        return C(self)

class C(Process):
    @next_process('A')
    def do_process(self):
        # dosomestuff
        return A(self)

MAP = {'A': A, 'B':B, 'C':C}

请注意,如果您继续创建一些 factory class,同样的原则也适用。只需在内部使用该工厂即可。或者不要让它急切求值。