如何在我的类中应用元类而不在类声明中对其进行硬编码

时间:2015-02-06 22:19:31

标签: python-3.x

对于考试,教授要求我写一个对项目中所有课程生效的元类,而不直接在课堂声明中声明,这可能吗?怎么样? 例如,我有以下代码:

class MetaOne(type): 
    def __new__(meta, classname, supers, classdict):
        print('In MetaOne.new: ', classname, supers, classdict, sep='\n...') 
        return type.__new__(meta, classname, supers, classdict) 
    def __init__(Class, classname, supers, classdict): 
        print('In MetaOne init:', classname, supers, classdict, sep='\n...') 
        print('...init class object:', list(Class.__dict__.keys()))

class Eggs: pass 

print('making class') 

class Spam(Eggs): 
    data = 1 
    def meth(self, arg): pass 

print('making instance') 
X = Spam() 
print('data:', X.data)

我希望输出等于以下代码的输出:

class MetaOne(type): 
    def __new__(meta, classname, supers, classdict):
        print('In MetaOne.new: ', classname, supers, classdict, sep='\n...') 
        return type.__new__(meta, classname, supers, classdict) 
    def __init__(Class, classname, supers, classdict): 
        print('In MetaOne init:', classname, supers, classdict, sep='\n...') 
        print('...init class object:', list(Class.__dict__.keys()))

class Eggs: pass 

print('making class') 

class Spam(Eggs, metaclass=MetaOne): 
    data = 1 
    def meth(self, arg): pass 

print('making instance') 
X = Spam() 
print('data:', X.data)

即使我没有直接申报,该元类也适用于我所有的课程。 我有很多关于元类的问题,但最后在他们的类的定义中总是使用metaclass = meta声明。

2 个答案:

答案 0 :(得分:2)

您可以在模块级别编写__metaclass__ = your_metaclass 。下面定义的所有类都将使用元类。如果在类定义中再次编写__metaclass__ = type,则可以覆盖此项。子类正在使用父类的元类。

答案 1 :(得分:0)

嗯,我很难理解你的问题。

如果Eggs继承MetaOneSpam继承Eggs,这是否会实现您的目标?

示例#1:

class MetaOne(metaclass=ABCMeta):
    pass

class Eggs(MetaOne):
    pass

class Spam(Eggs):
    pass

示例#2:

也许lgiordani.com提供的信息对您有用,尤其是前面链接中的以下代码块:

class FilterClass(type):
    @classmethod
    def __prepare__(name, bases, **kwds):
        return collections.OrderedDict()

    def __new__(metacls, name, bases, namespace, **kwds):
        result = type.__new__(metacls, name, bases, dict(namespace))
        result._filters = [
            value for value in namespace.values() if hasattr(value, '_filter')]
        return result

此代码块演示了如何在不使用metaclass=ABCMeta的情况下创建元类。

示例#3:

您熟悉super()吗?

class MetaOne:
    def __init__(self, name):
        self.name = name

class Eggs: pass

class Spam(MetaOne, Eggs):
    def __init__(self, name, is_tasty):
        super().__init__(name)
        self.is_tasty = is_tasty

>>> s = Spam('meta', True)
>>> s
<__main__.Spam object at 0x100705b38>
>>> s.name
'meta'
>>> s.is_tasty
True

虽然使用super()并不是真正的元类

示例#4:

根据您的Python版本,您可以在模块级别定义__metaclass__ = MetaOne,这将影响该声明下面的所有类。

class MetaOne: pass

class Eggs: pass

__metaclass__ = MetaOne

class Spam: pass
class Scrambled: pass
class Fried: pass

在此用例中,SpamScrambledFried的元类都将为MetaOne