Python - 在类声明中访问父类装饰器
Posted
技术标签:
【中文标题】Python - 在类声明中访问父类装饰器【英文标题】:Python - Accessing parent class decorators inside class declaration 【发布时间】:2019-08-07 00:05:35 【问题描述】:假设我有这个课程:
class Foo:
@classmethod
def some_decorator(cls, ...):
...
然后我创建一个使用父类装饰器的子类:
class Bar(Foo):
@Foo.some_decorator(...)
def some_function(...)
...
如何去掉装饰器名称前的Foo.
?以下代码不起作用:
class Bar(Foo):
@some_decorator(...)
def some_function(...)
...
我相信这是可能的,因为 sly
库可以做到这一点。
看看他们的例子:
from sly import Lexer, Parser
class CalcLexer(Lexer):
...
@_(r'\d+')
def NUMBER(self, t):
t.value = int(t.value)
return t
...
如您所见,您可以输入@_(...)
而不是@Lexer._(...)
。
他们是如何做到这一点的?
【问题讨论】:
旁白:我不太喜欢这种设计选择。在类中神奇地产生一个装饰器会产生不明显、难以理解的代码。一个更清洁的解决方案是让用户使用from sly import _
导入_
装饰器。三思而后行,是否要在代码库中包含它。
@Aran-Fey 在我看来,这也不是很好:你污染了全局命名空间,_
不能对每个类都意味着不同的东西。对于 sly,_
对于每个基类都有不同的含义。
我对这个项目一无所知,但词法分析器和解析器是为速度而不是可读性而构建的。这就是为什么 Lex 和 YACC 对某些人来说如此困难的原因。
【参考方案1】:
这是通过实现__prepare__
方法的metaclass 完成的。文档摘录:
3.3.3.4。准备类命名空间
一旦确定了合适的元类,那么该类 命名空间已准备好。如果元类具有
__prepare__
属性, 它被称为namespace = metaclass.__prepare__(name, bases, **kwds)
(其中额外的关键字参数,如果有的话,来自类 定义)。
简单来说:你让你的__prepare__
方法返回一个包含装饰器条目的字典。概念证明:
class MyMeta(type):
def __prepare__(name, bases):
return 'x': 'foobar'
class MyClass(metaclass=MyMeta):
print(x) # output: foobar
【讨论】:
谢谢。有没有办法像我的问题一样让装饰器成为@classmethod
?我需要在装饰器中访问cls
。
@DavidCallanan 好吧,当然可以将@classmethod
添加到装饰器中,但这不会让它访问类——它只会让它与TypeError: 'classmethod' object is not callable
一起崩溃。这在评论中有点难以回答,所以我可以请您发布一个关于它的新问题吗?
***.com/questions/55207813/…【参考方案2】:
我查看了您所说的库内部,Lexer
类继承了一个元类:
class Lexer(metaclass=LexerMeta):
在LexerMeta
中,您可以找到以下内容:
@classmethod
def __prepare__(meta, name, bases):
d = LexerMetaDict()
def _(pattern, *extra):
patterns = [pattern, *extra]
def decorate(func):
pattern = '|'.join(f'(pat)' for pat in patterns )
if hasattr(func, 'pattern'):
func.pattern = pattern + '|' + func.pattern
else:
func.pattern = pattern
return func
return decorate
d['_'] = _
d['before'] = _Before
return d
元类用于创建类对象,然后用于实例化对象。从我在该方法中可以看到,这里d['_'] = _
元类将_
方法动态附加到您要使用的类。
这意味着他们所做的与:
class Bar:
@staticmethod
def some_decorator(f):
...
@some_decorator
def some_function(self):
...
【讨论】:
以上是关于Python - 在类声明中访问父类装饰器的主要内容,如果未能解决你的问题,请参考以下文章