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__)

 

posted @ 2017-04-25 17:16  九级大狂风  阅读(210)  评论(0编辑  收藏  举报