在属性定义中获取类名

1 投票
3 回答
1194 浏览
提问于 2025-04-18 10:48

我需要创建一个混合类(mixin),这个混合类能够知道使用它的类的名字。就像这样:

class FooMixin(...):
    bar = self.__class__

不过在定义属性的时候,self 还没有被定义。有没有什么简单的方法可以做到这一点,让继承这个混合类的类使用起来感觉很自然呢?

3 个回答

1

首先,想要知道一个类的名字并不需要特别的操作:

class MyMixin(object):
    def frob(self):
        print "frobbing a", self.__class__.__name__

class Foo(MyMixin): pass
class Bar(MyMixin): pass
>>> Foo().frob()
frobbing a Foo
>>> Bar().frob() 
frobbing a Bar

同样,想要找到子类也不需要做什么特别的事情:

>>> MyMixin.__subclasses__()
[__main__.Foo, __main__.Bar]

如果这些都不是你想要的,因为你想在你的基类被子类化的时候采取一些行动,那你就需要一个 metaclass( metaclass 是元类)!

class MyMixinMeta(type):
    def __init__(cls, name, bases, attrs):
        if bases != (object,):
            print name, cls, "is a subclass of", bases

class MyMixin(object):
    __metaclass__ = MyMixinMeta
    def frob(self):
        print "frobbing a", self.__class__.__name__
>>> class Foo(MyMixin): pass
Foo <class '__main__.Foo'> is a subclass of (<class '__main__.MyMixin'>,)
>>> class Bar(MyMixin): pass
Bar <class '__main__.Bar'> is a subclass of (<class '__main__.MyMixin'>,)
1

Daniel的回答解释了为什么你想要的那种声明方式是行不通的——在定义Mixin的时候,没人知道它会在什么地方和什么时候被使用。

不过,如果你不在乎时间,只想要那种语法,也就是说你想要访问在Mixin中定义的属性bar,并返回self.class,那么这样做应该是可以的:

class classproperty(object):

    def __get__(self, instance, clazz):
        return clazz

class Mixin(object):

    bar = classproperty()


class Foo(Mixin):
    pass


print Foo().bar
3

在你定义这个混合类(mixin)的时候,没人知道这个混合类会被用在什么类里。你只能通过在类的方法里使用 self.__class__.__name__ 来动态获取类的名字:

class FooMixin(object):
    def some_method(self):
        print "I'm in class %s" % self.__class__.__name__

class Main(FooMixin):
    pass

instance = Main()
instance.some_method() # "I'm in class Main"

撰写回答