古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。

Python高级编程和异步I/O并发编程笔记 3 深入类和对象

Python admin 537℃ 0评论

鸭子类型和多态

鸭子类型是python中一个很重要的概念,贯穿了python类的核心知识点。在python中多态的前提是实现同样的方法。例如python中列表有extend()方法,其要求的参数只要实现了迭代相关的魔法方法即可,也就是说只要是迭代类型就可以作为参数传递。

抽象基类(abc模块)

python中的抽象基类类似Java中的接口(无法实现多继承,Java只能继承一个类,但可以继承多个接口),都是不能实例化的。继承抽象基类的类都必须实现基类中的方法,同时抽象基类不可以实例化。

在python已经拥有鸭子类型的情况下,为什么还设计了抽象基类,而不是直接实现方法?

如上例reason2中模拟实现抽象基类的方法,在子类调用set()方法时,如果没有重载基类的set()方法,则会抛出异常。更专业的写法是使用abc模块,python中abc模块有两个,一个是全局中的abc,直接”import abc”即可,还有一个是collection中的abc模块,实现抽象基类使用全局abc。如下例所示,此时,在初始化RedisCache时即会抛出异常。

在python中已经实现了一些通用的抽象基类,可以帮助我们理解数据结构的接口,这些都放在了collection中的abc模块,如Awaitable、Coroutine等等。总结来看,python虽然提供了静态语言里最常见的抽象基类的模式,但是python还是在尽量重用鸭子类型,所以鸭子类型才是python的根本。在使用python编码时,尽量少用抽象基类,而是使用鸭子类型,要将抽象基类看做“代码文档”,如果一定要继承某些接口的话,推荐使用mixin模式实现。

isinstance和type的区别

如上例所示,isinstance()会自动查找继承链,而type()只是在查找id()。

类变量和对象变量

类属性和实例属性以及查找顺序

属性查找顺序即“MRO算法”,简单继承中,在访问对象的属性时,如果在对象空间中没有查找到的内容会向上查找类变量,但是在多继承中,就会变得复杂。在早期的python版本中,MRO算法有采用“DFS算法(深度优先)”、“BFS算法(广度优先)”,都存在问题(覆盖、重载未被使用等)。当前在python中,python 2.2之前,python采用“经典类”的继承方式,即类A并不是自动继承Object类的,python 3则取消了“经典类”,所有类都继承自Object类,类的查找顺序则采用“C3算法”,比较复杂。在实践中,我们可以通过调用类的__mro__属性来查看类的查找顺序。

静态方法、类方法和对象方法以及参数

常见的类中的方法,以self即实例为对象的方法都是对象方法,如构造函数。以“@staticmethod”为装饰器的函数是静态方法,不需要接收实例对象参数,但是因为是定义在类空间中,所以使用的时候要通过类名来调用。由于静态方法中使用类的其他方法需要以类名来调用,这种“硬编码”的方式并不灵活,一旦类名修改,就会需要大量变动,所以出现了以“@classmethod”为装饰器的类方法,它默认第一个参数为类对象。不涉及类的其他内容的情况下,尽量用静态方法即可。

数据封装和私有属性

在Java等静态语言中提供有“private”或“protected”等关键字,来提供私有或受保护的方法,在python中并没有这样的设计,面对需要保护的属性可以使用私有属性,私有属性采用双下划线(__)的前缀,私有属性不可以在外部访问(如user.__birthday),但是可以通过类提供的方法来访问(如user.get_age()),与下例变量一样,在函数前加双下划线也可以把函数编程私有属性。但是这种方法也并不是从语言层面实现了真正的私有性和安全性,而是使用了结构化变形的方法的小技巧,如下列可以通过user.__User__birthday这种“__classname__attr”的方式获取到私有属性,虽然没有实现绝对安全,但是这种方式也是一种规范,对比Java中的private私有变量,其也无法做到绝对安全,利用Java的反射机制我们也可以获取,而且python的这种结构化方法也能够解决继承中同名私有属性的访问问题。

python对象的自省机制

自省是通过一定的机制查询对象的内部结构。如下例中使用“__dict__”查询属性,这个属性是使用C语言实现的,效率很高,是一个性能优越的数据结构,因为这个字典很重要,所以cpython编译器做了很多处理优化,python语言本身也大量应用了__dict__来做数据存储,在python类的内部结构里也是使用__dict__来做属性管理的。另一种更加强大的自省是使用python的内置函数dir(),可以列出对象的所有属性,但是仅提供有属性名而没有属性值。

super函数

django rest framework中对多继承使用的经验

mixin模式即混合模式,django rest framework是django的前后端分离的框架,内部大量采用了mixin模式。mixin模式的特点有mixin类的功能很单一;不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功,也就是说任意一个类都可以用或者不用这个mixin类,不具有强相关、绑定关系;在mixin中不要使用super这种用法。

python的上下文管理器

如上例所示,try…except..finally语句能够用来处理异常,而上下文管理器就是简化这个操作的,在python中就是with语句。with上下文管理器就是实现了上下文管理器协议(__enter__()和__exit__()两个魔法函数)的对象,python通过with来对上下文管理器协议进行支持。如下例,初始化时会先调用__enter__(),可以获取资源,在退出的时候调用__exit__(),可以释放资源。

上述方法可以实现自定义的上下文管理器,但是有些繁琐,为了简化操作,python提供了内置模块contextlib,其提供了一个装饰器”@contextlib.contextmanager”,巧妙地利用了生成器的特性,可以用来将一个函数变为上下文管理器,需要注意的是,使用这个装饰器修饰的函数必须为一个生成器。如下所示,yield之前的内容相当于上例的__enter__(),之后的内容相当于__exit__()。

转载请注明:北凉柿子 » Python高级编程和异步I/O并发编程笔记 3 深入类和对象

喜欢 (2)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址