1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【Python第六篇】Python面向对象(进阶篇)及相关(异常处理 反射)

【Python第六篇】Python面向对象(进阶篇)及相关(异常处理 反射)

时间:2021-03-21 01:52:34

相关推荐

【Python第六篇】Python面向对象(进阶篇)及相关(异常处理 反射)

本节内容:

类的成员字段方法(静态方法、类方法、普通方法)属性类成员的修饰符(私有成员、公有成员)类的特殊成员异常处理反射

类的成员

类的成员可以分为三大类:字段、方法和属性

注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

一、字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

普通字段属于对象静态字段属于

class Province:# 静态字段country = '中国'def __init__(self, name):# 普通字段self.name = name# 直接访问普通字段obj = Province('河北省')print obj.name# 直接访问静态字段Province.country

字段的定义和使用

由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式类似如下图:

由上图可是:

静态字段在内存中只保存一份普通字段在每个对象中都要保存一份

应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

二、方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls;静态方法:由调用;无默认参数;

class Foo:def __init__(self, name):self.name = namedef ord_func(self):""" 定义普通方法,至少有一个self参数 """# print self.nameprint '普通方法'@classmethoddef class_func(cls):""" 定义类方法,至少有一个cls参数 """print '类方法'@staticmethoddef static_func():""" 定义静态方法 ,无默认参数"""print '静态方法'# 调用普通方法f = Foo()f.ord_func()# 调用类方法Foo.class_func()# 调用静态方法Foo.static_func()

方法的定义和使用

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

不同点:方法调用者不同、调用方法时自动传入的参数不同。

三、属性

如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

对于属性,有以下三个知识点:

属性的基本使用属性的两种定义方式

1、属性的基本使用

# ############### 定义 ###############class Foo:def func(self):pass# 定义属性 @propertydef prop(self):pass# ############### 调用 ###############foo_obj = Foo()foo_obj.func()foo_obj.prop #调用属性

属性的定义和使用

由属性的定义和调用要注意一下几点:

定义时,在普通方法的基础上添加@property装饰器;定义时,属性仅有一个self参数调用时,无需括号

方法:foo_obj.func()

属性:foo_obj.prop

注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。

2、属性的两种定义方式

属性的定义有两种方式:

装饰器 即:在方法上应用装饰器静态字段 即:在类中定义值为property对象的静态字段

(1)装饰器方式:在类的普通方法上应用@property装饰器

我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )

经典类,具有一种@property装饰器

# ############### 定义 ############### class Goods:@propertydef price(self):return "wupeiqi"# ############### 调用 ###############obj = Goods()result = obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值

View Code

新式类,具有三种@property装饰器

# ############### 定义 ###############class Goods(object):@propertydef price(self):print '@property'@price.setterdef price(self, value):print '@price.setter'@price.deleterdef price(self):print '@price.deleter'# ############### 调用 ###############obj = Goods()obj.price# 自动执行 @property 修饰的 price 方法,并获取方法的返回值obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数del obj.price# 自动执行 @price.deleter 修饰的 price 方法

View Code

注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法

新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

class Goods(object):def __init__(self):# 原价self.original_price = 100# 折扣self.discount = 0.8@propertydef price(self):# 实际价格 = 原价 * 折扣new_price = self.original_price * self.discountreturn new_price@price.setterdef price(self, value):self.original_price = value@price.deltterdef price(self, value):del self.original_priceobj = Goods()obj.price # 获取商品价格obj.price = 200 # 修改商品原价del obj.price# 删除商品原价

实例

(2)静态字段方式,创建值为property对象的静态字段

当使用静态字段的方式创建属性时,经典类和新式类无区别

class Foo:def get_bar(self):return 'wupeiqi'BAR = property(get_bar)obj = Foo()result = obj.BAR # 自动调用get_bar方法,并获取方法的返回值print result

View Code

property的构造方法中有个四个参数

第一个参数是方法名,调用对象.属性时自动触发执行方法第二个参数是方法名,调用对象.属性 = XXX时自动触发执行方法第三个参数是方法名,调用del 对象.属性时自动触发执行方法第四个参数是字符串,调用对象.属性.__doc__,此参数是该属性的描述信息

class Foo:def get_bar(self):return 'wupeiqi'# *必须两个参数def set_bar(self, value): return return 'set value' + valuedef del_bar(self):return 'wupeiqi'BAR = property(get_bar, set_bar, del_bar, 'description...')obj = Foo()obj.BAR # 自动调用第一个参数中定义的方法:get_barobj.BAR = "alex"# 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入del Foo.BAR# 自动调用第三个参数中定义的方法:del_bar方法obj.BAE.__doc__# 自动获取第四个参数中设置的值:description...

View Code

由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

class Goods(object):def __init__(self):# 原价self.original_price = 100# 折扣self.discount = 0.8def get_price(self):# 实际价格 = 原价 * 折扣new_price = self.original_price * self.discountreturn new_pricedef set_price(self, value):self.original_price = valuedef del_price(self, value):del self.original_pricePRICE = property(get_price, set_price, del_price, '价格属性描述...')obj = Goods()obj.PRICE # 获取商品价格obj.PRICE = 200 # 修改商品原价del obj.PRICE# 删除商品原价

实例

所以,定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。

类成员的修饰符

类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:

公有成员,在任何地方都能访问私有成员,只有在类的内部才能方法

私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)

私有成员和公有成员的访问限制不同

静态字段

公有静态字段:类可以访问;类内部可以访问;派生类中可以访问私有静态字段:仅类内部可以访问;

class C:name = "公有静态字段"def func(self):print C.nameclass D(C):def show(self):print C.nameC.name # 类访问obj = C()obj.func()# 类内部可以访问obj_son = D()obj_son.show() # 派生类中可以访问

公有静态字段

class C:__name = "私有静态字段"def func(self):print C.__nameclass D(C):def show(self):print C.__nameC.__name # 类访问 ==> 错误obj = C()obj.func()# 类内部可以访问==> 正确obj_son = D()obj_son.show() # 派生类中可以访问 ==> 错误

私有静态字段

普通字段

公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问私有普通字段:仅类内部可以访问;

ps:如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。

class C:def __init__(self):self.foo = "公有字段"def func(self):print self.foo #类内部访问class D(C):def show(self):print self.foo# 派生类中访问obj = C()obj.foo# 通过对象访问obj.func() # 类内部访问obj_son = D();obj_son.show() # 派生类中访问

公有字段

class C:def __init__(self):self.__foo = "私有字段"def func(self):print self.foo #类内部访问class D(C):def show(self):print self.foo # 派生类中访问obj = C()obj.__foo# 通过对象访问 ==> 错误obj.func() # 类内部访问 ==> 正确obj_son = D();obj_son.show() # 派生类中访问 ==> 错误

私有字段

方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用

ps:非要访问私有属性的话,可以通过 对象._类__属性名

类的特殊成员

上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:

1. __doc__

表示类的描述信息

class Foo:""" 描述类信息,这是用于看片的神奇 """def func(self):passprint Foo.__doc__#输出:类的描述信息

View Code

2.__module__ 和 __class__

__module__ 表示当前操作的对象在那个模块

__class__ 表示当前操作的对象的类是什么

class C:def __init__(self):self.name = 'chris'

lib/aa.py

from lib.aa import Cobj = C()print obj.__module__ # 输出 lib.aa,即:输出模块print obj.__class__# 输出 lib.aa.C,即:输出类

index.py

3.__init__

构造方法,通过类创建对象时,自动触发执行。

class Foo:def __init__(self, name):self.name = nameself.age = 18obj = Foo('wupeiqi') # 自动执行类中的 __init__ 方法

View Code

4.__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class Foo:def __del__(self):pass

View Code

5.__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:def __init__(self):passdef __call__(self, *args, **kwargs):print '__call__'obj = Foo() # 执行 __init__obj() # 执行 __call__

View Code

6.__dict__

类或对象中的所有成员

上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

class Province:country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):print 'func'# 获取类的成员,即:静态字段、方法、print Province.__dict__# 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}obj1 = Province('HeBei',10000)print obj1.__dict__# 获取 对象obj1 的成员# 输出:{'count': 10000, 'name': 'HeBei'}obj2 = Province('HeNan', 3888)print obj2.__dict__# 获取 对象obj1 的成员# 输出:{'count': 3888, 'name': 'HeNan'}

View Code

7.__str__

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Foo:def __str__(self):return 'chris'obj = Foo()print obj# 输出:chris

View Code

8、__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

class Foo(object):def __getitem__(self, key):print '__getitem__',keydef __setitem__(self, key, value):print '__setitem__',key,valuedef __delitem__(self, key):print '__delitem__',keyobj = Foo()result = obj['k1']# 自动触发执行 __getitem__obj['k2'] = 'wupeiqi' # 自动触发执行 __setitem__del obj['k1'] # 自动触发执行 __delitem__

View Code

9、__getslice__、__setslice__、__delslice__

该三个方法用于分片操作,如:列表

class Foo(object):def __getslice__(self, i, j):print '__getslice__',i,jdef __setslice__(self, i, j, sequence):print '__setslice__',i,jdef __delslice__(self, i, j):print '__delslice__',i,jobj = Foo()obj[-1:1] # 自动触发执行 __getslice__obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__del obj[0:2]# 自动触发执行 __delslice__

View Code

10. __iter__

用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__

class Foo(object):def __init__(self, sq):self.sq = sqdef __iter__(self):return iter(self.sq)obj = Foo([11,22,33,44])for i in obj:print i

View Code

11. __new__ 和__metaclass__

阅读以下代码:

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

所以,obj对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a). 普通方式

b).特殊方式(type类的构造函数)

==》 类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性__metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为__metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

class MyType(type):def __init__(self, what, bases=None, dict=None):super(MyType, self).__init__(what, bases, dict)def __call__(self, *args, **kwargs):obj = self.__new__(self, *args, **kwargs)self.__init__(obj)class Foo(object):__metaclass__ = MyTypedef __init__(self, name):self.name = namedef __new__(cls, *args, **kwargs):return object.__new__(cls, *args, **kwargs)# 第一阶段:解释器从上到下执行代码创建Foo类# 第二阶段:通过Foo类创建obj对象obj = Foo()

View Code

类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__

异常处理

在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!

1、异常种类

python中的异常种类非常多,每个异常专门用于处理某一项异常!

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性xIOError 输入/输出异常;基本上是无法打开文件ImportError 无法引入模块或包;基本上是路径问题或名称错误IndentationError 语法错误(的子类) ;代码没有正确对齐IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]KeyError 试图访问字典里不存在的键KeyboardInterrupt Ctrl+C被按下NameError 使用一个还未被赋予对象的变量SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)TypeError 传入对象类型与要求的不符合UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它ValueError 传入一个调用者不期望的值,即使值的类型是正确的

常用异常

ArithmeticErrorAssertionErrorAttributeErrorBaseExceptionBufferErrorBytesWarningDeprecationWarningEnvironmentErrorEOFErrorExceptionFloatingPointErrorFutureWarningGeneratorExitImportErrorImportWarningIndentationErrorIndexErrorIOErrorKeyboardInterruptKeyErrorLookupErrorMemoryErrorNameErrorNotImplementedErrorOSErrorOverflowErrorPendingDeprecationWarningReferenceErrorRuntimeErrorRuntimeWarningStandardErrorStopIterationSyntaxErrorSyntaxWarningSystemErrorSystemExitTabErrorTypeErrorUnboundLocalErrorUnicodeDecodeErrorUnicodeEncodeErrorUnicodeErrorUnicodeTranslateErrorUnicodeWarningUserWarningValueErrorWarningZeroDivisionError

更多异常

dic = ["chris", 'alex']try:dic[10]except IndexError as e:print(e)

实例:IndexError

dic = {'k1':'v1'}try:dic['k20']except KeyError as e:print(e)

实例:KeyError

s1 = 'hello'try:int(s1)except ValueError as e:print(e)

实例:ValueError

对于上述实例,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。

所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:

万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:

接下来你可能要问了,既然有这个万能异常,其他异常是不是就可以忽略了!

答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。

2、异常其他结构

3、主动触发异常

4、自定义异常

5、断言

反射

python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,这四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

hasattr(object, name)

判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。

需要注意的是name要用引号引起来

1 >>> class test():2 ...name="xiaohua"3 ...def run(self):4 ... return "HelloWord"5 ...6 >>> t=test()7 >>> hasattr(t, "name") #判断对象有name属性8 True9 >>> hasattr(t, "run") #判断对象有run方法10 True

getattr(object, name[,default])

获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。

需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,

可以在后面添加括号()。

1 >>> class test():2 ...name="xiaohua"3 ...def run(self):4 ... return "HelloWord"5 ...6 >>> t=test()7 >>> getattr(t, "name") #获取name属性,存在就打印出来。8 'xiaohua'9 >>> getattr(t, "run") #获取run方法,存在就打印出方法的内存地址。10 <bound method test.run of <__main__.test instance at 0x0269C878>>11 >>> getattr(t, "run")() #获取run方法,后面加括号可以将这个方法运行。12 'HelloWord'13 >>> getattr(t, "age") #获取一个不存在的属性。14 Traceback (most recent call last):15 File "<stdin>", line 1, in <module>16 AttributeError: test instance has no attribute 'age'17 >>> getattr(t, "age","18") #若属性不存在,返回一个默认值。18 '18'

setattr(object, name, values)

给对象的属性赋值,若属性不存在,先创建再赋值。

1 >>> class test():2 ...name="xiaohua"3 ...def run(self):4 ... return "HelloWord"5 ...6 >>> t=test()7 >>> hasattr(t, "age") #判断属性是否存在8 False9 >>> setattr(t, "age", "18") #为属性赋值,并没有返回值10 >>> hasattr(t, "age") #属性存在了11 True

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。