在该篇章中所说的 对象 都是 类所返回的对象

1. __str__

  • 一定要有返回值,且返回值一定要是字符串
  • 当打印一个对象 或者 使用 str() 内置函数且所传入的值是一个对象的时候 就会执行 __str__ 方法
  • 执行顺序: 首先在类中找看有没有 __str__ 方法,如果没有再找 __repr__ 方法执行,最后才在 object 中找 __str__ 且 object 中的 __str__ 方法返回的是对象的内存地址

class Tearch:
    def __str__(self):
        print('__str__函数被执行了')
        return '这是一个教师类'

t = Tearch()

str(t)  # __str__函数被执行了
print(t)  # 这是一个教师类
          # 如果类中没有 __str__ 方法打印出来的是 <__main__.Tearch object at 0x000001750C651C88>

2.__unicode__

  • 和 __str__ 的功能是一样的,只不过 __unicode__ 是在 Python2 中使用

class Tearch:
    def __unicode__(self):
        print('__unicode__函数被执行了')
        return '这是一个教师类'

t = Tearch()

str(t)  # __unicode__函数被执行了
print(t)  # 这是一个教师类
# 如果类中没有 __unicode__ 方法打印出来的是 <__main__.Tearch object at 0x000001750C651C88>

3.__repr__

  • 一定要有返回值,且返回值一定要是字符串
  • 当使用了 repr() 内置函数且所传入的值是一个对象的时候就会执行 __repr__
  • 当打印一个对象 或者 使用 str() 内置函数且所传入的值是一个对象的时候 如果类中没有 __str__ 方法就会执行 __repr__ 方法
  • 当使用了 repr() 内置函数且所传入的值是一个对象的时候,如果类中没有 __repr__ 方法,只有 __str__ 方法且不会执行 __str__ 方法

class Tearch:
    def __repr__(self):
        print('__repr__函数被执行了')
        return '这是一个教师类'

t = Tearch()

str(t)  # __repr__函数被执行了
repr(t) # __repr__函数被执行了
print(t)  # 这是一个教师类  -> 当打印一个对象的时候如果类中没有 __str__ 方法就会执行 __repr__ 方法
print(repr(t))  # 这是一个教师类 -> 当打印一个对象且执行了 repr() 内置函数的时候就会执行 __repr__

4. __len__

  • 当使用 len() 内置函数且所传入的值是一个对象的时候就会执行 __len__

# 使用场景: 如果有一个教室类,且当我想打印类所返回的对象长度的时候,我想知道该对象中有多少个学生

class Classes:
    def __init__(self):
        self.student = ['Kevin', 'Yeung', 'Amy']

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

c = Classes()
print(len(c))

5. __del__

  • 在删除一个对象之前执行 __del__ 方法

class File:
    def __init__(self):
        self.f = open('log.txt', encoding='utf-8')

    def __del__(self):
        print('__del__函数被执行')
        self.f.close()

f = File()

del f

print(f)  # 报错,对象已被删除

6. __call__ -> 常用(很多 Python 源码都会用到它)

  • 在对象后面加上 () 就会执行 __call__ 方法

class Dic:
    def __init__(self):
        self.name = 'Kevin'
        self.age = 18
        self.height = 175

    def __call__(self, data):

'''
        打印这个对象的所有属性
        :param data:
        :return:
        '''

        print(data)
        for k in self.__dict__:
            print(self.__dict__[k])

# 写法一
d = Dic()('接收外部传入的数据')

# 写法二
d1 = Dic()
d1('接收外部传入的数据')

7. item 系列 -> 以操作字典的方式去操作类中的属性

  • __getitem__ -> 以获取字典值得形式去获取类中的值

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getitem__(self, item):
        if hasattr(self, item):
# return self.__dict__[item]  # 写法一
            return getattr(self, item)  # 写法二

f = Foo('Kevin', 22)
print(f['name'])  # Kevin -> 当以调用字典的方式去调用类中的属性的时候就会执行 __getitem__

  • __setitem__ -> 以修改字典的方式去修改类中的属性

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age


    def __getitem__(self, item):
        if hasattr(self, item):
            return self.__dict__[item]


    def __setitem__(self, key, value):
 # self.__dict__[key] = value # 写法一
        setattr(self, key, value)  # 写法二


f = Foo('Kevin', 22)

f['name'] = 'Yeung'  # 当以修改字典的方式去修改类中的属性的时候就会执行 __setitem__

print(f['name'])  # Yeung

  • __delitem__ -> 以删除字典中的值的方式去删除类中的属性

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age


    def __delitem__(self, key):
        # del self.__dict__[key]  # 写法一
        delattr(self, key)  # 写法二

f = Foo('Kevin', 22)

del f['name'] # 当以删除字典中的值的方式去删除类中的属性的时候就会执行 __delitem__

print(f.__dict__)  # {'age': 22}

8. __new__  -> 常用

  • 构造函数
  • 作用: 创建 self 对象
  • 在执行__init__之前先会执行__new__

class Foo:
    def __new__(cls, *args, **kwargs):
        print('in __new__ fn')
        return object.__new__(cls)

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

f = Foo('Kevin')  # 打印了 in __new__ fn -> 在实例化的时候首先会进入 __new__ 方法创建 self 对象
print(f.name)

  • __new__ 一般用在设计模式

  • 单例模式
    • 一个类始终只有一个实例
    • 当你第一次实例化这个类的时候 就创建一个实例化的对象,当你之后再来实例化的时候 就用之前创建的对象

class Person:
    __instance = False

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        if cls.__instance:  # 如果创建过对象始终返回上一个创建的对象
            return cls.__instance
        cls.__instance = object.__new__(cls)  # 创建第一个对象
        return cls.__instance

k = Person('Kevin', 22)
y = Person('Yeung', 18)

print(k.name)  # Yeung
print(y.name)  # Yeung
print(k)  # <__main__.Person object at 0x0000028763FC1FD0>
print(y)  # <__main__.Person object at 0x0000028763FC1FD0>
print(k == y)  # True

  • __new__ 方法的返回值决定了实例化出来的对象是什么

    • 通俗理解: __new__ 返回了什么那么实例化出来的就是什么

class Foo:
    def __new__(cls, *args, **kwargs):
        return 123


obj = Foo()
print(obj)  # 123

class Bar:
    pass


class Foo:
    def __new__(cls, *args, **kwargs):
        return Bar()


obj = Foo()  # 实际上得到的是 Bar 类的实例化对象
print(obj)  # <__main__.Bar object at 0x000001A9FCFEFB00>

9. __getattr__

  • 当调用类中不存在的属性和方法的时候就会执行 __getattr__ 方法

class Foo:
    def __init__(self):
        self.name = 'Kevin'

    def __getattr__(self, item):
        print(item)  # age -> 属性名
        return '类中不存在该属性'


k = Foo()
print(k.name)  # Kevin
print(k.age)  # 类中不存在该属性

10. __setattr__

  • 不要轻易的使用该方法,使用不当会导致设置了该方法的类无法设置属性值,因为当设置了__setattr__方法,就代表已经覆盖了object的__setattr__方法了

  • 当添加或修改对象属性的时候就会触发 __setattr__ 方法

class Foo:
    def __init__(self):
        self.name = 'Kevin'

    def __setattr__(self, key, value):
        print(key, value)
"""
        执行结果:
            name Kevin
            age 10
        """


k = Foo()
k.age = 10

  • 注意: 在 __setattr__ 方法中是无法获取 __init__ 中的属性值,因为此时 __init__ 还没有执行 __setattr__(因为: 当设置了__setattr__方法,就代表已经覆盖了object的__setattr__方法了)

class Foo:
    def __init__(self):
        self.name = 'Kevin'

    def __setattr__(self, key, value):
        print(self.name)  # 无法获取报错,因为此时 __init__ 还没有执行 __setattr__
        print(key, value)


k = Foo()
k.age = 10

  • 在 __setattr__ 中获取 __init__ 中属性值的解决方法

class Foo(object):
    def __init__(self):
object.__setattr__(self, 'name', 'Kevin')  # 调用父类object类中的__setattr__方法设置值

    def __setattr__(self, key, value):
        print(self.name)  # Kevin
        print(key, value)  # age 10


k = Foo()
k.age = 10

11. __delattr__ 

  • 当删除类中属性的时候就会执行 __delattr__ 方法

class Foo(object):
    def __init__(self):
        self.name = 'Kevin'
        self.age = 18

    def __delattr__(self, item):
        print(item)  # age
        print("你正在删除一个属性")
        return super().__delattr__(item)  # 调用父类的 __delattr__ 方法删除属性


k = Foo()
del k.age

12. __eq__ 

  • 当判断两个对象是否相等的时候就会执行 __eq__ 方法

# 使用场景:
    # 一般情况下比较两个相同属性的对象的时候返回值是 False,因为在比较两个对象是否相等的时候是比较它们的内存地址,
    # 如果想比较当两个对象的属性都相等的时候比较的结果返回 True 的时候就要使用 __eq__ 实现

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):  # self 代表第一对象,other 代表第二对象
        if self.__dict__ == other.__dict__:
            return True
        else:
            return False

k = Foo('Kevin', 22)
y = Foo('Kevin', 22)

print(k == y)  # True
               # 如果不使用 __eq__ 返回值是 False

13. __hash__ 

  • 当使用 hash() 内置函数且所传入的值是一个对象的时候就会执行 __hash__

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __hash__(self):
        print('in __hash__')
        return hash(str(self.name) + str(self.age))

k = Foo('Kevin', 22)
y = Foo('Kevin', 22)
print(hash(k))
print(hash(y))

# 面试题:有84个对象且对这84个对象中的 name 和 sex 相同的对象进行去重
# 使用 set() 方法去重 且 set() 方法的执行机制是 __hash__ __eq__

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

    def __eq__(self, other):
        if self.name == other.name and self.sex == other.sex:
            return True
        else:
            return False

    def __hash__(self):
        return hash(self.name + self.sex)

p_lst = []
for i in range(84):
    p_lst.append(Person('Kevin', '男', i))

s = set(p_lst)
print(s)  # {<__main__.Person object at 0x000001618E2D1FD0>}

14. __class__ 

  • 获取/查看该对象所在的类

class Foo:
    def __init__(self):
        self.name = 'Kevin'

    def fn(self):
        print(self.__class__)  # <class '__main__.Foo'>


k = Foo()
k.fn()
print(k.__class__)  # <class '__main__.Foo'>

15. __mro__

  • 查看类的继承顺序 

class A(object):
    pass


class B(A):
    pass


class C(B):
    pass


print(C.__mro__)  # (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

16. __dict__

  • 查看类中的所有属性和方法

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

    def class_fn(self, other_data):
        print(self.name)
        print(self.age)
        print(other_data)
        print('类的方法')

p = Person('Kevin', 22)

print(Person.__dict__) # {'__module__': '__main__', '__init__': <function Person.__init__ at 0x000002439FA29D08>, 'class_fn': <function Person.class_fn at 0x000002439FA29C80>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

  • 查看类中的所有属性

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

    def class_fn(self, other_data):
        print(self.name)
        print(self.age)
        print(other_data)
        print('类的方法')

p = Person('Kevin', 22)

print(p.__dict__) # {'name': 'Kevin', 'age': 22}

  • 通过 __dict__ 对类的属性进行增删改查


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

p = Person('Kevin', 22)

print(p.__dict__)  # {'name': 'Kevin', 'age': 22}

p.__dict__['height'] = 175

print(p.__dict__)  # {'name': 'Kevin', 'age': 22, 'height': 175}


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

p = Person('Kevin', 22)

print(p.__dict__)  # {'name': 'Kevin', 'age': 22}

p.__dict__.pop('age')

print(p.__dict__)  # {'name': 'Kevin'}


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

p = Person('Kevin', 22)

print(p.__dict__)  # {'name': 'Kevin', 'age': 22}

p.__dict__['age'] = 18

print(p.__dict__)  # {'name': 'Kevin', 'age': 18}


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

p = Person('Kevin', 22)

print(p.__dict__['name'])  # Kevin

17. __slots__

  • 设置当前对象能访问到的属性

  • 当定义了__slots__后,__slots__中定义的变量变成了类的描述符,相当于java,c++中的成员变量声明

  • 注意

    • 类的实例只能拥有__slots__中定义的变量,不能再增加新的变量

    • 定义了__slots__后,就不再有__dict__

class Foo:
__slots__ = ['name', 'age']

    def __init__(self):
        self.name = 'Kevin'
        self.age = 22


obj = Foo()
print(obj.name)  # Kevin
print(obj.age)  # 22

  • 错误示范

class Foo:
    __slots__ = ['name']

    def __init__(self):
        self.name = 'Kevin'
self.age = 22


obj = Foo()
print(obj.name)
print(obj.age)
print(obj.__dict__)

18. __iter__

  • 当对象被循环的时候就会执行 __iter__ 方法,且必须返回一个迭代器或生成器

  • 将实例化的对象变成一个可迭代对象

  • 返回值: 迭代器 或 生成器

class Foo:
    def __iter__(self):
        return iter([1, 2, 3])  # 必须返回一个迭代器或生成器


iterable_obj = Foo()  # 实例化可迭代对象

# 循环可迭代对象
for num in iterable_obj:
    print(num)

class Foo:
    def __iter__(self):
# 必须返回一个迭代器或生成器
        yield 1
        yield 2
        yield 3


iterable_obj = Foo()  # 实例化可迭代对象

# 循环可迭代对象
for num in iterable_obj:
    print(num)

19. __add__

  • 当对象进行加法运算的时候就会执行 __add__ 方法

class Foo:
    def __add__(self, other):
        print(other)  # 5
        return other + 10


obj = Foo()
num = obj + 5
print(num)  # 15

20. __sub__

  • 当对象进行减法运算的时候就会执行 __sub__ 方法

class Foo:
    def __sub__(self, other):
        print(other)  # 5
        return 20 - other


obj = Foo()
num = obj - 5
print(num)  # 15

21.__enter__ 和 __exit__

  • 当 with 一个对象的时候就会执行 __enter__ 和 __exit__

  • __enter__ : 在执行 with 代码块里面的代码之前执行

  • __exit__ : 在执行完 with 代码块里面的代码后执行

class Foo:
    def __enter__(self):
        print('enter')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')


obj = Foo()

with obj:
    print(123)

"""
执行结果:
    enter
    123
    exit
"""