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,同样的原则也适用。只需在内部使用该工厂即可。或者不要让它急切求值。
我在系统中有一些对象需要知道他们的下一个对象是谁。每个都有一个 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,同样的原则也适用。只需在内部使用该工厂即可。或者不要让它急切求值。