我在Python中实现了一个特殊的statemachine,它使用类方法作为状态表示。
class EntityBlock(Block):
def __init__(self, name):
self._name = name
@classmethod
def stateKeyword1(cls, parserState : ParserState):
pass
@classmethod
def stateWhitespace1(cls, parserState : ParserState):
token = parserState.Token
if isinstance(token, StringToken):
if (token <= "generate"):
parserState.NewToken = GenerateKeyword(token)
parserState.NewBlock = cls(....)
else:
raise TokenParserException("....", token)
raise TokenParserException("....", token)
@classmethod
def stateDelimiter(cls, parserState : ParserState):
pass
访问GitHub,获取完整源代码pyVHDLParser。
当我调试我的解析器FSM时,我将状态名打印为:
State: <bound method Package.stateParse of <class 'pyVHDLParser.DocumentModel.Sequential.Package.Package'>>
我想获得更好的报告,所以我想覆盖每个绑定方法对象的__repr__
的默认行为。
是的,我可以写一个元类或应用第二个装饰,但我在质疑自己:
是否可以从classmethod
派生并且只有一个装饰器被调用,例如state
吗
根据PyCharm的builtins.py(Python内置函数的一组虚拟代码),classmethod是一个基于类的装饰器。
答案 0 :(得分:1)
是的,如果需要,您可以编写自己的类classmethod
。虽然这有点复杂。您需要实现描述符协议(覆盖classmethod
的{{1}}的实现),以便它返回另一个自定义类的实例,其行为类似于绑定方法对象。不幸的是,你不能继承Python的内置绑定方法类型(我不知道为什么不这样做)。
然后,最好的方法可能是将一个普通方法对象包装在自定义类的实例中。我不确定你需要复制多少方法API,所以这可能会有点复杂。 (你需要你的州可以相互比较吗?他们需要是可以洗的吗?可选吗?)
无论如何,这是一个简单的实现,它实现了获得工作方法所需的最小量(加上新的__get__
):
repr
快速演示它的实际效果:
class MethodWrapper:
def __init__(self, name, method):
self.name = name if name is not None else repr(method)
self.method = method
def __call__(self, *args, **kwargs):
return self.method(*args, **kwargs)
def __repr__(self):
return self.name
class State(classmethod):
def __init__(self, func):
self.name = None
super().__init__(func)
def __set_name__(self, owner, name):
self.name = "{}.{}".format(owner.__name__, name)
def __get__(self, owner, instance):
method = super().__get__(owner, instance)
return MethodWrapper(self.name, method)
请注意,>>> class Foo:
@State
def foo(cls):
print(cls)
>>> Foo.foo
Foo.foo
>>> Foo.foo()
<class '__main__.Foo'>
>>> f = Foo()
>>> f.foo()
<class '__main__.Foo'>
描述符使用的__set_name__
方法仅由Python 3.6调用。如果没有这个新功能,描述符将更难以学习它自己的名称(您可能需要创建一个以名称作为参数的装饰器工厂)。