python之路7:面向对象编程进阶
- 面向对象高级语法
- 异常处理
面向对象高级语法
经典类和新式类
从字面上可以看出一个老一个新,新的必然包含了更多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了。
类的成员
类的成员可以分为三大类:字段、方法和属性
注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。
一、字段
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,
- 普通字段属于对象
- 静态字段属于类
二、方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:可以在实例化后直接调用,执行普通方法时,自动将调用该方法的对象赋值给self;至少一个self参数。
- 类方法:通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问静态字段,不能访问普通字段。至少一个参数。
- 静态方法:通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,静态方法是不可以访问静态字段或普通字段的。不要参数。
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:普通方法它的调用者不同、调用方法时自动传入的参数不同。
三、属性
在普通方法的基础上添加 @property 装饰器,属性仅有一个self参数,调用时,无需括号。
四、私有成员和公有成员
- 公有成员:在任何地方都能访问
- 私有成员:只有在类的内部才能访问,命名时,前两个字符是下划线__
- 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
- 私有静态字段:仅类内部可以访问;
- 公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
- 私有普通字段:仅类内部可以访问;
1 # -*- coding:utf-8 -*- 2 __author__ = 'BillyLV' 3 4 class Province(object): 5 # 静态字段 6 name = '省份' #公有静态字段 7 __name = "私有静态字段" 8 def __init__(self, name): 9 # 普通字段 10 self.name = name #公有普通字段 11 self.__foo = "私有普通字段" 12 13 def func1(self): 14 print(Province.__name)#打印私有静态字段 15 print(self.__foo)#打印私有普通字段 16 17 def ord_func(self): 18 """ 定义普通方法,至少有一个self参数 """ 19 print('普通方法') 20 21 @property #属性 22 def car(self): 23 print('@property获取') 24 25 @car.setter 26 def car(self,value): 27 print('@car.setter设置value') 28 29 @car.deleter 30 def car(self): 31 print('@car.deleter删除') 32 33 @classmethod 34 def class_func(self): 35 """ 定义类方法,至少有一个参数 """ 36 print('类 %s' % self.name)#只能访问类变量,即name = '省份',而不是构造方法里self.name的值了 37 38 @staticmethod 39 def static_func(): 40 """ 定义静态方法 ,无参数""" 41 print('静态方法' ) 42 43 class city(Province): 44 def func2(self): 45 print(Province.__name) 46 print(self.__foo) 47 48 obj = Province('湖北省') 49 50 obj.func1()#私有静态或普通字段仅类内部可以访问 51 52 # 直接访问公有普通字段,公有普通字段需要通过对象来访问,在每个对象中都要保存一份 53 print(obj.name) 54 obj.ord_func() 55 obj.class_func() 56 obj.static_func() 57 print('\n') 58 Province.class_func() 59 Province.static_func() 60 # 直接访问公有静态字段,公有静态字段通过类访问,在内存中只保存一份 61 print(Province.name) 62 63 obj.car #属性调用,自动执行 @property 修饰的car方法,并获取方法的返回值 64 obj.car = 1000000 #自动执行 @property 修饰的car方法并赋值给参数 65 del obj.car
ps:如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。
类的特殊成员方法:
__doc__ 表示类的描述信息
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
__init__ 构造方法,通过类创建对象时,自动触发执行。
__del__ 析构方法,当对象在内存中被释放时,自动触发执行。析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
__call__ 对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
__dict__ 查看类或对象中的所有成员
__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
__getitem__、__setitem__、__delitem__ 用于索引操作,如字典。分别表示获取、设置、删除数据
__getslice__、__setslice__、__delslice__ 该三个方法用于分片操作
__iter__ 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
__metaclass__ 用来表示该类由 谁 来实例化创建
PS:类的生成调用顺序依次是 __new__ --> __init__ --> __call__
反射
python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,该四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。
1 # -*- coding:utf-8 -*- 2 __author__ = 'BillyLV' 3 4 class test(super): 5 def __init__(self): 6 self.name = 'bill' 7 def func(self): 8 print('just testing') 9 10 obj = test() 11 12 # 检查是否含有成员 13 print(hasattr(obj,'na'))#如无打印False 14 print(hasattr(obj,'name'))#如有打印True 15 print(hasattr(obj,'func')) 16 17 # 获取成员 18 getattr(obj,'name')#如没有会报错 19 getattr(obj,'func') 20 print(obj.name) 21 print(getattr(obj,'name')) 22 obj.func() 23 print('-1-') 24 25 # 设置成员 26 setattr(obj,'name','lv')#把name值改为lv 27 setattr(obj,'age','20')#添加age值为20 28 setattr(obj, 'show', lambda num: num + 1) 29 print(obj.age) 30 print(getattr(obj,'age')) 31 print(obj.show(2)) 32 print('----------',obj.name) 33 print('-2-') 34 35 # 删除成员 36 delattr(obj,'age') 37 #delattr(obj,'show') 38 print(obj.show(4)) 39 obj.func() 40 print(obj.name) 41 print(getattr(obj,'name')) 42 a=obj.__dict__['name'] 43 print(a)
异常处理
在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是显示一个提示的页面。
python中的异常种类非常多,每个异常专门用于处理某一项异常。
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
1 # -*- coding:utf-8 -*- 2 __author__ = 'BillyLV' 3 4 list1 = ['a','b'] 5 try: 6 # 主代码块 7 c = list1[1] 8 f = open('file1') 9 10 # 异常时,执行该块 11 except IndexError as e: 12 print('列表错误',e) 13 except FileNotFoundError as e: 14 print('文件异常',e) 15 except Exception as e: 16 print('未知错误',e) 17 except BaseException as e: 18 print('所有错误',e) 19 20 # 主代码块执行完,执行该块 21 else: 22 print('一切正常') 23 24 # 无论异常与否,最终执行该块 25 finally: 26 print('不管有没有错都执行') 27 28 #主动触发异常 29 try: 30 raise Exception('出错了') 31 except Exception as e: 32 print(e) 33 34 #手动触发异常,用于调试检查 35 assert 1 == 1 36 assert 1 == 2 # assert 条件
参考:
http://www.cnblogs.com/alex3714
http://www.cnblogs.com/wupeiqi
internet&python books
PS:如侵权,联我删。