• 类的进阶


    一 isinstance(obj,cls)和issubclass(sub,super)

    class Foo:
        def __init__(self,name):
            self.name = name
    
    obj = Foo("egon")
    
    print(isinstance(obj,Foo))
    
    
    l = list([1,2,3])
    print(isinstance(l,list))
    
    -----------------结果-----------
    
    True
    True
    isinstance(obj,cls)检查是否obj是否是类 cls 的对象
    class Foo:
        pass
    
    class Bar(Foo):
        pass
    
    print(issubclass(Bar,Foo))
    
    ------------------------结果----------
    True
    issubclass(sub, super)检查sub类是否是 super 类的派生类

    二.反射

    # 反射类中的名字
    getattr(类名,'静态属性')
    getattr(类名,'类方法')()
    getattr(类名,'静态方法')()
    
    # 反射对象中的名字
    getattr(对象名,'对象属性')
    getattr(对象名,'方法名')()
    
    # 反射模块中的名字
    import 模块名
    getattr(模块名,'模块中的变量')
    getattr(模块名,'模块中的函数')()
    getattr(模块名,'模块中的类名')
    
    # 反射当前模块中的名字
    import sys
    getattr(sys.modules[__name__],'变量')
    getattr(sys.modules[__name__],'函数')()
    getattr(sys.modules[__name__],'类名')

      1.python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

    class People:
        country = "china"
        def __init__(self,name):
            self.name = name
    
    
    p = People("egon")
    print(p.__dict__)
    #-------------------------
    print(hasattr(p,"name"))
    print("name" in p.__dict__)
    print(hasattr(People,"country"))
    
    ----------------------------------
    {'name': 'egon'}
    True
    True
    True
    hasattr(object,name)
    class People:
        country = "china"
        def __init__(self,name):
            self.name = name
    
        def walk(self):
            print("%s is working" % self.name)
    
    p = People("egon")
    
    print(getattr(p,"country"))     #print(p.country)
        # china
    print(getattr(p,"walk"))        #print(p.walk)
        #<bound method People.walk of <__main__.People object at 0x101979278>>
    getattr(object, name, default=None)
    class People:
        country = "china"
        def __init__(self,name):
            self.name = name
    
        def walk(self):
            print("%s is working" % self.name)
    
    p = People("egon")
    
    setattr(p,"age",15)
    print(p.__dict__)
        {'age': 15, 'name': 'egon'}
    setattr(x, y, v)
    class People:
        country = "china"
        def __init__(self,name):
            self.name = name
    
        def walk(self):
            print("%s is working" % self.name)
    
    p = People("egon")
    
    print(p.__dict__)
        {'name': 'egon'}
    delattr(p,"name")
    print(p.__dict__)
        {}
    delattr(x, y)
    import sys
    def add():
        print("add")
    
    def delete():
        print("delete")
    
    def update():
        print("update")
    
    def search():
        print("search")
    
    this_module = sys.modules[__name__]
    while True:
        cmd = input("please input: ")
        if not cmd:continue
        if hasattr(this_module,cmd):
            func = getattr(this_module,cmd)
            func()
    sys.modules[__name__]

      2.反射的好处 

      好处一:实现可插拔机制

      有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,

          lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

      总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?

          即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能 

    #Ftpclent.py 文件
    
    class FtpClient:
        'ftp客户端,但是还么有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器 %s ' %addr)
            self.addr=addr
    
        def get(self):
            print("get")
    
    
    #Ftpserver.py  文件
    
    from day32 import FtpClient
    
    obj =  FtpClient.FtpClient('192.168.1.1')
    
    if hasattr(obj,"get"):
        func = getattr(obj,"get")
        func()
    
    print("other func")
    FTP 代码

       好处二:动态导入模块(基于反射当前模块成员)

    #导入字符串
    __import__("time")
    
    #使用模块
    import importlib
    t = importlib.import_module("time")
    print(t.time())
        1493026292.217129
    

    三.__setattr__,__delattr__,__getattr__

    #初始化和赋值时触发__setattr__运行
    
    
    #发现__dict__没有name 和 age
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setattr__(self, key, value):
            print("__setattr__  key:%s value:%s"%(key,value))
    
    obj = Foo("egon")
         __setattr__  key:name value:egon
    obj.age = 18
         __setattr__  key:age value:18
    print(obj.__dict__)           #发现__dict__没有name 和 age
         {}
    
    
    #初始化和赋值都在__dict__中找到
    
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setattr__(self, key, value):
            print("__setattr__  key:%s value:%s"%(key,value))
            self.__dict__[key] = value
    
    obj = Foo("egon")
        __setattr__  key:name value:egon
    obj.age = 15
        __setattr__  key:age value:15
    print(obj.__dict__)
        {'name': 'egon', 'age': 15}
    
    
    
    #初始化赋值时判断如果不是数字不可以赋值
    
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setattr__(self, key, value):
            if not isinstance(value,int):
                raise TypeError("type error")
            self.__dict__[key] = value
    
    obj = Foo(15)
    obj.age = 15
    print(obj.__dict__)
        {'age': 15, 'name': 15}
    __setattr__
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setattr__(self, key, value):
            self.__dict__[key] = value
    
        def __delattr__(self, item):
            self.__dict__.pop(item)
    obj = Foo("egon")
    
    print(obj.__dict__)
        {'name': 'egon'}
    del obj.name
    print(obj.__dict__)
        {}
    __delattr__ 
    #属性不存在时候运行
    
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):
            print("__getattr__  %s" % item)
    
    obj = Foo("egon")
    print(obj.name)
        egon
    print(obj.xxx)
        __getattr__  xxx
        None 
    __getattr__

    四. 二次加工标准类型(包装)

    包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工) 

    #自定义自己的数据类型,追加和插入,如果不是数字,报错
    
    class List(list):
        def append(self, p_object):
            if not isinstance(p_object,int):
                raise TypeError("Type error")
            super().append(p_object)
    
        def insert(self, index, p_object):
            if not  isinstance(p_object,int):
                raise TypeError("Type error")
            super().insert(index,p_object)
    
    l = List([1,2,3])
    print(l)
        [1, 2, 3]
    l.append("4")   #不能追加字符串
    
    l.insert(0,-1)
    print(l)
        [-1, 1, 2, 3]
    自定义数据类型
    import time
    
    class Open:
        def __init__(self,filepath,mode="r",encode="utf-8"):
            self.x = open(filepath,mode=mode,encoding=encode)
            self.filepath = filepath
            self.mode = mode
            self.encoding = encode
    
        def write(self,value):
            log_time = time.strftime('%Y-%m-%d %X')
            self.x.write("%s %s" % (log_time,value))
    
        def __getattr__(self, item):
            return getattr(self.x,item)
    
    f = Open("b.txt","a+")
    f.write("11111111
    ")
    f.seek(0)
    print(f.read())
    授权
    #基于继承来定制自己的数据类型
    class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
        def append(self, p_object):
            ' 派生自己的append:加上类型检查'
            if not isinstance(p_object,int):
                raise TypeError('must be int')
            super().append(p_object)
    
        @property
        def mid(self):
            '新增自己的属性'
            index=len(self)//2
            return self[index]
    
    
    l=List([1,2,3])
    print(l.mid)
    
    
    
    基于授权来定制自己的数据类型:
    
    class Open:
        def __init__(self,filepath,mode,encode='utf-8'):
            self.f=open(filepath,mode=mode,encoding=encode)
            self.filepath=filepath
            self.mode=mode
            self.encoding=encode
    
        def write(self,line):
            print('write')
            self.f.write(line)
    
        def __getattr__(self, item):
            return getattr(self.f,item)
    
    
    f=Open('a.txt','w')
    f.write('123123123123123
    ')
    print(f.seek)
    f.close()
    授权 继承 数据类型

    五.反射作业

    1.基于授权定制自己的列表类型,要求定制的自己的__init__方法,
    2.定制自己的append:只能向列表加入字符串类型的值
    3.定制显示列表中间那个值的属性(提示:property)
    4.其余方法都使用list默认的(提示:__getattr__加反射)
    
    class List:
        def __init__(self,x):
            self.seq=list(x)
    
        def append(self,value):
            if not isinstance(value,str):
                raise TypeError('must be str')
            self.seq.append(value)
        @property
        def mid(self):
            index=len(self.seq)//2
            return self.seq[index]
        def __getattr__(self, item):
            return getattr(self.seq,item)
    
        def __str__(self):
            print("111")
            return str(self.seq)
    
    l=List([1,2,3])
    
    l.append('1')
    
    print(l.mid)
    
    l.insert(0,123)
    View Code

    六.__setitem__,__getitem,__delitem__

    #把对象操作属性模拟成字典的格式
    
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getitem__(self, item):
            return self.__dict__[item]
        def __setitem__(self, key, value):
            self.__dict__[key] = value
        def __delitem__(self, item):
            self.__dict__.pop(item)
    
    
    f = Foo("egon")
    print(f.name)
        egon
    f.name = "egonlin"
    print(f.__dict__)
        {'name': 'egonlin'}
    
    f["age"] = 18
    print(f.__dict__)
        {'name': 'egon', 'age': 18}
    
    del f["name"]
    print(f.__dict__)
        {}
    把对象操作属性模拟成字典的格式

    七.__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__实现迭代器协议

    class Foo:
        def __init__(self, end,start=0):
            self.start = start
            self.end = end
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.start >= self.end:
                raise StopIteration
            n = self.start
            self.start+=1
            return n
    
    f = Foo(10)
    for i in f:
        print(i)
    rangge(10)
    class Range:
        def __init__(self,start,stop):
            self.start = start
            self.stop = stop
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if  self.start >= self.stop:
                raise StopIteration("StopIteration Error")
            n = self.start
            self.start += 1
            return n
    
    obj = Range(0,15)
    
    for i in obj:
        print(i)
    Range(1,15)
    class Range:
        def __init__(self, *args):
            self.args = args
            if len(self.args) == 2:
                self.start = self.args[0]
                self.end = self.args[1]
            else:
                self.start = 0
                self.end = self.args[0]
        def __iter__(self):
            return self
    
        def __next__(self):
            n = self.start
            if n < self.end:
                n = self.start
                self.start += 1
                return n
            raise StopIteration
    
    
    for i in Range(1,10):
        print(i)
    
    for i in Range(10):
        print(i)
    range(10) range(1,15)
    class Fib:
        def __init__(self):
            self._a=0
            self._b=1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            self._a,self._b=self._b,self._a + self._b
            return self._a
    
    f1=Fib()
    
    print(f1.__next__())
    print(next(f1))
    print(next(f1))
    
    for i in f1:
        if i > 100:
            break
        print('%s ' %i,end='')
    斐波那契数列

    九.__del__

    析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    del f1
    print('------->')
    --------------------结果-------------
    
    执行我啦
    ------->
    销毁--->执行完
    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    print('------->')
    --------------------结果-------------
    
    ------->
    执行我啦
    执行完--->销毁

    十.__enter__和__exit__

    with open('a.txt') as f:
       '代码块'
     
    上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
     
    class Open:
        def __init__(self,name):
            self.name=name
     
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
            # return self
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
     
     
    with Open('a.txt') as f:
        print('=====>执行代码块')
         
    -----------------结果----------------
     
    出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
    =====>执行代码块
    with中代码块执行完毕时执行我啊
    说明
    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            print(exc_type)
            print(exc_val)
            print(exc_tb)
    
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100) #------------------------------->不会执行
    __exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            print(exc_type)
            print(exc_val)
            print(exc_tb)
            return True
    
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100) #------------------------------->会执行
    如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
    import time
    
    class Open:
        def __init__(self,filepath,mode="r",encode="utf-8"):
            self.x = open(filepath,mode=mode,encoding=encode)
            self.filepath = filepath
            self.mode = mode
            self.encoding = encode
    
        def __enter__(self):
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.x.close()
            return True
    
        def write(self,value):
            log_time = time.strftime('%Y-%m-%d %X')
            self.x.write("%s %s" % (log_time,value))
    
        def __getattr__(self, item):
            return getattr(self.x,item)
    
    
    with Open("b.txt","a+") as f :    #obj = Open().__enter__() ---> obj = f
        f.write("11111111
    ")
    Open类 with打开

    十一.__call__

    对象后面加括号,触发执行。

    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    class Foo:
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('__call__')
    
    
    obj = Foo()  # 执行 __init__
    obj()  # 执行 __call__
        __call__
    

    十二.__str__

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return "名字是%s 年龄是%s" %(self.name,self.age)
    
    f1 = Foo("agon",18)
    print(f1)
    
    # --------------结果----------
    名字是agon 年龄是18
    __str__ 打印时候触发

    十三.__new__

     __new__ 单例

    十四. 创建类

    1. 类在创建的时候执行type的__init__方法  类相当于type的对象
    2. 类() = type对象() 相当于实例化 执行type的__call__方法
    3. type的__call__方法会调用
        - 调用类的__new__方法 用于创建对象
        - 调用类的__init__方法 用于初始化
    4. 对象() 执行类的__call__方法
    -------------------------------(一)-------------------------------
    
    class SingletonType(type):
    
        def __init__(self,*args,**kwargs):
            super(SingletonType,self).__init__(*args,**kwargs)
    
    
    
    class Foo(metaclass=SingletonType):
        pass
    
    
    类默认是由type创建也可以指定metaclass创建 在父类构造方法继续让type执行 相当于没做什么操作
    对象是由类创建的
    
    -------------------------------(二)-------------------------------
    
    class SingletonType(type):
    
        def __init__(self,*args,**kwargs):
            print(self)
            super(SingletonType,self).__init__(*args,**kwargs)
    
    
    
    class Foo(metaclass=SingletonType):
        pass
    
    
    此时在父类里面打印print(self) 发现结果为<class '__main__.Foo'>
    
    对象是类创建 创建对象时候类的__init__方法自动执行
    类是type创建 创建类时候type的__init__方法自动执行
    
    
    -------------------------------(三)-------------------------------
    
    
    对象() 执行类的__call__方法
    类() 执行type的__call__方法 执行__call__方法内部会调用(类的__new__方法和__init__方法)
    
    
    class SingletonType(type):
    
        def __init__(self,*args,**kwargs):
            print(self)
            super(SingletonType,self).__init__(*args,**kwargs)
    
        def __call__(cls, *args, **kwargs): # cls 表示 SingletonType类
            obj = cls.__new__(cls, *args, **kwargs)                # obj 为创建的对象
    
    
    class Foo(metaclass=SingletonType):
    
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls, *args, **kwargs)
    
    
    -------------------------------(四)-------------------------------
    
    
    
    class SingletonType(type):
    
        def __init__(self,*args,**kwargs):
            print(self)
            super(SingletonType,self).__init__(*args,**kwargs)
    
        def __call__(cls, *args, **kwargs):    # cls 表示 SingletonType类
            obj = cls.__new__(cls, *args, **kwargs)
    
            cls.__init__(obj,*args, **kwargs)  # 实例化 底下两者效果相同
            #obj.__init__(*args, **kwargs)
            return obj
    
    class Foo(metaclass=SingletonType):
    
        def __init__(self):
            pass
    
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls, *args, **kwargs)
    
    
    obj = Foo()
    创建类 对象 流程
    元类是用来如何创建类的 正如类是创建对象的模版一样
    
    元类的实例是类  正如类的实例为对象
    
    一个类如果没有声明自己的元类,默认他的元类就是type, 也可以通过继承type来自定义元类
    
    
    def __init__(self,name,age):
        pass
    
    obj = type('foo',(object,),{'x':1,'__init__':__init__})
        #参数一: 类名
        #参数二: 继承类
        #参数三: 类的属性 方法
    
    
    type 实例化结果就是一个类
    View Code
  • 相关阅读:
    Ubuntu上安装Redis
    Unity Shader中将指定颜色过滤成透明
    用Python发送邮件
    Flask搭建简单的服务器
    SQLServer 中All、Any和Some用法与区别
    Linux探秘之用户态与内核态
    MTDDL 美团点评分布式数据访问层中间件
    基础数据结构 例:栈、队列、链表、数据、字典、树、等
    二叉树、红黑树、B&B+树数据结构
    CPU,GPU,高速缓存cache,内存RAM,虚拟内存VM,磁盘ROM,磁盘缓存之间的关系
  • 原文地址:https://www.cnblogs.com/golangav/p/6752412.html
Copyright © 2020-2023  润新知