这个简单的Python元类有什么问题?

6

闲话开头

我刚学了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

我做错了什么?

5个回答

4

我并不完全了解您正在执行的全局方法,例如设置__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

3

我已经让你的例子可以运行:

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”。 - John La Rooy
不应该从object继承的是元类还是模块中的所有类? - ritratt

2

参见此答案:Python元类和对象基类

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

此外,您的元类有缺陷,即使您使其应用(通过在类内设置__metaclass__),它也无法工作。它应该只接受三个参数。通常会看到接受四个参数的示例,但那是因为元类通常是一个,因此它接受额外的“self”参数(按惯例称为元类的cls)。


1
可能这就是你想要的。从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
@ritratt,“metest”是一个返回从“type”继承的类的函数。全局变量“metaclass=metest”仅适用于经典类。一旦您从“object”继承,就会将元类设置回“type”,除非该类再次覆盖元类。 - John La Rooy

1
你的模块级元类被覆盖了,就像BrenBarn上面所说的那样。 为了解决这个问题,请尝试将其编码为return cls而不是将其设置为类实例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接