python之路7:面向对象编程进阶

  1. 面向对象高级语法
  2. 异常处理

面向对象高级语法

经典类和新式类

从字面上可以看出一个老一个新,新的必然包含了更多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了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('
')
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
View Code

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)
View Code

异常处理

 在编程过程中为了增加友好性,在程序出现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 条件
View Code

参考: 

http://www.cnblogs.com/alex3714

http://www.cnblogs.com/wupeiqi

internet&python books

PS:如侵权,联我删。

原文地址:https://www.cnblogs.com/BillyLV/p/10917726.html