zoukankan      html  css  js  c++  java
  • 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
    ")  #已经把内容写入进a.txt了
    15 a.write("2222222222
    ")
    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
    ")
    26     f.write("111111111
    ")
    27     f.write("111111111
    ")
    28     f.write("111111111
    ")
    29     f.write("111111111
    ")

    六,__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__)
  • 相关阅读:
    @Profile使用及SpringBoot获取profile值
    浅谈maven中的scope,systempath
    Maven Filter与Profile隔离生产环境与开发环境
    spring的@Value注解使用
    maven项目引入spring boot依赖之后filter不生效的问题
    SpringBoot整合Servlet的两种方式
    程序员,30岁,“理所应当”就该中年危机了吗?
    Spring Boot 2 Webflux的全局异常处理
    正经学C#_表达式与其运算符[赋值运算符]:《c#入门经典》
    正经学C#_表达式与其运算符[算术运算符]:《c#入门经典》
  • 原文地址:https://www.cnblogs.com/gaoyuan111/p/6762869.html
Copyright © 2011-2022 走看看