python基础--------面向对象进阶
一,__getitem__ ,__setitem__ , __delitem__
1 # 把对象操作属性的,模拟成字典的格式
2 class Foo:
3 def __init__(self,name):
4 self.name =name
5 def __getitem__(self, item):
6 print(self.__dict__[item])
7
8 def __setitem__(self, key, value):
9 print("修改增加的时候,才会触发我")
10 self.__dict__[key]= value
11 def __delitem__(self, key):
12 print("删除的时候,才会触发我")
13 self.__dict__.pop(key)
14 f = Foo("egon")
15 f["age"] = 12 #修改,增加的时候 才会触发__srtitem__
16 print(f.__dict__) #{'name': 'egon', 'age': 12}
17 #del f["name"] # 模拟字典的key ,字典的key是str类型
18 print(f.__dict__)
19 print(f["name"]) #触发 __getitem__ ,获取dict中“name”的value, 没有就会报错
20 print(f["sex"]) # 报错:KeyError: 'sex'
二,__slots__
1,__slots__是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性),
2,把类内部的所有属性,统一管理起来,不会产生新的名称空间,也就是新的dict,实例化一个对象,就会相对应的产生一个对象的名称空间,使用__slots__,只有一个名称空间,即__slote__[],或()或{}这里面的
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
1 class People:
2 __slots__ = ["x","y","z"] #以列表为例
3 p = People()
4 print(People.__dict__) #整个类 只有类有字典
5 p.x = 1
6 p.y = 2
7 p.z = 3
8 p.a = 5 ##报错AttributeError: 'People' object has no attribute 'name'意思就是在字典里找不到a这个key
9
10 #print(p.__dict__) #报错,对象没有dict了
11 p1 = People()
12 p1.z =10
13 p1.x = 20
14 p1.y = 30
15 print(p1.z,p1.x,p1.y)
16 print(People.__dict__)
三,实现迭代器协议:
1.
1 class Foo:
2 def __init__(self,start):
3 self.start = start
4 def __iter__(self):
5 return self
6 def __next__(self):
7 if self.start>10:
8 raise StopIteration("超出范围") #主动抛出异常
9 n = self.start
10 self.start+=1
11 return n
12 f= Foo(1)
13 print(next(f)) #一次一次的next取值,直到所有的值全被取完,next到11的时候,因为没有值可以取了
14 print(next(f)) # 就主动抛出 raise StopIteration("超出范围")
15 print(next(f))
16 print(next(f))
17 print(next(f))
18 print(next(f))
19 print(next(f))
20 print(next(f))
21 print(next(f))
22 print(next(f))
23 print(next(f)) #用这种方法很搂,跟简单的就是for循环,他帮我们把__iter__和__next__全部做好了
24 for i in f:
25 print(i)
2,模拟range函数,1到10,跟上面的差不多,定义一个截止的参数就行了
1 #模拟range函数,1到10
2 class Range:
3 def __init__(self,start,end):
4 self.start = start
5 self.end = end
6 def __iter__(self):
7 return self
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 f = Range(1,10)
15 for i in f: #其实for循环本身就自带控制技能,遍历完最大数,即结束
16 print(i)
四,__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
1 class Open:
2 def __init__(self,filepath,mode="r",encode="utf-8"):
3 self.f = open(filepath,mode=mode,encoding=encode)
4 def write(self,value):
5 self.f.write(value)
6
7 def __getattr__(self, item):
8 return getattr(self.f,item)
9 def __del__(self):
10 print(".....处罚我")
11 self.f.close() #关闭文件
12 a = Open("a.txt","w") #实例化的 传完值自动触发__del__运行
13
14 a.write("1111111111\n") #已经把内容写入进a.txt了
15 a.write("2222222222\n")
16 #a.txt中内容:
1111111111
2222222222
2222222222
五,上下文管理协议:__enter__ 和 __exit__
1操作文件有两种写法
1 f = open("a.txt","r")
2 f.read()
3 f.close() #关闭文件
2,前者需要自己关闭文件,下面这种with语句,自动在你处理完文件时关闭
1 with open("a.txt","r") as f:
2 f.read()
3
4
5 #自动在后台偷偷的关闭文件了
3,with语句 又称上下文管理协议with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
1 import time
2
3 class Open:
4 def __init__(self,filepath,m="r",endcode="utf8"):
5 self.x = open(filepath,mode=m,encoding = endcode)
6
7 self.filepath = filepath
8 self.m = m
9 self.encoding = endcode
10
11 def write(self,line):
12 t = time.strftime("%Y-%m-%d %X") #年月日格式,当前时间
13 self.x.write("%s %s"%(t,line)) #把字符串和时间 写入self.x中
14
15 def __getattr__(self, item): #
16 return getattr(self.x,item)
17
18 def __enter__(self): #看这里
19 return self
20
21 def __exit__(self, exc_type, exc_val, exc_tb): #看这里
22 self.x.close()
23
24 with Open("b.txt","w") as f:
25 f.write("111111111\n")
26 f.write("111111111\n")
27 f.write("111111111\n")
28 f.write("111111111\n")
29 f.write("111111111\n")
六,__call__
1 # 对象后面加括号,触发执行。 2 # 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ; 3 # 而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()() 4 class Foo: 5 def __init__(self): 6 pass 7 def __call__(self, *args, **kwargs): 8 print("执行我") 9 10 a = Foo() # 执行__init__方法 11 a() # 对象() 执行__call__ #执行结果: 执行我
七,元类:
python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例)
下例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?
1 class Foo: #这是通过关键字class 创建类
2 pass
3
4 f1 = Foo() #f1是Foo类实例化的对象
5 # type函数可以查看类型,也可以用来查看对象的类,二者是一样的
6 print(type(Foo)) #<class 'type'>
7 print(type(f1)) #<class '__main__.Foo'> f1是Foo实例化的对象
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样
元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
1,创建类的两种方式
方式一:
1 #方式1,关键字class
2 class Bar:
3 x = 1
4 def __init__(self,name):
5 self.name = name
6 def run(self):
7 pass
8 f = Bar("a")
9 print(Bar.__dict__)
10 #类名称空间的字典
11 #{'__module__': '__main__', 'x': 1, '__init__': <function Bar.__init__ at 0x00000000021EAA60>,
12 # 'run': <function Bar.run at 0x00000000021EAAE8>,
13 # '__dict__': <attribute '__dict__' of 'Bar' objects>, '__weakref__': <attribute '__weakref__'
14 # of 'Bar' objects>, '__doc__': None}
方式二:
1 #type称为元类,是所有类的类,利用type模拟class关键字的创建类的过程
2 #
3 def run(self):
4 pass
5 class_name = "Bar" # 模拟类名
6 bases = (object,) #继承类
7 class_dict={"x":1,"name":"a","run":run} #类的名称空间的字典
8 Bar = type(class_name,bases,class_dict) #创建类 必须有,类名,继承类,类名称空间的字典,缺一不可
9 print(Bar) #<class '__main__.Bar'>
10 print(Bar.__dict__)
11 # 类的名称空间
11 #{'x': 1, 'name': 'a', 'run': <function run at 0x00000000026EA950>,
12 # '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Bar' objects>,
13 # '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None}
2,用元类,限制子类必须写__doc__
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dict):
type.__init__(self,class_name,class_bases,class_dict)
for key in class_dict:
if not callable(class_dict[key]):
continue
if not class_dict[key].__doc__:
raise TypeError("你没写注释,抓紧去写")
class Foo(metaclass=Mymeta):
x = 1
def run(self):
'''run方法'''
print("running")
# f = Foo()
print(Foo.__dict__)