【问题标题】:What is wrong with this simple python metaclass?这个简单的 python 元类有什么问题?
【发布时间】:2012-06-30 15:47:42
【问题描述】:

题外话开始

我刚刚了解了 Python 中的元类。我不认为 python 的创建者希望每个人都使用它们。我的意思是命名一些在大多数情况下可能不是类的元类足以让大多数人远离这个概念!

题外话

关于我的问题。我编写了这个简单的元类来为模块中创建的所有类添加一个默认的文档字符串。但它不起作用:

def metest(cls,name,bases,dict):
    cls.setattr(cls,'__doc__',"""Default Doc""")
    return type(cls,(),{})

__metaclass__=metest

class test(object):
    pass

print test.__doc__

t=test()

print t.__doc__

输出:

None
None

我做错了什么?

【问题讨论】:

    标签: python metaclass


    【解决方案1】:

    正如上面 BrenBarn 所述,您的模块级元类已被覆盖。 要解决此问题,请尝试将其编码为 return cls 而不是将其设置为类实例。

    【讨论】:

      【解决方案2】:

      我让你的例子起作用了:

      def metest(name, bases, dict):
          print name, bases, dict
          dict['__doc__'] = """New Doc"""
          cls = type(name+"_meta", bases, dict)
          return cls
      
      class Test(object):
          "Old doc"
          __metaclass__ = metest
      
      print Test
      print Test.__doc__
      
      t = Test()
      
      print t.__doc__
      
      1. 使用“元类”。
      2. 更正“类创建函数”的签名。 cls 将由我们创建。
      3. 有一个“旧”和一个“新”文档字符串以便区分。

      【讨论】:

      • 可以使用全局元类,只是不要继承自 object
      • 谁不应该从对象继承?元类或模块中的所有类?
      【解决方案3】:

      这可能就是你想要的。从object 继承将使元类type,因此如果您想使用全局元类,则不能这样做

      def metest(name, bases, dct):
          dct['__doc__'] = """Default Doc"""
          return type(name, bases, dct)
      
      __metaclass__=metest
      
      class test:
          pass
      
      print test.__doc__
      
      t=test()
      
      print t.__doc__
      

      【讨论】:

      • 但是元类不应该是一个类型吗?因为据我了解,Python 中的所有类都是type 类的对象。因此,如果我想更改所有类,那么我需要覆盖type,这就是metaclass 所做的。那么为什么我不应该从type 继承呢?是因为它继承自非覆盖的type 类吗?我很迷惑。 :S
      • @ritratt, metest 是一个函数,它返回一个继承自类型的类。全局 __metaclass__=metest 仅适用于经典类。从object 继承后,您将元类设置回type,除非该类随后再次覆盖元类
      【解决方案4】:

      看到这个答案:Python metaclass and the object base class

      提供object 基类会覆盖模块级元类并将其替换为typeobject 的元类)。

      此外,您的元类有问题,即使您应用它也无法工作(通过在类中设置__metaclass__)。它应该只接受三个参数。您通常会看到接受四个的示例,但那是因为元类通常是,你猜怎么着,一个,所以它接受一个额外的“self”参数(按照惯例,元类称为cls) .

      【讨论】:

        【解决方案5】:

        我并不完全熟悉你正在做的全局方法,像这样设置__metaclass__。据我所知,它是另一种有效的风格。

        但我会提供一个我熟悉的例子:

        class MeTest(type):
            def __new__(cls,name,bases,dict):
                dict['__doc__'] = """Default Doc"""
                return type.__new__(cls,name,bases,dict)
        
        class Test(object):
            __metaclass__ = MeTest
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-20
          • 2010-09-26
          • 1970-01-01
          相关资源
          最近更新 更多