Pyhton——面向对象进阶二:类的内置函数补充和描述符

Python——面向对象进阶二:

一、类的内置函数补充

1、isinstance(obj,cls)——检查obj是否是该类的对象

class Hoo:
    def __init__(self,name,tem):
        self.name = name
        self.tem = tem

class foo(Hoo):
    pass

f1=foo('e',20)
print(isinstance(f1,Hoo))

首先 f1 肯定是 foo 的对象,如果 Hoo 是 foo 的父类,那么 f1 也同样是 Hoo 的对象。

2、issubclass(sub,super)——检查sub类是否是super类的派生类(子类)

在这里插入图片描述

3、__getattribute __

首先 __getattribute __ 与前面的 __getattr __ 很像,当然他们实际的功能也类似:

在这里插入图片描述
可以看到,当执行不存在的方法时,应该是执行 __getattr __ 的,但是现在执行的却是 __getattribute __ ;接着我们看下,如果执行的是存在的方法呢?

在这里插入图片描述
可以看到,当执行的方法是存在的时候,依然执行的是 __getattribute __ 。所以,无论执行的方法存不存在,都会执行 __getattribute __ 。

那么这个方法有什么作用呢?跟__getattr __ 又有什么联系呢?首先先来看下,当执行一个不存在的方法时,其报错的异常

在这里插入图片描述
这是原本的异常。
在__getattribute __方法中,可以通过 raise AttributeError 来发出你想要发出的异常

在这里插入图片描述
如果此时 __getattribute __ 与 __getattr __ 同时存在会发生什么呢?

在这里插入图片描述
从以上结果可以看到,当这两个方法同时存在,且执行类里面没有的方法时,是不会发出异常的,本该出现的异常被 __getattr __接去了,

4、__setitem __ 、__getitem __ 与 __delitem __

这三个与前面的 attr 函数很类似,功能也差不多。直接上结论。

attr 函数主要是通过 点 的方式触发,当通过 点 来调用方法时,就会触发 attr 函数。而 item 函数主要是通过字典来触发,当用字典来操作的时候,就会触发 item 函数

在这里插入图片描述
从上面的结果可以印证上面的结论

如果要完成本来的功能,看下:

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

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

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

5(1)、__str __ ——打印显示方式

在这里插入图片描述
f1 是类的实例化对象,直接打印这个对象,会显示这么一串东西。如果我们想要显示别的行不行?

在这里插入图片描述
修改此 str 就可以显示自己要显示的东西

5(2)、__repr __ ——打印显示方式

在这里插入图片描述
可以看到这里 repr 也能显示自定义打印方式

同样是打印显示方式,str 与 repr 有什么区别呢?
repr 主要在解释器中触发

那么 repr 与 str 同时存在会打印哪个?

在这里插入图片描述
两个同时存在的情况下,调用的是 str ,但并不是优先执行谁,而是 print 本质调用的是 str方法,如果 找不到 str ,就会去找 repr 这个替代品

注意:str 与 repr 返回值必须是字符串,否则会抛出异常

6、自定制 format 方法

方法:略
主要通过运用字典的方式来自定制

7、slots 属性

在这里插入图片描述

用法举例:
在这里插入图片描述
此方法用得少,用的时候慎用

8、__doc __ ——文档描述信息

该属性无法被继承
在这里插入图片描述

9、__module __和__class __ ——查看对象来自于哪一个模块或类

在这里插入图片描述

10、__del __ ——析构方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论:从上面三个结果中看出,只有实例被删除的时候才会触发 __del __ ;单单删除实例下的属性不会触发;文件执行完毕,实例被回收,触发__del __。

11、__call __

在这里插入图片描述在这里插入图片描述
foo 虽然是一个类,但是也是一个对象(既然是对象,就有另外一个类来产生)

12(1)、__iter __ 与 __next __ ——迭代器协议

在这里插入图片描述
其它的暂略… …

12(2)、迭代器协议实现斐波那契数列

在这里插入图片描述

13、__enter __ 和 __exit __ ————上下文管理协议

首先,先来看下文件处理操作

with open('abc.txt',w) as f:
	''代码''

上述代码叫做上下文管理协议,即with语句,为了让对象兼容with语句,必须在这个对象的类中声明__enter __ , 和 __exit __ 方法。先来看一下这两个方法的执行顺序

在这里插入图片描述

上图中,可以看到执行 with 语句的过程:先执行了 __enter __ 方法,然后输出横杠,with 里面的 print 语句执行完了,接着执行了__exit __ 方法,到此,with 语句就执行完毕了。最后就是输出等号。

如果在 __enter __ 方法中加一个 return:

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

    def __enter__(self):
        print('执行enter')
        return self

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

with foo('a.txt') as f:
    print('-------')
    print('-------')
    print('-------')

那么其执行顺序就是:foo 实例化,接着执行 enter 方法,return 返回值 给 f (f 就是 foo 产生的对象)

接着来看__exit __ 方法,其后面还有三个值。先看下图

在这里插入图片描述
可以看到,报出异常后,直接就执行了 exit 方法(执行到这里就停止了,后面的不执行);exc_type 意为错误类型,exc_val 意为错误信息,exc_tb 意为追踪信息(这个好像没啥用)。

如果不想看到异常,正常结束 with,就在 exit 里加个 return True。
在这里插入图片描述
上图中,可以看到异常被吞掉了,出错的后面部分没有执行,但是 with 这里属于正常结束。接着就是执行 with 外面的语句。

总结:
在这里插入图片描述
那么问题来了,其用途在哪?或者说好处?:
在这里插入图片描述

二、描述符(__get __、__set __、__delete __)

普通开发中用不到,开发大型的框架,给别人用的时候才用得到

1、描述符的定义

在这里插入图片描述

2、描述符的作用

描述符的作用:是用来代理另外一个类属性(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

在这里插入图片描述
从上图中看到,无论怎么调用,都无法触发里面的方法,问题在于,描述符是代理另外一个类的属性,所以,必须要其他的类来调用,才能触发。看下图:

在这里插入图片描述
上图中看到,必须是有其他的类来调用描述符,才能触发描述符方法

3、两种描述符

描述符分两种

在这里插入图片描述
在这里插入图片描述

注意事项:

一、描述符本身应该定义成新式类,被代理的类也应该是新式类
二、必须把描述符定义成这个类的类属性,不能定义为构造函数中

在这里插入图片描述
比如上图这个,定义成这种就不行,什么都不会触发。再看下图:
在这里插入图片描述
这种是可以触发的。在上图 类hoo 当中,x被 foo 描述了,所以凡是关于 x 的操作都是 foo的操作 ;x被 foo 代理了。

三、要严格遵循该优先级,优先级由高到低分别是:

1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()

举例子:
1、类属性与描述符
在这里插入图片描述
上图中,可以看到有描述符,有类。但是结果并不是显示描述符;因为 hoo 调用了自己的数据属性,此时显示的是 hoo 自己的属性,而描述符没有显示。所以优先级 类属性>描述符,实质是底层字典的覆盖操作,覆盖了描述符

2、描述符与实例属性
在这里插入图片描述
优先级:描述符>实例属性

3、实例属性与非数据描述符

没有实现 set 方法的就是数据描述符

在这里插入图片描述
优先级:实例属性>非数据描述符

4、描述符的应用

通过描述符来为python加上类型检测

由于在实例化对象之前,就要检测类型,所以选择数据描述符,因为数据描述符的优先级高于实例属性。

先来看下 set 方法与 get 方法后面两个值代表什么:

在这里插入图片描述
上图中:可以看到,instance 代表的是 p1, value 代表的是值 ,owner 代表的是该实例的拥有者(类)。但是发现似乎没有name,因为 name 被代理了,被Type的对象 Type()代理了,就是Type里面的self;所以 name 实际存储在 instance 里面。

在这里插入图片描述

这时候可以看到,people类实例化前,都要绕到Type类里面,原因在于真正实例化之前,可以进行判断类型检测,如果不符合,则不实例化,符合了才实例化。更多代码实现细节看上图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值