OOP 内置函数

内置函数:类中存在一些名字带有__(双下滑线)开头的内置函数,这些函数会在某些时候被自动调用

1.  isinstance &  issubclass

  isinstance:判断一个对象是否是某个类的实例

  用法:isinstance(obj, cls)    检查 obj 对象是否是 cls 类  (不仅限于类中)

  issubclass:判断一个类是否是另一个类的子类

  用法:issubclass(sub, super)    检查 sub 类是否是 super 类的派生类

2. __str__

  用法:调用 str 函数或者 print 函数时(输出结果为字符串)自动执行,返回值作为显示内容

  使用场景:我们可以利用该函数来自定义对象的打印格式(不设置则默认解释器里面内置的)

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

    def __str__(self):
        return '我叫%s,我今年%s岁了' % (self.name, self.age)  # 可以自定义输出格式


p = Person('zhao', 24)
print(p)  # 我叫zhao,我今年24岁了

 

3. __del__

  当对象在内存中被释放时(手动删除对象、程序运行结束时),会自动触发执行

  使用场景:当你的对象在使用过程中打开了不属于解释器的资源:例如文件、网络端口

class File:
    def __del__(self):
        print('已删除...')

f = File()
del f  # 已删除...

4. __call__

  在对象被调用时执行

  用法:对象()

  注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()的区别

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

    def __call__(self, *args, **kwargs):
        print('执行我了')
        print(*args)
        print(**kwargs)


p = Person('zhao', 24)  # 执行 __init__
p()  # 执行我了  执行 __call__
p('hobby = read')  # 执行我了  hobby = read    执行 __call__

 

5. __slots__

  该属性是一个类属性,用于优化对象内存占用

  优化的原理:将原本不固定的属性数量,变得固定了

  这样的解释器就不会为这个对象创建名称空间,所以__dict__也没了 

  从而达到减少内存开销的效果

  用法:

class Person:
    __slots__ = ['name']

p = Person()
p.name = 'jake'
print(p.__slots__)  # ['name']
p.age = 18  # 报错,当类中出现了slots时将导致这个类的对象无法在添加新的属性
''' Traceback (most recent call last): File "D:/代码练习/7.29/clots.py", line 10, in <module> p.age = 18 AttributeError: 'Person' object has no attribute 'age '''' print(p.__dict__) # 报错,使用slots后就不存在__dict__ ''' AttributeError: 'Person' object has no attribute 'age '''' ^ SyntaxError: EOL while scanning string literal '''

6. __getattribute__ & __getattr__ & __setattr__ & __delattr__

  __getattribute__:使用 点语法 调用 属性的时候触发,无论属性是否存在都会执行

  __getattr__:使用 点语法 调用 属性且属性不存在的时候才会触发

  __setattr__:使用 点语法 添加/修改 属性会触发它的执行

  __delattr__:使用 点语法 删除 属性的时候会触发

  注意:当 __getattribute__ 与 __getattr__ 同时存在时,仅执行 __getattribute__

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

    def __getattr__(self, item):
        return self.__dict__[item]

    def __setattr__(self, key, value):
        self.__dict__[key] = value

    def __delattr__(self, item):
        del self.__dict__[item]


p = Person('zhao')
print(p.__dict__)  # {'name': 'zhao'} 此时只有这么一个元素

p.age = 24
print(p.__dict__)  # {'name': 'zhao', 'age': 24}  触发了__setattr__,成功添加进去
print(p.age)  # 24  触发了__getattr__,成功访问到新添加进去的值

del p.age  # 触发__delattr__,成功删除p.age属性
print(p.__dict__)  # {'name': 'zhao'}

7. __getitem__ & __setitem__ & __delitem__

  __getitem__:使用 key 的形式获取属性时触发

  __setitem__:使用 key 的形式添加/修改属性时触发

  __delitem__:使用 key 的形式删除属性时触发

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

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

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        self.__dict__.pop(key)


p = Person('zhao', 24)
print(p.__dict__)  # {'name': 'zhao', 'age': 24}

p['name']  # 触发了__getitem__方法
print(p['name'])  # zhao

p['age'] = 18  # 触发了__setitem__方法
print(p['age'])  # 18

del p['name']  # 触发__delitem__方法
print(p.__dict__)  # {'age': 18}

8. __gt__ & __lt__ & __eq__ (运算符重载)

  当我们在使用某个符号时,python解释器都会为这个符号定义一个含义,同时调用对应的处理函数

  当我们需要自定义对象的比较规则时,就可在子类中覆盖大于、等于、小于等一系列方法....

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

    def __gt__(self, other):  # 自定义比较的方法,在这里比较的是对象中的年龄,覆盖了原来的   other指的是另一个参与比较的对象
        return self.age > other.age

    def __lt__(self, other):  # 自定义比较的方法,在这里比较的是对象中的年龄,覆盖了原来的   other指的是另一个参与比较的对象
        return self.age < other.age

    def __eq__(self, other):  # 自定义比较的方法,在这里比较的是对象中的年龄,覆盖了原来的   other指的是另一个参与比较的对象
        if self.age == other.age:
            return True
        return False


p = Person('', 24)
p1 = Person('', 18)
p2 = Person('', 18)

print(p > p1)  # True
print(p < p1)  # False
print(p1 == p2)  # True

 

9. __iter__ & __next__ (迭代器协议)

  回顾:迭代器是指具有__iter__和__next__的对象

  因此:我们可以为对象增加这两个方法来让对象变成一个迭代器

'''
定义自己的range方法
'''

class MyRange:  # 定义自己的range
    def __init__(self,start,end,step):
        self.start = start  # 起始
        self.end = end  # 结束
        self.step = step  # 步长

    def __iter__(self):
        return self  # 迭代器对象调用__iter__方法后还是迭代器,生成器对象调用__iter__方法后生成迭代器对象

    def __next__(self):
        a = self.start
        self.start += self.step
        if a < self.end:
            return a
        else:
            raise StopIteration  # 不知道这是啥,也没讲,也不敢问


myrange = MyRange(1,6,2)
for i in myrange:
    print(i)  # 1 3 5

10. __enter__ & __exit__ (上下文管理)

  上下文:context   在这个代码中python解释器分析出你的代码想要做的事情,然后在结束的时候自动帮你将资源释放了

  with中的所有代码都在一个上下文中,你可以把他理解为一个代码范围---------仅在上下文范围内有效

  __enter__出现 with语句,对象的 __enter__ 被触发,有返回值则赋值给 as 声明的变量

  __exit__with 中代码块执行完毕时执行

  只要一个类实现了这两个方法就可以被 with 语句使用

class MyOpen:  # 定义自己的打开
    def __init__(self, filepath, mode='r', encoding='utf-8'):
        self.filepath = filepath
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        self.f = open(self.filepath, mode=self.mode, encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):  # 三个参数分别代表异常类型,异常值和追溯信息
        self.f.close()
        print('文件关闭了')
     # return True with MyOpen(
'xxx.txt', 'a') as f: print(f) # <_io.TextIOWrapper name='xxx.txt' mode='a' encoding='utf-8'> 这是啥..... f.write('你好啊!') # 结果成功写入
   f.wasdf #抛出异常,交给__exit__处理
# 反正最后自己定义的MyOpen成功了,与内置的open具有相同的效果

注:1.  with 语句中代码块出现异常时,会立即触发方法 __exit__ 的执行,并将异常信息错误参数传入

  2.  with 语句中代码块未出现异常正常结束时也会触发方法 __exit__ 的执行,此时参数中的异常信息为空

  3. 如果 __exit__ 返回值为 True ,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行

总结:

  使用 with 语句的目的就是把代码块放入 with 中执行,with 结束后,自动完成清理工作,无须手动干预

  在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在 __exit__ 中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

*******与del的区别:del管理的是对象的生命周期 ,会在对象销毁时执行清理 

  

原文地址:https://www.cnblogs.com/pupy/p/11266477.html