一、作业
要点:
1、封装,对象中嵌套对象
2、pickle,load:切记,一定要先导入相关的类
二、上节内容回顾和补充
面向对象基本知识:
1、类和对象的关系
2、三大特性:
封装
继承
多态
多态(多种形态、多种类型)
# 接受任何类型就是多态
def func(arg):
print(arg)
func(11)
func('alex')
func([11,12,22,33])
C#/Java
def func(list arg):
print(arg)
func(123)
func("alex") # 报错
class A:
pass
class B(A):
pass
class C(A):
pass
# arg参数:必须是A类型或A的子类类型
def func(A arg):
print(arg)
# obj = B()
# obj = C()
obj = A()
func(obj)
三、面向对象中类成员
字段:
静态字段
普通字段
PS:静态字段代码加载时候,已经创建
方法
所有的方法属于类
1、普通方法:至少一个self,对象执行
2、静态方法:任意参数, 类执行(对象执行)
3、类方法 :至少一个cls, 类执行(对象执行)
属性
不论不类的东西
具有方法的写作形式,具有字段访问形式
1. 字段
class Foo:
#字段(静态字段)
CC = 123
def __init__(self):
# 普通字段
self.name = 'alex'
def show(self):
print(self.name)
ret = Foo()
ret.show()
结果
alex
多个对像共用一份中国
class Province:
coutory = "中国" #静态字段,可共用(类和对象共用)
def __init__(self,name):
self.name = name #普通字段
print(self.name)
hn = Province('河南')
hb = Province('河北')
sd = Province('山东')
db = Province('黑龙江')
#print(hn.name) #独个调用
-----结果
河南
河北
山东
黑龙江
#普通字段保存在对像里
#静态字段保存在类里
class Province:
coutory = "中国" #共用,静态字段
def __init__(self,name):
self.name = name #普通字段
# 一般情况:自己访问自己字段
# 规则:
# 普通字段只能使用对像访问
# 静态字段用类访问(万不得已的时候可以使用对像)
hn = Province('河南')
print(hn.name) #对象调用普通字段
print(Province.coutory) #类调用静态字段
print(hn.coutory) #对象调用静态字段,不建议使用
----结果
河南
中国
中国
2. 类的方法
所有的方法属于类
1.普通方法:至少一个self,对像执行
2.静态方法:任意参数,类执行 (也可对象执行,不对万不得已不用)
3.类方法,必须有cls,是类名,类执行(也可对象执行,不对万不得已不用)
#对像执行类的方法
class Province:
country = "中国"
def __init__(self,name):
self.name = name
def show(self): #定义show方法
print(self.name)
obj = Province("河南")
obj.show() #调用类的show方法
----方法合用
#静态方法,由类调用,不用self,不用创建对像
# @staticmethod 和 @classmethod 使用
class Province:
country = '中国' #静态字段,共用,静态字段,由类执行
def __init__(self,name): #构造方法
self.name = name #普通字段,由对象调用
#普通方法,由对象去调用执行(方法属于类)
def show(self): #普通方法
#print(self.name)
print(123)
@staticmethod #静态方法
#def f1(arg1,arg2):
def f1(cla,arg1,arg2):
#静态方法,由类调用执行,由类调用执行,不用self
print(arg1,arg2)
@classmethod #类方法
def f2(cls): #必须要有cls参数,cls全拼就是class,自动传值,就是把类当成参数传递
print(cls)
#Province.f1(11,22) #调用静态方法
Province.f1(Province,11,22) #调用静态方法
#Province.f1('fsafdsa',11,22)
Province.f2() #调用类方法
3. 属性
#类的属性,不用括号
class Pager:
def __init__(self,all_count):
self.all_count = all_count
@property #属性
def all_pager(self):
a1,a2 = divmod(self.all_count,10) #除法算余商
if a2 == 0: #如果没有余数,回显__init__的all_count
return a1
else: #否则商加1
return a1 + 1
p = Pager(101) #传101,就是100除以10
ret = p.all_pager #不用括号调用执行类方法,即类的属性
print(ret)
结果
11
类属性的获取,设置,删除功能,只是执行对应的属性调用对应的方法
# @property
# @.setter
# @.deleter
class Pager:
def __init__(self,all_count):
self.all_count = all_count
@property #获取
def all_pager(self):
a1,a2 = divmod(self.all_count,10)
if a2 == 0:
return a1
else:
return a1 + 1
@all_pager.setter #设置
def all_pager(self,value):
print(value)
@all_pager.deleter #删除
def all_pager(self):
print('del all_pager')
p = Pager(101)
ret = p.all_pager #执行这句就调用@property “获取”
print(ret)
p.all_pager = 111 #执行这句就调用@all_pager.setter “设置”
del p.all_pager #执行这句就调用@all_pager.deleter "删除"
结果
11
111
del all_pager
类的属性另一种使用方法
class Pager:
def __init__(self,all_count):
self.all_count = all_count
def f1(self):
return 123
def f2(self,value):
print(value)
def f3(self):
print('wmh')
foo = property(fget=f1,fset=f2,fdel=f3) #fget获取,fset设置,fdel删除
p = Pager(101)
result = p.foo #调用fget=f1
print(result)
p.foo = 'alex' #调用fset=f2
del p.foo #调用fdel=f3
结果
123
alex
wmh
四、成员修饰符
私有:
只能类自己本身成员内部可以访问
公有:
公有成员,在任何地方都能访问
私有成员,只有在类的内部才能方法
私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)
class C:
def __init__(self):
self.name = '公有字段'
self.__foo = "私有字段"
私有成员和公有成员的访问限制不同:
静态字段
公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
私有静态字段:仅类内部可以访问;
class C:
name = '公有静态字段'
def func(self):
print(C.name)
class D(C):
def show(self):
print(C.name)
C.name # 类访问
obj = C()
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() # 派生类中可以访问
1. 私有
#字段前面加__即创建私有字段,只有在内部调用
class Foo:
def __init__(self,name):
self.__name = name #__name 是私有字段,创建私有字段,只有内部可以调用
def f1(self):
print(self.__name) #内部可以访问私有字段
obj = Foo('alex')
print(obj.__name) # 不能用,这样写就会报错,因为外部访问不了
obj.f1() #可以调用
静态字段,私有调用
class Foo:
__cc = '123' #静态字段,私有使用
def __init__(self,name):
self.__name = name
def f1(self):
print(self.__name)
@staticmethod
def f3():
print(Foo.__cc) #可以内部调用
#print(Foo.__cc) #调用会报错因为是私有
obj = Foo('dddd')
obj.f3()
Foo.f3()
结果
123
123
私有字段,外部类也访问不了,即使你继承了它
class Foo:
def __init__(self,name):
self.__name = name #__name 是私有字段
def f1(self):
print(self.__name) #内部可以访问私有字段
class Bar(Foo): #Bar类继承了Foo类
def f2(self):
print(self.__name) #这里的类调用Foo类的__name是访问不了的,因为私有字段外部调用不了
obj = Bar("alex")
#obj.f2() #这里Bar类里调用f2方法继承Foo父类的__name是引用不了的,会报错
obj.f1() #这里Bar类直接输出父类的__name是可以的,所以可以打印alex
结果如下:
alex
特殊情况下,外部调用私有字段
class Foo:
def __init__(self, name):
self.__name = name
def f1(self):
print(self.__name)
obj = Foo("alex")
#print(obj.__name) #直接调用私有字段是不可以的,会报错
print(obj._Foo__name) #强制调用私有,语法:_类名__字段名
结果
alex
2. 公有
# 类内外都能访问的是公有字段,没有__下划线字段是公有字段,有__字段是私有字段
class Foo:
def __init__(self,name):
self.name = name
def f1(self):
print(self.name)
obj = Foo('alex')
print(obj.name)
obj.f1()
五. 特殊成员
__init__: 构造方法:如果存在,类首先自动执行,__init__() 就是调用构造方法
__del__: 析构方法:如果存在,类最后会自动执行,__del__() 就是调用析构方法
__call__: call方法:就是 对象() 执行call方法
__str__: 如果一个类中定义了__str__方法,那么打印对象时,默认输出该方法的返回值
__doc__
__setitem__
1. __doc__
表示类的描述信息
class Foo:
""" 描述类信息,这是用于看片的神奇 """
def func(self):
pass
print(Foo.__doc__)
#输出:类的描述信息
----结果
描述类信息,这是用于看片的神奇
2. __init__
构造方法,通过类创建对象时,自动触发执行。
class Foo:
def __init__(self,name):
self.name = name
self.age = 19
obj = Foo('wmh') # 自动执行类中的 __init__ 方法
print(obj.name)
print(obj.age)
4. __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
pass
5. __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
结果
__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 Foo:
def __str__(self):
return 'wupeiqi'
obj = Foo()
print(obj)
# 输出:wupeiqi
8、__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
#!/usr/bin/env python
# -*- coding:utf-8 -*-
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'] = 'wmh' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__
结果
__getitem__ k1
__setitem__ k2 wmh
__delitem__ k1
9、__getslice__、__setslice__、__delslice__
该三个方法用于分片操作,如:列表
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):
def __getslice__(self, i, j):
print('__getslice__',i,j)
def __setslice__(self, i, j, sequence):
print('__setslice__',i,j)
def __delslice__(self, i, j):
print('__delslice__',i,j)
obj = Foo()
#obj[-1:1] # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
del obj[0:2] # 自动触发执行 __delslice__
10. __iter__
#加__iter__就是为了给类for 循环
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
class Foo(object):
pass
obj = Foo()
for i in obj:
print i
# 报错:TypeError: 'Foo' object is not iterable
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):
def __iter__(self):
pass
obj = Foo()
for i in obj:
print i
# 报错:TypeError: iter() returned non-iterator of type 'NoneType'
----加__iter__就是为了给类for 循环递归,一个一个取
#!/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)
结果
11
22
33
44
以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
obj = iter([11,22,33,44])
for i in obj:
print(i)
1. call方法
class Foo:
#构造方法:如果存在,类首先自动执行,__init__() 就是调用构造方法
def __init__(self):
print('__init__')
#析构方法:如果存在,类最后会自动执行,__del__() 就是调用析构方法
def __del__(self):
print('__del__')
#call方法:可以对象直接加()调用
def __call__(self):
print('__call__')
obj = Foo()
obj() #对象直接调用call方法
Foo()() #与上面完全相同
2. str方法
class Foo:
#构造方法:如果存在,类首先自动执行,__init__() 就是调用构造方法
def __init__(self,name,age):
self.name = name
self.age = age
#析构方法:如果存在,类最后会自动执行,__del__() 就是调用析构方法
def __del__(self):
print('__del__')
#call方法:可以对象直接加()调用
def __call__(self):
print('__call__')
#如果一个类中定义了__str__方法,那么打印对象时,默认输出该方法的返回值
def __str__(self):
return '%s - %d' %(self.name,self.age)
obj1 = Foo('alex',73)
obj2 = Foo('eric',84)
#print(obj1)
#print(obj2)
ret = str(obj1)
print(ret)
结果
alex - 73
__del__
__del__
3. dict 方法
#获取类中的所有字段的数据
class Foo:
#构造方法:如果存在,类首先自动执行,__init__() 就是调用构造方法
def __init__(self,name,age):
self.name = name
self.age = age
#析构方法:如果存在,类在最后会自动执行,__del__() 就是调用析构方法
def __del__(self):
print('__del__')
def __call__(self):
print('__call__')
#如果一个类中定义了__str__方法,那么打印对象时,默认输出该方法的返回值
def __str__(self):
return '%s - %d' %(self.name,self.age)
obj1 = Foo('alex',73)
obj2 = Foo('eric',84)
ret = obj1.__dict__ #获取类中的所有字段的数据
print(ret)
class Foo:
#构造方法:如果存在,类首先自动执行,__init__() 就是调用构造方法
def __init__(self,name,age):
self.name = name
self.age = age
def __getitem__(self, item):
return 123
def __setitem__(self, key, value):
print('setitem')
def __delitem__(self, key):
print('del item')
obj = Foo('alex',73)
ret = obj['ad'] #执行__getitem__方法
print(ret)
obj['k1'] = 111 #执行__setitem__方法
del obj['k1'] #执行__delitem__方法
#取步长
li = [11,22,33,44,55]
print(li[0:5:2]) #2为取步长,在0到5的索引范围取两步的值
#切片类型使用,重要看结果都是切片类型
class Foo:
# 构造方法
def __init__(self, name,age):
self.name = name
self.age = age
# 析构方法
def __del__(self):
pass
def __call__(self):
print('call')
def __str__(self):
return "%s - %d" %(self.name, self.age)
def __add__(self, other):
temp = "%s - %d" %(self.name,other.age)
return temp
def __getitem__(self, item):
# print(type(item),item)
# item.start item.stop item.step
print(type(item))
return 123
def __setitem__(self, key, value):
# key.start key.stop key.step
print(type(key),type(value))
def __delitem__(self, key):
# key.start key.stop key.step
print(type(key))
obj = Foo('alex', 73)
# obj() # call
# 语法对应关系
# ret1 = obj['ad']
ret2 = obj[1:4:2]
obj[1:4] = [11,22,33,44,66]
del obj[1:4]
结果
<class 'slice'>
<class 'slice'> <class 'list'>
<class 'slice'>
类的迭代
#使用__iter__是为了给类for循环迭代
li = list([11,22,33,44])
for item in li:
print(item)
class Foo:
def __iter__(self):
return iter([11,22,33,44])
obj = Foo() #对象迭代
for item in obj:
print(item)
结果
11
22
33
44
for 循环对象默认引用iter方法
#有yield即生成器
class Foo:
def __iter__(self):
yield 1
yield 2
obj = Foo() #对象迭代
for item in obj:
print(item)
结果
1
2
六、面向对象其他
- isinstance
- issubclass
- 继承 2.7
- 应用:
自定义类型,对字典进行补充,有序字典
源码的扩展
1. isinstance 和 issubclass
# isinstance(obj,Bar) 判断一个对像是否是一个对像创建的
class Bar:
pass
class Foo(Bar):
pass
obj = Foo()
#obj,Bar(obj类型和obj类型的父类)的实列
ret = isinstance(obj,Bar) #判断obj是否是Bar类创建的
print(ret)
ret = issubclass(Bar,Foo) #判断类是否某类的父类
print(ret)
结果
True
False
七、异常处理
#当程序有异常情况,异常就出现了,就需要异常处理,有默认异常和自创建异常
while True:
num1 = input('num1:')
num2 = input('num2:')
try:
num1 = int(num1)
num2 = int(num2)
result = num1 + num2
except Exception as ex:
print(ex) #str
结果
num1:wrw
num2:fdsafa
invalid literal for int() with base 10: 'wefwrw'
自定义异常
#raise 引发异常
#!/usr/bin/python
# Filename: raising.py
class Error1(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s = raw_input('Enter something --> ')
if len(s) < 3:
raise Error1(len(s), 3) #raise 引发异常
# Other work can continue as usual here
except EOFError:
print '
Why did you do an EOF on me?'
except Error1, x:
print 'Error1: The input was of length%d,was expecting at least %d' % (x.length,x.atleast)
else:
print 'No exception was raised.'
#测试
python raising.py
Enter something --> #输入小于三位即触发Error1
Error1: The input was of length0,was expecting at least 3 #回显输入长度,至少长度为3
python raising.py
Enter something --> jalksjdlajflksafalds #输入长度超过3,即调用else的正常,没有异常触发
No exception was raised. #没有异常触发
python raising.py
Enter something --> #非法操作ctrl+d即,返回FOFError
Why did you do an EOF on me? #你对我做了什么
#finally 无论异常发生于否都执行操作,总是会运行
touch poem.txt
vi finally.py
import time
try:
f = file('poem.txt')
while True:
line=f.readline()
if len(line)==0:
break
time.sleep(2) # time.sleep 方法暂停2秒钟
print line,
finally:
f.close()
print 'Cleaning up.....closed the file'
八、设计模式之单例模式
类方法
静态方法
1.类方法
执行父类的方法
class C1:
def f1(self):
print('c1.f1')
class C2(C1):
def f1(self):
#主动执行父类的f1方法
super(C2,self).f1()
print('c2.f1')
#C1.f1(self) # python 2.0 执行父类f1方法
obj = C2()
obj.f1()
结果
c1.f1
c2.f1
#实现有序的字典
class MyDict(dict):
def __init__(self):
self.li = []
super(MyDict,self).__init__()
def __setitem__(self, key, value):
self.li.append(key)
super(MyDict,self).__setitem__(key,value)
def __str__(self):
temp_list = []
for key in self.li:
value = self.get(key)
temp_list.append("'%s':%s" % (key,value,))
temp_str = "{" + ",".join(temp_list) + "}" #字符串拼接成的有序字典
return temp_str
#
obj = MyDict()
obj['k1'] = 123
obj['k2'] = 456
print(obj)
结果
{'k1':123,'k2':456}
2. 单例模式
#永远都是一个结果
class Foo:
instance = None
def __init__(self,name):
self.name = name
@classmethod
def get_instance(cls):
# cls类名
if cls.instance:
return cls.instance
else:
obj = cls('alex')
cls.instance = obj
return obj
obj1 = Foo.get_instance()
print(obj1)
obj2 = Foo.get_instance()
print(obj2)
结果
<__main__.Foo object at 0x00000000010E3978>
<__main__.Foo object at 0x00000000010E3978>