zoukankan      html  css  js  c++  java
  • 面向对象进阶

    isinstance(obj,cls) 检查obj是否是cls的实例

    issubclass(obj,cls) 检查obj是否是cls的继承类

    反射

    通过字符串的形式操作对象的相关的属性。

    主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)

    hasattr(obj,name) 检查obj下是否有叫name属性,name必须字符串
    
    getattr(obj,name,default=None)  查询obj下的属性,有返回name对应的参数,没有返回default
    
    setattr(obj,x,y)  给obj设置属性,x必须字符串
    
    delattr(obj,x)    删除obj下的属性,x必须字符串
    

    示例:

    class BlackMedium:
        feature='Ugly'
        def __init__(self,name,addr):
            self.name=name
            self.addr=addr
    
        def sell_house(self):
            print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
        def rent_house(self):
            print('%s 黑中介租房子啦,傻逼才租呢' %self.name)
    
    b1=BlackMedium('万成置地','回龙观天露园')
    
    #检测是否含有某属性
    print(hasattr(b1,'name'))
    print(hasattr(b1,'sell_house'))
    
    #获取属性
    n=getattr(b1,'name')
    print(n)
    func=getattr(b1,'rent_house')
    func()
    
    # getattr(b1,'aaaaaaaa') #报错
    print(getattr(b1,'aaaaaaaa','不存在啊'))
    
    #设置属性
    setattr(b1,'sb',True)
    setattr(b1,'show_name',lambda self:self.name+'sb')
    print(b1.__dict__)
    print(b1.show_name(b1))
    
    #删除属性
    delattr(b1,'addr')
    delattr(b1,'show_name')
    delattr(b1,'show_name111')#不存在,则报错
    
    print(b1.__dict__)
    

    反射的好处

    好处一:实现可插拔机制

    有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,
    但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,
    等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
    
    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,
    这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
    

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

    在模块中导入自己:
    
    	this_modul=sys.modules[__name__]
    
    
    使用字符串导入模块:
    
    	1、__import__("time")
    
    	2、import importlib
    	
    		importlib.import_module("time")
    
    	推荐使用第二种
    

    setattr,getattr,delattr 操作属性,在类中的用法和意义

    setattr

    设置属性的时候会触发。实质是操作类.__dict__
    

    delattr

    删除类的属性时会触发,实质是操作类.__dict__
    

    getattr

    调用类中不存在的属性时会触发。
    

    三者的用法演示:

    class Foo:
        x=1
        def __init__(self,y):
            self.y=y
    
        def __getattr__(self, item):
            print('----> from getattr:你找的属性不存在')
    
    
        def __setattr__(self, key, value):
            print('----> from setattr')
            # self.key=value #这就无限递归了,你好好想想
            # self.__dict__[key]=value #应该使用它
    
        def __delattr__(self, item):
            print('----> from delattr')
            # del self.item #无限递归了
            self.__dict__.pop(item)
    
    #__setattr__添加/修改属性会触发它的执行
    f1=Foo(10)
    print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f1.z=3
    print(f1.__dict__)
    
    #__delattr__删除属性的时候会触发
    f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.__dict__)
    
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    f1.xxxxxx
    

    setitem,getitem,__delitem__的使用方法

    作用同上。只不过是调用的时候__setattr__那中方法是用 . 去调用。而这种是用["值"]的方式去调用。

    class Foo:
        x = 1
    
        def __init__(self, y):
            self.y = y
    
        def __getitem__(self, item):   #执行对象[属性],找不到属性的时候会执行这个代码。
            print('----> from getattr:你找的属性不存在')
    
        def __setitem__(self, key, value):  #执行对象[属性]=值,的时候会执行这个代码
            self.__dict__[key]=value
     
        def __delitem__(self, item):        #执行 del 对象[属性] 的时候会执行这个代码。
            self.__dict__.pop(item)
    
    f1 = Foo(10)   #初始化触发init
    print(f1.__dict__)
    
    f1["z"]=3      #赋值触发setitem
    print(f1.__dict__)
    
    f1["a"]        #查找不存在的属性,触发getitem
    
    f1.__dict__['a'] = 3
    del f1["a"]      #删除触发delitem
    print(f1.__dict__)
    

    定制自己的数据类型:二次加工标准类型

    基于类继承实现

    class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
        def append(self, p_object):
            
            if not isinstance(p_object,int):  #' 派生自己的append:加上类型检查'
                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,4])
    print(l)
    l.append(5)
    print(l)
    # l.append('1111111') #报错,必须为int类型
    
    print(l.mid)
    
    #其余的方法都继承list的
    l.insert(0,-123)
    print(l)
    l.clear()
    print(l)
    

    授权的方式

    import time
    class FileHandle:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            self.file=open(filename,mode,encoding=encoding)
        def write(self,line):
            t=time.strftime('%Y-%m-%d %T')
            self.file.write('%s %s' %(t,line))
    
        def __getattr__(self, item):
            return getattr(self.file,item)
    
    f1=FileHandle('b.txt','w+')
    f1.write('你好啊')
    f1.seek(0)
    print(f1.read())
    f1.close()
    
    
    #重写list
    class List:
        def __init__(self,seq):
            self.seq=seq
    
        def append(self, p_object):
            ' 派生自己的append加上类型检查,覆盖原有的append'
            if not isinstance(p_object,int):
                raise TypeError('must be int')
            self.seq.append(p_object)
    
    	def clear(self):
            if not self.permission:
                raise PermissionError('not allow the operation')
            self.seq.clear()	
    
        @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):
            return str(self.seq)
    
    l=List([1,2,3])
    print(l)
    l.append(4)
    print(l)
    # l.append('3333333') #报错,必须为int类型
    
    print(l.mid)
    
    #基于授权,获得insert方法
    l.insert(0,-123)
    print(l)
    

    自定制格式化字符串__format__

    date_dic={
        'ymd':'{0.year}:{0.month}:{0.day}',
        'dmy':'{0.day}/{0.month}/{0.year}',
        'mdy':'{0.month}-{0.day}-{0.year}',
    }
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
    
        def __format__(self, format_spec):
            if not format_spec or format_spec not in date_dic: 如果输入的为空或者输入的格式不在规定的字典中,赋予默认格式
    
                format_spec='ymd'
    
            fmt=date_dic[format_spec]
            return fmt.format(self)
    
    
    d1=Date(2016,12,29)
    print(format(d1))           #默认输出模式
    print('{:mdy1}'.format(d1)) #没有mdy1这个模式。所以默认ymd模式输出
    
    
    print('{:mdy}'.format(d1))  #mdy输出模式
    
    
    print(format(d1,"dmy"))     #dmy输出模式
    print("{:dmy}".format(d1))  #dmy输出模式,同上
    

    __next__和__iter__实现迭代器协议

    from collections import Iterable(可迭代对象),Iterator(迭代器)
    
    class Foo:
        def __init__(self,start=0,stop=0):
            self.start=start
            self.stop=stop
            self.con=0
    
    
        def __iter__(self):
            return self
    
    
        def __next__(self):
            if self.con >= self.start and self.start >=self.stop :
                raise StopIteration
            if self.stop==0:
                if self.con < self.start:
                    n = self.con
                    self.con += 1
                    return n
            else:
                self.con=self.stop
                n=self.start
                self.start+=1
                return n
    
    f=Foo(1,6)
    print(isinstance(f,Iterator))	 #判断f是否是迭代器
    
    for i in Foo(1,6):
        print(i)
    
    for i in Foo(6):
        print(i)
    

    doc

    class Foo:
    	'我是描述信息'
    	pass
    
    print(Foo.__doc__)
    
    输出:'我是描述信息'
    

    这个属性无法被继承

    enter__和__exit

    class Open:
        def __init__(self,name,mode="w"):
            self.x=open(name,mode=mode)
            self.name=name
            self.mode=mode
    
        def __enter__(self): #出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):  #with中代码块执行完毕后执行
            print("exc_type",exc_type)                  #捕获异常。获取异常的各个信息。
            print("exc_val",exc_val)
            print("exc_tb",exc_tb)
            return True
    
    
    
        def write(self,value):
            self.x.write(value)
    
        def __getattr__(self, item):
            return getattr(self.x,item)
    
    # a=Open("a.txt","r")
    # print(a.read())
    # a.seek(0)
    # print(a.read())
    
    with Open("a.txt","r") as f:
        print(f.read())
        raise TypeError("error!")
    
    print("-------------------------")
    

    call

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

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

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

    元类:

    什么是元类?

    元类是类的类,是类的模板

    元类是用来控制如何创建类的,正如类是创建对象的模板一样

    type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象

    创建类的两种方法

    方式一:

    1 class Foo:
    2     def func(self):
    3         print('from func')
    

    方式二:

    1 def func(self):
    2         print('from func')
    3 x=1
    4 Foo=type('Foo',(object,),{'func':func,'x':1})
    

    一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类

    自定制元类

    class B(type):
        def __init__(self,name,bases=None,dict=None):
            print("init B")
            self.name=name
    
        def __call__(self, *args, **kwargs):
            print("call")
            obj=self.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj
    
    class A(object,metaclass=B):
        def __init__(self,name):
            print("init A")
            self.name=name
    
        def __new__(cls, *args, **kwargs):
            print("new A")
            return super().__new__(cls)
    
    a=A("name1")
    print(a.__dict__)
    

    精简版

    class Mytype(type):
    
        def __init__(self,what,bases=None,dict=None):
            print(what,bases,dict)
    
        def __call__(self, *args, **kwargs):
            print('--->')
            obj=object.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj
    
    
    class Room(metaclass=Mytype):
    
        def __init__(self,name):
            self.name=name
    
    r1=Room('alex')
    print(r1.__dict__)
    

    总结

    元类总结

    class Mymeta(type):
        def __init__(self,name,bases,dic):
            print('===>Mymeta.__init__')
    
    
        def __new__(cls, *args, **kwargs):
            print('===>Mymeta.__new__')
            return type.__new__(cls,*args,**kwargs)
    
        def __call__(self, *args, **kwargs):
            print('aaa')
            obj=self.__new__(self)
            self.__init__(self,*args,**kwargs)
            return obj
    
    class Foo(object,metaclass=Mymeta):
        def __init__(self,name):
            self.name=name
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls)
    
    '''
    需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__
    
    而爹.__call__一般做两件事:
    1.调用name.__new__方法并返回一个对象
    2.进而调用name.__init__方法对儿子name进行初始化
    '''
    
    '''
    class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
    Foo=Mymeta('foo',(...),{...})
    因此我们可以看到,只定义class就会有如下执行效果
    ===>Mymeta.__new__
    ===>Mymeta.__init__
    实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
    遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
    于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
    '''
    
    '''
    obj=Foo('egon')
    的原理同上
    '''
    
    '''
    总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
    1.谁后面跟括号,就从谁的爹中找__call__方法执行
    type->Mymeta->Foo->obj
    Mymeta()触发type.__call__
    Foo()触发Mymeta.__call__
    obj()触发Foo.__call__
    2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
    '''
  • 相关阅读:
    【转】UCenter的MVC架构
    最新的windows xp sp3序列号(绝对可通过正版验证)
    马丁催眠的花园
    【转】UCenter 的 daddslashes详解
    ckEditor与ckFinder的集成
    【转】UCenter代码研究第一篇(ROOT/admin.php)
    MVC学习第三节:Controller与View
    MVC学习第二节:UrlRouting
    MVC 学习第十节 请求Controller
    MVC学习第九节 HtmlHelper
  • 原文地址:https://www.cnblogs.com/G-YUE/p/6757636.html
Copyright © 2011-2022 走看看