python-面向对象-进阶篇
类的成员
类的成员可以分为三大类:字段、方法和属性

一、字段
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同
class Province: // 静态字段 country = '中国' def __init__(self, name): // 普通字段 self.name = name obj = Province('河北省') print(obj.name) print(Province.country)
由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式不同

由上图可是:
- 静态字段在内存中只保存一份
- 普通字段在每个对象中都要保存一份
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段
二、方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
class Foo(object): def __init__(self, name): self.name = name def ord_func(self): """ 定义普通方法,至少有一个self参数 """ # print self.name print ('普通方法') @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print ('类方法') @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print ('静态方法') # 调用普通方法 f = Foo('阿郎') f.ord_func() # 调用类方法 Foo.class_func() # 调用静态方法 Foo.static_func()
class Student: f = open('student', encoding='utf-8') def __init__(self): pass @classmethod #类方法 :有个默认参数cls,并且可以直接使用类名去 #调用,还可以与类属性交互(也就是可以使用类属性) def show_student_info_class(cls): # f = open('student', encoding='utf-8') for line in cls.f: name,sex = line.strip().split(',') print(name,sex) @staticmethod #静态方法:可以直接使用类名去调用,就像正常的函数调用一样 def show_student_info_static(): #不用传self f = open('student',encoding='utf-8') for line in f: name,sex = line.strip().split(',') print(name,sex) # egon = Student() # egon.show_student_info_static() #也可以这样调,但是还是推荐用类名去调 # egon.show_student_info_class() Student.show_student_info_class()#类名.方法名() print('-------------------') Student.show_student_info_static()#类名.方法名() staticmethod和classmethod
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同
三、属性
如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。
对于属性,有以下2个知识点:
- 属性的基本使用
- 属性的两种定义方式
1、属性的基本使用
# ############### 定义 ############### class Foo: def func(self): pass # 定义属性 @property def prop(self): print('prop') # ############### 调用 ############### foo_obj = Foo() foo_obj.func() foo_obj.prop #调用属性

由属性的定义和调用要注意一下几点:
- 定义时,在普通方法的基础上添加 @property 装饰器;
- 定义时,属性仅有一个self参数
- 调用时,无需括号
方法:foo_obj.func()
属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:
- 根据用户请求的当前页和总数据条数计算出 m 和 n
- 根据m 和 n 去数据库中请求数据
# ############### 定义 ############### class Pager: def __init__(self, current_page): # 用户当前请求的页码(第一页、第二页...) self.current_page = current_page # 每页默认显示10条数据 self.per_items = 10 @property def start(self): val = (self.current_page - 1) * self.per_items return val @property def end(self): val = self.current_page * self.per_items return val # ############### 调用 ############### p = Pager(1) p.start 就是起始值,即:m p.end 就是结束值,即:n
从上述可见,Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。
2、属性的两种定义方式
属性的定义有两种方式:
- 装饰器 即:在方法上应用装饰器
- 静态字段 即:在类中定义值为property对象的静态字段
装饰器方式:在类的普通方法上应用@property装饰器
# ############### 定义 ############### class Goods(object): @property def price(self): print ('@property') @price.setter def price(self, value): print ('@price.setter') @price.deleter def price(self): print ('@price.deleter') # ############### 调用 ############### obj = Goods() obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数 del obj.price # 自动执行 @price.deleter 修饰的 price 方法
静态字段方式
class Foo: def get_bar(self): return 'wupeiqi' BAR = property(get_bar) obj = Foo() reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值 print (reuslt)
反射
反射:可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),python中一切皆对象,都可以使用反射。
反射有四种方法:
hasattr:hasattr(object,name)判断一个对象是否有name属性或者name方法。有就返回True,没有就返回False
getattr:获取对象的属性或者方法,如果存在则打印出来。hasattr和getattr配套使用
需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址,如果需要运行这个方法,可以在后面添加一对()
setattr:给对象的属性赋值,若属性不存在,先创建后赋值
delattr:删除该对象指定的一个属性
class Foo: f = '类的静态变量' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73) 检测是否含有某属性 print(hasattr(obj,'name')) //ture print(hasattr(obj,'say_hi')) //ture 获取属性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func() #设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) //{'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x000001FD977BC1E0>} print(obj.show_name(obj)) //egonsb # #删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__) //{'name': 'egon', 'sb': True}
class Foo: def __init__(self): self.name = 'egon' self.age = 51 def func(self): print('hello') egg = Foo() print(hasattr(egg,'name')) //#先判断name在egg里面存在不存在 print(getattr(egg,'name')) //#如果为True它才去得到 print(hasattr(egg,'func')) print(getattr(egg,'func')) //#得到的是地址 # getattr(egg,'func')() //#在这里加括号才能得到,因为func是方法 if hasattr(egg,'func'): getattr(egg,'func')() else: print('没找到') 对象应用反射
class Foo: f = 123 @classmethod def class_method_dome(cls): print('class_method_dome') @staticmethod def static_method_dome(): print('static_method_dome') print(hasattr(Foo,'class_method_dome')) method = getattr(Foo,'class_method_dome') method() print('------------') print(hasattr(Foo,'static_method_dome')) method1 = getattr(Foo,'static_method_dome') method1()
模块应用反射
# 1.导入其他模块引用 import mymodule print(hasattr(mymodule,'test')) getattr(mymodule,'test')() //# # 这里的getattr(mymodule,'test')()这一句相当于 //# p = getattr(mymodule,'test') //# p() 导入其他模块反射
本模块中反射
# 2.在本模块中应用反射 def demo1(): print('wwww') import sys # print(sys.modules) module_obj = sys.modules[__name__] #相当于'__main__' print(module_obj) print(hasattr(module_obj,'demo1')) getattr(module_obj,'demo1')() <module '__main__' from 'D:/pcxm/面向对象/类的复习.py'> True wwww
# 举例 def 注册(): print('regiester') def 登录(): print('login') def 购物(): pass print('注册,登录,购物') ret = input('请输入你要做的操作:') import sys my_module = sys.modules[__name__] #利用sys模块导入一个自己的模块 print(my_module) if hasattr(my_module,ret): getattr(my_module,ret)()
def bulk(self): print("%s is yelling....."%self.name) class Dog(object): def __init__(self,name): self.name=name def eat(self,food): print("%s is eating%s"%(self.name,food)) d=Dog("张文学") choice=input(">>_").strip() if hasattr(d,choice): getattr(d,choice) setattr(d,choice,"alex") print(d.name) else: setattr(d,choice,bulk) c=getattr(d,choice) c(d)
类的特殊成员
上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:
1. __doc__
表示类的描述信息
class Foo: """ 描述类信息,这是用于看片的神奇 """ def func(self): pass print (Foo.__doc__) #输出:类的描述信息
2. __module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
#!/usr/bin/env python # -*- coding:utf-8 -*- class C: def __init__(self): self.name = 'wupeiqi' lib/aa.py ----------------------------------------- #!/usr/bin/env python # -*- coding:utf-8 -*- from lib.aa import C obj = C() print obj.__module__ # 输出 lib.aa,即:输出模块 print obj.__class__ # 输出 lib.aa.C,即:输出类
3. __init__
构造方法,通过类创建对象时,自动触发执行。
class Foo: def __init__(self, name): self.name = name self.age = 18 obj = Foo('kefeng') # 自动执行类中的 __init__ 方法
4. __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
5. __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print '__call__' obj = Foo() # 执行 __init__ obj() # 执行 __call__
6. __dict__
类或对象中的所有成员
上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

class Province: country = 'China' def __init__(self, name, count): self.name = name self.count = count def 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'}
7. __str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Province: country = 'China' def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print ('func') def __str__(self): return self.name obj1 = Province('HeBei',10000) print (obj1) // hebei
8、__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
class Foo(object): def __getitem__(self, key): print('__getitem__', key) def __setitem__(self, key, value): print('__setitem__', key, value) def __delitem__(self, key): print('__delitem__', key) obj = Foo() result = obj['k1'] # 自动触发执行 __getitem__ obj['k2'] = 'wupeiqi' # 自动触发执行 __setitem__ # del obj['k1']
10. __iter__
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __init__(self, sq): self.sq = sq def __iter__(self): return iter(self.sq) obj = Foo([11,22,33,44]) for i in obj: print i 第三步
四、异常处理
一 异常基础
程序中难免会出现错误,而错误分为两种
1.语法错误:(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)
2.逻辑错误:(逻辑错误),比如用户输入的不合适等一系列错误
那什么是异常呢?
异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下。异常发生之后,异常之后的代码就不执行了

3 异常种类:在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,
不同的类对象标识不同的异常,一个异常标识一种错误
AttributeError //试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError //输入/输出异常;基本上是无法打开文件 ImportError //无法引入模块或包;基本上是路径问题或名称错误 IndentationError// 语法错误(的子类) ;代码没有正确对齐 IndexError //下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError //试图访问字典里不存在的键 KeyboardInterrupt //Ctrl+C被按下 NameError //使用一个还未被赋予对象的变量 SyntaxError //Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError// 传入对象类型与要求的不符合 UnboundLocalError //试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError// 传入一个调用者不期望的值,即使值的类型是正确的
二、异常处理
1.什么是异常处理?
python解释器检测到错误,触发异常(也允许程序员自己触发异常)
程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)
如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理
2.为何要进行异常处理?
python解析器去执行程序,检测到了一个错误时,触发异常,异常触发后且没被处理的情况下,程序就在当前异常处终止,后面的代码不会运行,谁会去用一个运行着突然就崩溃的软件。
所以你必须提供一种异常处理机制来增强你程序的健壮性与容错性
3.如何进行异常处理
首先须知,异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正
1.语法:
try: //被检测的代码块 except 异常类型: //try中一旦检测到异常,就执行这个位置的逻辑
2.异常类只能用来处理指定的异常情况,如果非指定异常则无法处理
// 未捕获到异常,程序直接报错 s1 = 'hello' try: int(s1) except IndexError,e: print e
3 所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:多分枝
s1 = 'hello' try: int(s1) except IndexError,e: print e except KeyError,e: print e except ValueError,e: print e
4 万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:
s1 = 'hello' try: int(s1) except Exception,e: print e
5既然有这个万能异常,其他异常是不是就可以忽略了!
答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行
s1 = 'hello' try: int(s1) except KeyError as e: print ('键错误') except IndexError as e: print ('索引错误') except Exception as e: print ('错误')
6 主动触发异常
try: raise IndexError('错误了。。。') except IndexError as e: print (e)
7 自定义异常
class lukefeng(Exception): def __init__(self, msg): self.message = msg def __str__(self): return self.message try: raise lukefeng('我的异常') except lukefeng as e: print (e)
8 断言
assert 1==12 if 1==2: print("123") print('haha')
9异常其他结构
try: # 主代码块 pass except KeyError,e: # 异常时,执行该块 pass else: # 主代码块执行完,执行该块 pass finally: # 无论异常与否,最终执行该块 pass

浙公网安备 33010602011771号