从超类获取子类的名称?

8

我有一个基类bc,还有许多基于bc的子类。

class bc(Object):
  def get_subclass_name(self):
      # Retrieve the name of the most derived subclass of this instance
      pass
  def somemethod(self):
      x = self.get_subclass_name()

class sc1(bc):
    pass

class sc2(bc)
    pass

这个想法是,当在bc的一个子类实例上调用somemethod()时,它将能够使用该实例最终派生子类的名称,而不需要提前知道可能存在哪些子类。

我为此编写了一个测试用例:

class base_class(object):
    @classmethod
    def get_subclass_name(cls):
        return cls.__name__

    def somemethod(self):
        print(base_class.get_subclass_name())

class sub_class(base_class):
    pass

sub_class().somemethod()

当运行此代码时,它会产生`base_class`而不是`sub_class`。

5
“the most derived subclass” 意思是“最终派生子类”。 - falsetru
如果有另一个class sc3(sc2),那么对于sc2的实例来说,“最派生的子类”是sc3还是仍然是sc2 - tobias_k
@livsky 我看了一下元类,但是没看出它们在这种特定情况下会有什么帮助。 - Jonathan
3
请提供一个测试案例,以展示你所想要实现的内容。 - iperelivskiy
1
注意这一行代码!使用self调用它,就可以正常工作了。你正在显式地传递基类,而不是当前类。print(base_class.get_subclass_name()) - tobias_k
显示剩余4条评论
2个回答

14

就像是对@poorsod的解决方案的另一个替代品,对我来说完全可以正常工作,这里是另一种可能更简单的变体,不使用类方法,而是使用self.__class__。就像self总是指向当前实例一样,self.__class__总是指向该实例的实际类。

class bc(object):
    def get_subclass_name(self):
        return self.__class__.__name__

示例,测试于Python 2.6.6:

>>> class sc1(bc): pass
>>> class sc2(sc1): pass
>>> class sc3(sc2): pass
>>> print sc2().get_subclass_name()
sc2
如果这不起作用,请更具体地说明您期望的输出和实际获得的输出。

1
我在这个实例中寻找sc3。 - Jonathan
请解释为什么。当创建sc2()的实例时,sc2是实例的实际类。而sc3只是为了避免“最派生类”的歧义。 - tobias_k
非常感谢。你的提案完美地运作了,但是使用@poorsod的classmethod的提案却没有产生我预期中的相同结果。 - Jonathan
@Jonathan,使用classmethod的答案也可以。根据您的编辑,您只是使用方法不正确。请参见我在您问题上面的评论。 - tobias_k
1
在这种方法中,您需要先创建一个实例,有没有办法获得子类名称(问题中的确切要求),但不创建实例?@tobias_k - Anubis
显示剩余2条评论

8

你需要一个class方法

class bc(Object):
    @classmethod
    def get_subclass_name(cls):
        return cls.__name__

    def somemethod(self):
        x = self.get_subclass_name()

普通方法在被调用时,第一个参数会传递实例本身。这就是为什么你在 Python 中到处都看到 self 的原因。
然而,当你调用类方法时,会将 实例所属的具体类 作为参数传递给函数。我们通常使用名称 cls,就像我在这里所做的一样。
类方法的经典用例是替代构造函数。例如,标准库的 dict 类提供了一个 fromkeys 类方法,它使用提供的键和单个值构造一个新的字典。你可以手动构造这样一个字典,但 Python 开发人员为你简化了生活!

如果sc是从bc派生的,你会得到bc作为名称,而不是我想要的sc。我已经尝试过了。 - Jonathan
1
为什么不直接使用 self.__class__ - tobias_k
@Jonathan 我是否误解了您的要求?如果您在 sc 的实例上调用 get_subclass_name,它将返回 'sc' - Benjamin Hodgson
@tobias_k 是的,这大致相当于使用 self.__class__,但它更符合 Pythonic 风格(既不啰嗦又更明确)。 - Benjamin Hodgson

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