python 如何根据父类的属性判断父类的示例是否为子类的示例

yv5phkfx  于 2023-08-02  发布在  Python
关注(0)|答案(2)|浏览(155)

“Man”是“Person”的子类,具有属性gender='male '。如何判断Person的instance是否是Man的instance?假设Bob=Person(name='bob ',gender='male'),我如何获得isinstance(Bob,Man)=True?

class Person:
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def __repr__(self):
        return f"Person(name={self.name}, gender={self.gender})"

    @classmethod
    def create_person(cls, name, gender):
        if gender == 'male':
            return Man(name, gender)
        elif gender == 'female':
            return Woman(name, gender)
        else:
            raise ValueError("Invalid gender")

class Man(Person):
    def __init__(self, name, gender):
        super().__init__(name, gender)

class Woman(Person):
    def __init__(self, name, gender):
        super().__init__(name, gender)

bob = Person("bob", "male")
print(isinstance(bob, Man))

字符串
我得到的结果是“假”,但不是“真”,我应该如何纠正它?

r6l8ljro

r6l8ljro1#

Person是你的超类。男人和女人是人的子类。
因此,你应该构建男人或女人-而不是人
也许这会让事情变得更清楚:

class Person:
    def __init__(self, name: str):
        self._name = name
    def __str__(self) -> str:
        return f'My name is {self._name} and I am a {type(self).__name__}'

class Man(Person):
    def __init__(self, name: str):
        super().__init__(name)

class Woman(Person):
    def __init__(self, name: str):
        super().__init__(name)

man = Man('Dave')
woman = Woman('Linda')

print(man)
print(woman)

字符串

输出:

My name is Dave and I am a Man
My name is Linda and I am a Woman


当然,你可能想要一个替代使用类名的方法,所以通过使用class属性,我们可以做到这一点:

class Person:
    def __init__(self, name: str):
        self._name = name
    def __str__(self) -> str:
        gender = getattr(self, '_gender', 'Unknown')
        return f'My name is {self._name} and I am a {gender}'

class Man(Person):
    _gender = 'man'
    def __init__(self, name: str):
        super().__init__(name)

class Woman(Person):
    _gender = 'woman'
    def __init__(self, name: str):
        super().__init__(name)

man = Man('Dave')
woman = Woman('Linda')

print(man)
print(woman)

输出:

My name is Dave and I am a man
My name is Linda and I am a woman

qq24tv8q

qq24tv8q2#

这在技术上是可行的,而且在某些情况下非常有用。话虽如此,正如在其他几个答案中所述,这是一种反模式,并将打破Python中被认为是“标准”的一堆东西,因此如果可以的话,您可能更喜欢Factory Design Pattern
因此,请负责任地享受以下内容。
最简单的方法是使用__init_subclass__方法,在创建子类时将子类注册到超类中(如this answer所示),然后在__init__期间动态更改示例类。
动态更改类对于不熟悉您的代码的人来说确实很混乱,而且看起来像是变魔术,所以您需要适当地记录它。这也意味着你在任何子类'__init__'中所能做的都是非常有限的。您需要创建一个__post_init__,它可以通过子类进行专门化(类似于dataclasses.dataclass结构)。

class Person:

    gender = 'unknown'  # this is a class variable
    '''the default gender for this class'''
    _REGISTERED_GENDERS = {}
    '''
    a dictionary of all genders known to `Person`,
    and the respective `Person` subclasses which 
    should be instantiated from these genders
    '''

    def __init__(self, name: str, gender: str = None):
        '''
        initialize a person. if no gender is given,
        this method will default to the class' gender.

        NOTE:
        `__init__` should not be subclassed. Instead, for
        subclass specific setup, you should subclass the
        `__post_init__` method
        '''

        self.name = name  # this is an instance variable
        '''the name of this instance of `Person`'''

        # gender is an instance variable. We instantiate it from
        # the `gender` argument, if it is provided, or from the
        # class' default `gender` variable if it is not
        self.gender = gender or self.__class__.gender
        '''the gender of this instance of `Person`'''

        # dynamically change this object's class based on gender
        self.__class__ = __class__._REGISTERED_GENDERS.get(
            self.gender, __class__)

        # Do subclass-specific setup stuff.
        # this will now call the `__post_init__` method
        # of the relevant subclass.
        self.__post_init__()

    def __post_init__(self):
        '''do sub-class specific setup stuff here'''
        print(f"A person was born today. Their name is {self.name}.")

    def __init_subclass__(cls, gender=None):
        '''register a new subclass of a given gender'''

        # set the subclass' default `gender`
        if gender is not None:
            cls.gender = gender

        # register the subclass to this super-class
        __class__._REGISTERED_GENDERS[cls.gender] = cls

    def __repr__(self):
        return f"{self.__class__.__name__}(name={self.name}, gender={self.gender})"

class Man(Person, gender='man'):
    def __post_init__(self):
        '''do sub-class specific setup stuff here'''
        print(f"A man was born today. His name is {self.name}.")

class Woman(Person, gender='woman'):
    def __post_init__(self):
        '''do sub-class specific setup stuff here'''
        print(f"A woman was born today. Her name is {self.name}.")

字符串
如果我们以“通常”的方式做事,我们会得到预期的结果:

dave = Man('Dave')
print(dave)


今天有个人出生了。他叫戴夫。
男性(姓名=Dave,性别=man)
如果我们以“新的”/“非常规的”/“错误的”方式做事,我们也会得到想要的结果:

tom = Person('Tom', 'man')
print(tom)


今天有个人出生了。他叫汤姆。
男(姓名=Tom,性别=man)
作为一个额外的好处,我们可以示例化一个没有性别的人,他们将拥有默认的Person类。

robot = Person("Isaac")
print(robot)


今天有一个人出生了。他们的名字是艾萨克。
人员(姓名=Isaac,性别=未知)

相关问题