python面向对象的细节问题总结

所周知,python是一个非常“沉默”的语言,不仅支持动态类型,对于面向对象的用法也可以最大程度地“放任”,直到程序完全跑不下去才会无情报错,但也由此带来很多坑,如果不深入研究,很可能引起非常隐蔽的逻辑错误。

本人最近因为业务需求的扩展,原本写死的多种逻辑、参数、阈值需要同时支持默认模式和可传参功能,而且要同时支持多套不同的环境的上传、下载、调用机制,所以需要对原python代码库做大量重构,不可避免地遇到了python面向对象的诸多坑。为了彻底搞清楚,作者做了一波实验,可能有些是一般情况下遇不到的,但有助于深入理解python面向对象机制,整理如下:

一、类变量(静态变量)和实例变量的用法

  1. 同一个类中的用法:

1) 类变量可以通过类名访问也可以通过实例self访问,实例变量只能通过实例self访问

2)假如有同名的类变量和实例变量,self只能访问实例变量,类变量只能用类名访问

  1. 在类的继承中的用法

1)子类必须显式地初始化父类,才可以继承父类的实例变量,并且只能用实例self访问,不显式初始化只能继承父类的类变量,或者不写__init__函数,默认使用父类的__init__函数初始化

2)子类可以继承父类的实例变量,只能用self访问

2)子类可以继承父类的类变量,可以用self/super()/子类类名/父类类名访问父类的类变量(子类类名竟然也行!!),假如父类还有同名的实例变量,子类用self只能访问父类的实例变量,用super()/子类类名/父类类名只能访问父类的类变量

  1. 子类可以重写父类的实例变量,只能用实例self访问子类的实例变量,无法访问父类的实例变量(因为实例化子类的时候并没有对父类进行实例化,super()得得到的只是父类的类对象!!)

4)子类可以重写父类的类变量,可以用self/子类类名访问子类的类变量,可以用父类类名/super()访问父类的类变量。假如父类还有同名的实例变量,子类用self只能访问父类的实例变量(也很神奇!!)
5)父类的保护属性(_开头)可以被父类实例和子类访问,私有属性(__开头)只能在类内部访问,但由于python的伪私有性质,在类的外部可以通过实例._类名__变量名访问

总结:

  1. 用self优先访问实例变量,即使是继承父类的实例变量,子类父类都找不到才会访问类变量

  2. 为避免出错,尽量使用类名访问类变量,除非继承情况

二、类方法(静态方法)和实例方法的用法

  1. 同一个类中的用法:

1) 类方法可以通过类名访问也可以通过实例self访问,实例方法只能通过实例self访问

2) 不允许有同名的类方法和实例方法,假如有,位置在下面的会覆盖上面的

  1. 在类的继承中的用法

1)子类可以不显式初始化父类,就可以继承父类的类方法和静态方法(注意和实例变量不一样,实例变量必须实例化才存在,而实例方法不依赖于实例化对象!!)

2)子类可以继承父类的实例方法,只能通过self访问

3)子类可以继承父类的类方法,可以用self/super()/子类类名/父类类名访问父类的类方法

4)子类可以重写父类的实例方法,可以用实例self访问子类的实例方法,也可以用super()访问父类的实例方法(注意也和实例变量不一样!!)

5)子类可以重写父类的类方法,可以用实例self/子类类名访问子类的类方法,也可以用父类类名/super()访问父类的类方法

6)子类重写父类方法时,参数个数必须一样

7)父类的保护方法(_开头)可以被父类实例和子类访问,私有方法(__开头)只能在类内部访问,但由于python的伪私有性质,在类的外部可以通过实例._类名__方法名访问

总结:方法和属性在大部分情况下的使用方式是一样的,主要有两个不同点:实例方法不依赖于实例而存在,且不允许与静态方法同名。

更多细节欢迎补充~


版权声明:本文为weixin_43148897原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。