【问题标题】:how to get derived class name from base class如何从基类中获取派生类名
【发布时间】:2012-07-09 14:59:23
【问题描述】:

我有一个基类Person 和派生类ManagerEmployee。现在,我想知道创建的对象是ManagerEmployee

此人如下:

from Project.CMFCore.utils import getToolByName
schema = getattr(Person, 'schema', Schema(())).copy() + Schema((TextField('FirstName', required = True, widget = StringWidget(label='First Name', i18n_domain='project')), TextField('Last Name', required = True, widget = StringWidget(label='Last Name', i18n_domain='i5', label_msgid='label_pub_city'))
class Manager(BaseContent):
  def get_name(self):
    catalog = getToolByName(self, "portal_catalog")
      people = catalog(portal_type='Person')
      person={}
      for object in people:
        fname = object.firstName
        lname = object.lastName
        person['name'] = fname+' '+ lname
        # if the derived class is Employee then i would like go to the method title of employee and if its a Manager then go to the title method of Manager
        person['post'] = Employee/Manager.title()
      return person

对于经理和员工来说,他们是一样的(员工也是相似的,但有些不同的方法)

from Project.Person import Person
class Manager(Person):
    def title(self):
      return "Manager"

对于员工,标题是“员工”。当我创建Person 时,它要么是Manager,要么是Employee。当我得到 person 对象时,类是 Person,但我想知道它是来自派生类“Manager”还是“Employee”。

【问题讨论】:

  • 你能提供一些代码来展示你想要做什么吗?

标签: python plone derived-class base-class


【解决方案1】:

Python 类具有 __subclasses__ 魔术方法,可用于查看当前哪些范围内的类是从给定的父类派生的。

# related.py

class Parent: ...

class Child(Parent): ...
>>> from related import Parent
>>> Parent.__subclasses__()
[<class 'related.Child'>]

在访问 Parent 类时,这些类是对任何范围内派生类的弱引用。

# not_related.py

class StepChild(Parent): ...
>>> from related import Parent
>>> Parent.__subclasses__()
[<class '__main__.Child'>]
>>> from not_related import StepChild
>>> Parent.__subclasses__()
[<class 'related.Child'>, <class 'not_related.StepChild'>]

【讨论】:

    【解决方案2】:

    您可以使用x.__class__.__name__ 以字符串形式检索类名,例如

    class Person:
        pass
    
    class Manager(Person):
        pass
    
    class Employee(Person):
        pass
    
    def get_class_name(instance):
        return instance.__class__.__name__
    
    >>> m = Manager()
    >>> print get_class_name(m)
    Manager
    >>> print get_class_name(Employee())
    Employee
    

    或者,您可以使用 isinstance 来检查不同的类型:

    >>> print isinstance(m, Person)
    True
    >>> print isinstance(m, Manager)
    True
    >>> print isinstance(m, Employee)
    False
    

    所以你可以这样做:

    def handle_person(person):
        if isinstance(person, Manager):
            person.read_paper()     # method of Manager class only
        elif isinstance(person, Employee):
            person.work_hard()      # method of Employee class only
        elif isinstance(person, Person):
            person.blah()           # method of the base class
        else:
            print "Not a person"
    

    【讨论】:

      【解决方案3】:

      在您的示例中,您不需要知道类,您只需通过引用类实例来调用方法:

      # if the derived class is Employee then i would like go to the method title 
      # of employee and if its a Manager then go to the title method of Manager
      person['post'] = object.title()
      

      但是不要使用object作为变量名,你隐藏了内置名称。

      【讨论】:

        【解决方案4】:

        你会寻找这样的东西吗?

        >>> class Employee:
        ...     pass
        ... 
        >>> class Manager(Employee):
        ...     pass
        ... 
        >>> e = Employee()
        >>> m = Manager()
        >>> print e.__class__.__name__
        Employee
        >>> print m.__class__.__name__
        Manager
        >>> e.__class__.__name__ == 'Manager'
        False
        >>> e.__class__.__name__ == 'Employee'
        True
        

        【讨论】:

          【解决方案5】:

          “这样做”的最佳方法是不这样做。相反,在 Person 上创建方法,在 Manager 或 Employee 上被覆盖,或者为子类提供自己的扩展基类的方法。

          class Person(object):
              def doYourStuff(self):
                  print "I'm just a person, I don't have anything to do"
          
          class Manager(object):
              def doYourStuff(self):
                  print "I hereby manage you"
          
          class Employee(object):
              def doYourStuff(self):
                  print "I work long hours"
          

          如果您发现自己需要在基类中知道正在实例化哪个子类,则您的程序可能存在设计错误。如果其他人后来扩展 Person 以添加一个名为 Contractor 的新子类,你会怎么做?当子类不是它所知道的任何硬编码替代品时,Person 会做什么?

          【讨论】:

          • 怀疑这是“最佳方式”,或者 OP 的设计有问题。实现起来更简单,如this answer 所示,其中基类有一个所有子类都可以使用的方法(无论他们选择什么目的)。
          【解决方案6】:

          我不知道这是否是您想要的,以及您希望它实现的方式,但这是一个尝试:

          >>> class Person(object):
              def _type(self):
                  return self.__class__.__name__
          
          
          >>> p = Person()
          >>> p._type()
          'Person'
          >>> class Manager(Person):
              pass
          
          >>> m = Manager()
          >>> m._type()
          'Manager'
          >>> 
          

          优点:_type 方法只有一个定义。

          【讨论】:

          • 简洁。很好地使用交互式输出。
          • 非常感谢.. 这就是我要找的东西!
          • 如果我创建了 3 种类型的用户类,我想知道从 request.user 获得的对象的类。 request.user 返回一个 User 类的对象。
          • 对不起@Chandan,但我不明白你的问题。你能说得更准确点吗?
          • @ShlomoGottlieb:这完全改变了解决方案,因为这个解决方案是基于 self 的对象实例...我猜你必须在每个派生类中定义一个静态方法,这不是可扩展的。但是您可以类似地使用@classmethod: def type2(cls): return cls.__name_
          【解决方案7】:

          Python 对象提供了一个__class__ 属性,该属性存储用于创建该对象的类型。这反过来提供了一个__name__ 属性,可用于将类型的名称作为字符串获取。所以,在简单的情况下:

          class A(object):
              pass
          class B(A):
              pass
          
          b = B()
          print b.__class__.__name__
          

          愿意:

          'B'

          所以,如果我正确地回答了你的问题,你会这样做:

          m = Manager()
          print m.__class__.__name__
          'Manager'
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-10-15
            • 1970-01-01
            • 2015-03-30
            • 1970-01-01
            • 1970-01-01
            • 2017-11-05
            • 2010-11-01
            相关资源
            最近更新 更多