python 类的进阶
类的进阶
一 isinstance(obj,cls)和issubclass(sub,super)
1 class Foo:
2 def __init__(self,name):
3 self.name = name
4
5 obj = Foo("egon")
6
7 print(isinstance(obj,Foo))
8
9
10 l = list([1,2,3])
11 print(isinstance(l,list))
12
13 -----------------结果-----------
14
15 True
16 True
17
18 isinstance(obj,cls)检查是否obj是否是类 cls 的对象
1 class Foo:
2 pass
3
4 class Bar(Foo):
5 pass
6
7 print(issubclass(Bar,Foo))
8
9 ------------------------结果----------
10 True
11
12 issubclass(sub, super)检查sub类是否是 super 类的派生类
二.反射
1.python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
1 class People:
2 country = "china"
3 def __init__(self,name):
4 self.name = name
5
6
7 p = People("egon")
8 print(p.__dict__)
9 #-------------------------
10 print(hasattr(p,"name"))
11 print("name" in p.__dict__)
12 print(hasattr(People,"country"))
13
14 ----------------------------------
15 {'name': 'egon'}
16 True
17 True
18 True
1 class People:
2 country = "china"
3 def __init__(self,name):
4 self.name = name
5
6 def walk(self):
7 print("%s is working" % self.name)
8
9 p = People("egon")
10
11 print(getattr(p,"country")) #print(p.country)
12 # china
13 print(getattr(p,"walk")) #print(p.walk)
14 #<bound method People.walk of <__main__.People object at 0x101979278>>
1 class People:
2 country = "china"
3 def __init__(self,name):
4 self.name = name
5
6 def walk(self):
7 print("%s is working" % self.name)
8
9 p = People("egon")
10
11 setattr(p,"age",15)
12 print(p.__dict__)
13 {'age': 15, 'name': 'egon'}
1 class People:
2 country = "china"
3 def __init__(self,name):
4 self.name = name
5
6 def walk(self):
7 print("%s is working" % self.name)
8
9 p = People("egon")
10
11 print(p.__dict__)
12 {'name': 'egon'}
13 delattr(p,"name")
14 print(p.__dict__)
15 {}
1 import sys
2 def add():
3 print("add")
4
5 def delete():
6 print("delete")
7
8 def update():
9 print("update")
10
11 def search():
12 print("search")
13
14 this_module = sys.modules[__name__]
15 while True:
16 cmd = input("please input: ")
17 if not cmd:continue
18 if hasattr(this_module,cmd):
19 func = getattr(this_module,cmd)
20 func()
2.反射的好处
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,
lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?
即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
1 #Ftpclent.py 文件
2
3 class FtpClient:
4 'ftp客户端,但是还么有实现具体的功能'
5 def __init__(self,addr):
6 print('正在连接服务器 %s ' %addr)
7 self.addr=addr
8
9 def get(self):
10 print("get")
11
12
13 #Ftpserver.py 文件
14
15 from day32 import FtpClient
16
17 obj = FtpClient.FtpClient('192.168.1.1')
18
19 if hasattr(obj,"get"):
20 func = getattr(obj,"get")
21 func()
22
23 print("other func")
好处二:动态导入模块(基于反射当前模块成员)
1
2
3
4
5
6
7
8
|
#导入字符串 __import__ ( "time" ) #使用模块 import importlib t = importlib.import_module( "time" ) print (t.time()) 1493026292.217129 |
三.__setattr__,__delattr__,__getattr__
1 #初始化和赋值时触发__setattr__运行
2
3
4 #发现__dict__没有name 和 age
5 class Foo:
6 def __init__(self,name):
7 self.name = name
8
9 def __setattr__(self, key, value):
10 print("__setattr__ key:%s value:%s"%(key,value))
11
12 obj = Foo("egon")
13 __setattr__ key:name value:egon
14 obj.age = 18
15 __setattr__ key:age value:18
16 print(obj.__dict__) #发现__dict__没有name 和 age
17 {}
18
19
20 #初始化和赋值都在__dict__中找到
21
22 class Foo:
23 def __init__(self,name):
24 self.name = name
25
26 def __setattr__(self, key, value):
27 print("__setattr__ key:%s value:%s"%(key,value))
28 self.__dict__[key] = value
29
30 obj = Foo("egon")
31 __setattr__ key:name value:egon
32 obj.age = 15
33 __setattr__ key:age value:15
34 print(obj.__dict__)
35 {'name': 'egon', 'age': 15}
36
37
38
39 #初始化赋值时判断如果不是数字不可以赋值
40
41 class Foo:
42 def __init__(self,name):
43 self.name = name
44
45 def __setattr__(self, key, value):
46 if not isinstance(value,int):
47 raise TypeError("type error")
48 self.__dict__[key] = value
49
50 obj = Foo(15)
51 obj.age = 15
52 print(obj.__dict__)
53 {'age': 15, 'name': 15}
1 __delattr__
1 #属性不存在时候运行
2
3 class Foo:
4 def __init__(self,name):
5 self.name = name
6
7 def __getattr__(self, item):
8 print("__getattr__ %s" % item)
9
10 obj = Foo("egon")
11 print(obj.name)
12 egon
13 print(obj.xxx)
14 __getattr__ xxx
15 None
四. 二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
1 #自定义自己的数据类型,追加和插入,如果不是数字,报错
2
3 class List(list):
4 def append(self, p_object):
5 if not isinstance(p_object,int):
6 raise TypeError("Type error")
7 super().append(p_object)
8
9 def insert(self, index, p_object):
10 if not isinstance(p_object,int):
11 raise TypeError("Type error")
12 super().insert(index,p_object)
13
14 l = List([1,2,3])
15 print(l)
16 [1, 2, 3]
17 l.append("4") #不能追加字符串
18
19 l.insert(0,-1)
20 print(l)
21 [-1, 1, 2, 3]
1 import time
2
3 class Open:
4 def __init__(self,filepath,mode="r",encode="utf-8"):
5 self.x = open(filepath,mode=mode,encoding=encode)
6 self.filepath = filepath
7 self.mode = mode
8 self.encoding = encode
9
10 def write(self,value):
11 log_time = time.strftime('%Y-%m-%d %X')
12 self.x.write("%s %s" % (log_time,value))
13
14 def __getattr__(self, item):
15 return getattr(self.x,item)
16
17 f = Open("b.txt","a+")
18 f.write("11111111\n")
19 f.seek(0)
20 print(f.read())
1 #基于继承来定制自己的数据类型
2 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
3 def append(self, p_object):
4 ' 派生自己的append:加上类型检查'
5 if not isinstance(p_object,int):
6 raise TypeError('must be int')
7 super().append(p_object)
8
9 @property
10 def mid(self):
11 '新增自己的属性'
12 index=len(self)//2
13 return self[index]
14
15
16 l=List([1,2,3])
17 print(l.mid)
18
19
20
21 基于授权来定制自己的数据类型:
22
23 class Open:
24 def __init__(self,filepath,mode,encode='utf-8'):
25 self.f=open(filepath,mode=mode,encoding=encode)
26 self.filepath=filepath
27 self.mode=mode
28 self.encoding=encode
29
30 def write(self,line):
31 print('write')
32 self.f.write(line)
33
34 def __getattr__(self, item):
35 return getattr(self.f,item)
36
37
38 f=Open('a.txt','w')
39 f.write('123123123123123\n')
40 print(f.seek)
41 f.close()
五.反射作业
1
2
3
4
|
1. 基于授权定制自己的列表类型,要求定制的自己的__init__方法, 2. 定制自己的append:只能向列表加入字符串类型的值 3. 定制显示列表中间那个值的属性(提示: property ) 4. 其余方法都使用 list 默认的(提示:__getattr__加反射) |
1 class List:
2 def __init__(self,x):
3 self.seq=list(x)
4
5 def append(self,value):
6 if not isinstance(value,str):
7 raise TypeError('must be str')
8 self.seq.append(value)
9 @property
10 def mid(self):
11 index=len(self.seq)//2
12 return self.seq[index]
13 def __getattr__(self, item):
14 return getattr(self.seq,item)
15
16 def __str__(self):
17 print("111")
18 return str(self.seq)
19
20 l=List([1,2,3])
21
22 l.append('1')
23
24 print(l.mid)
25
26 l.insert(0,123)
六.__setitem__,__getitem,__delitem__
1 #把对象操作属性模拟成字典的格式
2
3 class Foo:
4 def __init__(self,name):
5 self.name = name
6
7 def __getitem__(self, item):
8 return self.__dict__[item]
9 def __setitem__(self, key, value):
10 self.__dict__[key] = value
11 def __delitem__(self, item):
12 self.__dict__.pop(item)
13
14
15 f = Foo("egon")
16 print(f.name)
17 egon
18 f.name = "egonlin"
19 print(f.__dict__)
20 {'name': 'egonlin'}
21
22 f["age"] = 18
23 print(f.__dict__)
24 {'name': 'egon', 'age': 18}
25
26 del f["name"]
27 print(f.__dict__)
28 {}
七.__slots__
'''
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该
只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。 更多的是用来作为一个内存优化工具。
'''
class Foo:
__slots__='x'
f1=Foo()
f1.x=1
f1.y=2#报错
print(f1.__slots__) #f1不再有__dict__
class Bar:
__slots__=['x','y']
n=Bar()
n.x,n.y=1,2
n.z=3#报错
__slots__使用
八.__next__和__iter__实现迭代器协议
1 class Foo:
2 def __init__(self, end,start=0):
3 self.start = start
4 self.end = end
5 def __iter__(self):
6 return self
7
8 def __next__(self):
9 if self.start >= self.end:
10 raise StopIteration
11 n = self.start
12 self.start+=1
13 return n
14
15 f = Foo(10)
16 for i in f:
17 print(i)
1 class Range:
2 def __init__(self,start,stop):
3 self.start = start
4 self.stop = stop
5
6 def __iter__(self):
7 return self
8
9 def __next__(self):
10 if self.start >= self.stop:
11 raise StopIteration("StopIteration Error")
12 n = self.start
13 self.start += 1
14 return n
15
16 obj = Range(0,15)
17
18 for i in obj:
19 print(i)
1 class Range:
2 def __init__(self, *args):
3 self.args = args
4 if len(self.args) == 2:
5 self.start = self.args[0]
6 self.end = self.args[1]
7 else:
8 self.start = 0
9 self.end = self.args[0]
10 def __iter__(self):
11 return self
12
13 def __next__(self):
14 n = self.start
15 if n < self.end:
16 n = self.start
17 self.start += 1
18 return n
19 raise StopIteration
20
21
22 for i in Range(1,10):
23 print(i)
24
25 for i in Range(10):
26 print(i)
1 class Fib:
2 def __init__(self):
3 self._a=0
4 self._b=1
5
6 def __iter__(self):
7 return self
8
9 def __next__(self):
10 self._a,self._b=self._b,self._a + self._b
11 return self._a
12
13 f1=Fib()
14
15 print(f1.__next__())
16 print(next(f1))
17 print(next(f1))
18
19 for i in f1:
20 if i > 100:
21 break
22 print('%s ' %i,end='')
九.__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
1 class Foo:
2
3 def __del__(self):
4 print('执行我啦')
5
6 f1=Foo()
7 del f1
8 print('------->')
9 --------------------结果-------------
10
11 执行我啦
12 ------->
1 class Foo:
2
3 def __del__(self):
4 print('执行我啦')
5
6 f1=Foo()
7 print('------->')
8 --------------------结果-------------
9
10 ------->
11 执行我啦
十.__enter__和__exit__
1 with open('a.txt') as f:
2 '代码块'
3
4 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
5
6 class Open:
7 def __init__(self,name):
8 self.name=name
9
10 def __enter__(self):
11 print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
12 # return self
13 def __exit__(self, exc_type, exc_val, exc_tb):
14 print('with中代码块执行完毕时执行我啊')
15
16
17 with Open('a.txt') as f:
18 print('=====>执行代码块')
19
20 -----------------结果----------------
21
22 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
23 =====>执行代码块
24 with中代码块执行完毕时执行我啊
1 class Open:
2 def __init__(self,name):
3 self.name=name
4
5 def __enter__(self):
6 print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
7
8 def __exit__(self, exc_type, exc_val, exc_tb):
9 print('with中代码块执行完毕时执行我啊')
10 print(exc_type)
11 print(exc_val)
12 print(exc_tb)
13
14
15
16 with Open('a.txt') as f:
17 print('=====>执行代码块')
18 raise AttributeError('***着火啦,救火啊***')
19 print('0'*100) #------------------------------->不会执行
1 class Open:
2 def __init__(self,name):
3 self.name=name
4
5 def __enter__(self):
6 print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
7
8 def __exit__(self, exc_type, exc_val, exc_tb):
9 print('with中代码块执行完毕时执行我啊')
10 print(exc_type)
11 print(exc_val)
12 print(exc_tb)
13 return True
14
15
16
17 with Open('a.txt') as f:
18 print('=====>执行代码块')
19 raise AttributeError('***着火啦,救火啊***')
20 print('0'*100) #------------------------------->会执行
1 import time
2
3 class Open:
4 def __init__(self,filepath,mode="r",encode="utf-8"):
5 self.x = open(filepath,mode=mode,encoding=encode)
6 self.filepath = filepath
7 self.mode = mode
8 self.encoding = encode
9
10 def __enter__(self):
11 return self
12
13 def __exit__(self, exc_type, exc_val, exc_tb):
14 self.x.close()
15 return True
16
17 def write(self,value):
18 log_time = time.strftime('%Y-%m-%d %X')
19 self.x.write("%s %s" % (log_time,value))
20
21 def __getattr__(self, item):
22 return getattr(self.x,item)
23
24
25 with Open("b.txt","a+") as f : #obj = Open().__enter__() ---> obj = f
26 f.write("11111111\n")
十一.__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
__call__
十二.__str__
1 class Foo:
2 def __init__(self,name,age):
3 self.name = name
4 self.age = age
5
6 def __str__(self):
7 return "名字是%s 年龄是%s" %(self.name,self.age)
8
9 f1 = Foo("agon",18)
10 print(f1)
11
12 # --------------结果----------
13 名字是agon 年龄是18