Python的object类(特殊属性、方法)以及新式类和经典类

在 Python 3 中,object 类是 Python 为所有类所提供的父类(基类),因此所有的类都直接或者间接的继承了 object 类的属性和方法。

我们可以使用内置函数 dir() 去查看指定对象的所有属性和方法。

>>> class A:
...     pass
...
>>> a = A()
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__
hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '_
_repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

>>> obj = object()
>>> dir(obj)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__
init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '
__sizeof__', '__str__', '__subclasshook__']
>>>
图片[1]-Python的object类(特殊属性、方法)以及新式类和经典类-尤尤'blog

在 Python 3 中,如果一个类没有写父类,则默认继承自 object 类。

特殊属性

__dict__获得类对象或实例对象绑定的所有属性和方法的字典。
__class__输出对象所属的类
__bases__输出类的父类类型的元组
__base__输出与类离得最近的基类
__mro__输出类的层次结构
__subclasses__输出子类列表
特殊属性
class A:
    pass

class B:
    pass

class C(A, B):
    def __init__(self, name, age):
        self.name = name
        self.age = age

c = C('Tom', 10)

# 获得类对象或实例对象绑定的所有属性和方法的字典。
print(c.__dict__)  # {'name': 'Tom', 'age': 10}
print(C.__dict__)  # {'__module__': '__main__', '__init__': <function C.__init__ at 0x00000227583FF130>, '__doc__': None}

# 输出对象所属的类
print(c.__class__)  # <class '__main__.C'>

# 输出父类类型的元组
print(C.__bases__)  # (<class '__main__.A'>, <class '__main__.B'>)

# 输出和类离得最近的基类
print(C.__base__)  # <class '__main__.A'>

# 查看类的层次结构:“类名.__mro__” 可以打印出当前类所继承的父类以及继承的层级关系。可以让我们快速得到类的继承关系。
print(C.__mro__)  # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

# 输出子类列表
print(A.__subclasses__())  # [<class '__main__.C'>]
图片[2]-Python的object类(特殊属性、方法)以及新式类和经典类-尤尤'blog

特殊方法

__len__()重写__len__()方法,让内置函数len()的参数可以是自定义类型。
__add__()重写__add__()方法,使得自定义对象具有“+”的功能。
__init__()创建对象时自动调用。
__new__()初始化方法。

1、__add__(self,other)

当我们将两个整数相加时,Python 解释器会在底层调用 __add__ 方法来完成相加操作。但是两个自定义对象不能进行相加操作。我们可以通过重写 __add__ 方法,使自定义对象具有 ‘+’ 功能

a = 10
b = 100
print(a+b)
print(a.__add__(b))

class Student:
    def __init__(self,name):
        self.name = name
    def __add__(self, other):
        return self.name + other.name

stu1 = Student('汤姆')
stu2 = Student('杰克')
# 两个对象不能直接相加,如果要相加,需要重写__add__特殊方法
# s = stu1 + stu2 # TypeError: unsupported operand type(s) for +: 'Student' and 'Student'
s = stu1 + stu2
print(s)    # 汤姆杰克

2、__len__()

通过重写 __len__() 方法,是内置函数 len() 的参数可以是自定义类型。

class Student:
    def __init__(self, name):
        self.name = name

    def __len__(self):
        return len(self.name)


stu1 = Student('汤姆')

lst = [10, 20, 30, 40]
print(len(lst))  # 内置函数len()

# 重写__len__()方法,才能将自定义对象当做参数传给len()内置函数
# print(len(stu1))  # TypeError: object of type 'Student' has no len()
print(len(stu1)) # 2

3、__new__()和__init__()

__new__用来创建对象,它是由object类提供的内置静态方法,所以在调用的时候要主动给 cls 传递参数。__init__()为实例属性初始化。

当使用 类名() 创建对象时,Python解释器会先自动调用__new__()方法为对象分配内存空间,然后返回对象的引用。Python解释器获得对象的引用后,将这个引用作为第一个参数传给__init__()方法。

注意:重写__new__方法一定要retun super().__new__(cls),否则Python解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法__init__。

重写__new__方法是为了对分配空间的方法进行改造,使得我们在使用类名()创建对象的时候,无论执行多少次,在内存中只会创建出一个实例对象,以达到单例设计模式(类创建的对象,在系统中只有唯一一个实例,也就是每次执行类名(),返回的对象地址都相同。例如音乐播放器,每次只能播放一首歌)

class Person(object):
    def __new__(cls, *args, **kwargs):      # 创建对象
        print('__new__被调用执行了,cls的id值为{0}'.format(id(cls)))
        obj = super().__new__(cls)      # Person传给了object类,在object中创建一个对象obj
        print('创建的对象的id值为{0}'.format(id(obj)))
        return obj   # 返回给self
    def __init__(self,name,age):            # 为创建的对象赋值
        print('__init__被调用了,self 的id值为{0}'.format(id(self)))
        self.name = name
        self.age = age

print('object这个类对象的id为{0}'.format(id(object)))
print('Person这个类对象的id为{0}'.format(id(Person)))

print('-------------------------------------------------------------')
p1 = Person('张三',20)   # 先执行赋值号右侧的代码,自动调用__new__,把Person传给了cls   __init__初始化方法执行完成后,再把self赋值给p1
print('-------------------------------------------------------------')
print('p1这个Person的实例对象的id为{0}'.format(id(p1)))
图片[3]-Python的object类(特殊属性、方法)以及新式类和经典类-尤尤'blog

4、__str__()

object 类有一个方法 __str__(),用于返回一个对于对象的描述,在 ‘Python 类方法、静态方法和初始化方法’ 中有详细讲解。

我们使用 print 打印对象时,输出的是对象的内存地址。但我们可以通过重写 __str__() 方法来自定义这个输出内容,注意,__str__() 必须返回一个字符串。

class Student:  # 默认继承自object
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):  # 重写__str__方法
        return f'我叫{self.name},今年{self.age}岁。'

stu = Student('张三',21)
print(dir(stu))
# print(stu)  # <__main__.Student object at 0x0000016DF4CB7430>
# 如果在类中重写了__str__方法,使用print打印对象输出的就是自定义的内容了
print(stu)  # 自动调用__str__方法
图片[4]-Python的object类(特殊属性、方法)以及新式类和经典类-尤尤'blog

新式类和旧式类(经典类)

新式类:以 object 为基类(父类)的类。

经典类:不以 object 为基类的类。

在 Python 2.x 中,如果没有指定父类,也不会把 object 作为基类。

而在 Python 3.x 中,如果未指定父类,则默认将 object 作为该类的基类,所以 Python 3.x 中定义的都是新式类。

注意:推荐使用新式类,在定义类的时候,如果没有父类,则让它继承自 object 基类。

class 类名(object):
    pass

新式类和经典类在多继承中,会影响 MRO(方法搜索顺序)。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容