Py学习  »  Python

python-访问类声明内的父类修饰符

David Callanan • 6 年前 • 1822 次点击  

假设我有这门课:

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._(...) .

他们是如何做到这一点的?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/38284
 
1822 次点击  
文章 [ 2 ]  |  最新文章 6 年前
Alexandru Martin
Reply   •   1 楼
Alexandru Martin    6 年前

我查了你所说的图书馆 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):
        ...
Aran-Fey
Reply   •   2 楼
Aran-Fey    6 年前

这是用一个 metaclass 实现了一个 __prepare__ 方法。文件摘录:

3.3.3.4.正在准备类命名空间

一旦确定了适当的元类,那么 命名空间已准备好。如果元类具有 _准备__ 属性, 它被称为 namespace = metaclass.__prepare__(name, bases, **kwds) (如果其他关键字参数(如果有)来自类 定义)。

简单地说:你把 _准备__ 方法返回包含decorator项的字典。概念证明:

class MyMeta(type):
    def __prepare__(name, bases):
        return {'x': 'foobar'}

class MyClass(metaclass=MyMeta):
    print(x)  # output: foobar