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

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

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象

    1 class Foo(object):
    2     pass
    3  
    4 obj = Foo()
    5  
    6 isinstance(obj, Foo)
    

    ssubclass(sub, super)检查sub类是否是 super 类的派生类

    class Foo(object):
        pass
     
    class Bar(Foo):
        pass
     
    issubclass(Bar, Foo)
    

    反射

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

    四个可以实现自省的函数

    下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

    判断object中有没有一个name字符串对应的方法或属性
    hasattr(object,name)
    def getattr(object, name, default=None): # known special case of getattr
        """
        getattr(object, name[, default]) -> value
    
        Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
        When a default argument is given, it is returned when the attribute doesn't
        exist; without it, an exception is raised in that case.
        """
        pass
    
    getattr(object, name, default=None)
    getattr(object, name, default=None)
    def setattr(x, y, v): # real signature unknown; restored from __doc__
        """
        Sets the named attribute on the given object to the specified value.
    
        setattr(x, 'y', v) is equivalent to ``x.y = v''
        """
        pass
    
    setattr(x, y, v)
    setattr(x, y, v)
    def delattr(x, y): # real signature unknown; restored from __doc__
        """
        Deletes the named attribute from the given object.
    
        delattr(x, 'y') is equivalent to ``del x.y''
        """
        pass
    
    delattr(x, y)
    delattr(x, y)
    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__)
    
    四个方法的使用演示
    四个方法的使用演示
    class Foo(object):
     
        staticField = "old boy"
     
        def __init__(self):
            self.name = 'wupeiqi'
     
        def func(self):
            return 'func'
     
        @staticmethod
        def bar():
            return 'bar'
     
    print getattr(Foo, 'staticField')
    print getattr(Foo, 'func')
    print getattr(Foo, 'bar')
    
    类也是对象
    类也是对象
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import sys
    
    
    def s1():
        print 's1'
    
    
    def s2():
        print 's2'
    
    
    this_module = sys.modules[__name__]
    
    hasattr(this_module, 's1')
    getattr(this_module, 's2')
    
    反射当前模块成员
    反射当前模块成员

    导入其他模块,利用反射查找该模块是否存在某个方法

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    """
    程序目录:
        module_test.py
        index.py
     
    当前文件:
        index.py
    """
    
    import module_test as obj
    
    #obj.test()
    
    print(hasattr(obj,'test'))
    
    getattr(obj,'test')()
    module_test.py

    反射的好处

    好处一:实现可插拔机制

    有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

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

     __setattr__,__delattr__,__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
    
    三者的用法演示
    三者的用法演示

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

    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,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)
    
    二次加工标准类型(基于继承实现)
    二次加工标准类型(基于继承实现)

    授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

    实现授权的关键点就是覆盖__getattr__方法

    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()
    
     授权示范一
    例子

    __getattribute__

    class Foo:
        def __init__(self,x):
            self.x=x
    
        def __getattr__(self, item):
            print('执行的是我')
            # return self.__dict__[item]
    
    f1=Foo(10)
    print(f1.x)
    f1.xxxxxx #不存在的属性访问,触发__getattr__
    
    回顾__getattr__
    回顾
    class Foo:
        def __init__(self,x):
            self.x=x
    
        def __getattribute__(self, item):
            print('不管是否存在,我都会执行')
    
    f1=Foo(10)
    f1.x
    f1.xxxxxx
    
    __getattribute__
    __getattribute__

    描述符(__get__,__set__,__delete__)

    1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
    __get__():调用一个属性时,触发
    __set__():为一个属性赋值时,触发
    __delete__():采用del删除属性时,触发

    class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
        def __get__(self, instance, owner):
            pass
        def __set__(self, instance, value):
            pass
        def __delete__(self, instance):
            pass
    
    定义一个描述符
    定义一个描述符

    2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

    class Foo:
        def __get__(self, instance, owner):
            print('触发get')
        def __set__(self, instance, value):
            print('触发set')
        def __delete__(self, instance):
            print('触发delete')
    
    #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
    f1=Foo()
    f1.name='egon'
    f1.name
    del f1.name
    #疑问:何时,何地,会触发这三个方法的执行
    
    引子:描述符类产生的实例进行属性操作并不会触发三个方法的执行
    引子:描述符类产生的实例进行属性操作并不会触发三个方法的执行

    3 描述符分两种
    一 数据描述符:至少实现了__get__()和__set__()

    1 class Foo:
    2     def __set__(self, instance, value):
    3         print('set')
    4     def __get__(self, instance, owner):
    5         print('get')
    

    二 非数据描述符:没有实现__set__()

    1 class Foo:
    2     def __get__(self, instance, owner):
    3         print('get')
    

    4 注意事项:
    一 描述符本身应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
    1.类属性
    2.数据描述符
    3.实例属性
    4.非数据描述符
    5.找不到的属性触发__getattr__()

    __del__

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

    注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__

    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    del f1
    print('------->')
    
    #输出结果
    执行我啦
    ------->
    
    简单示范
    
    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    # del f1
    print('------->')
    
    #输出结果
    ------->
    执行我啦
    
    
    
    
    
    #为何啊???
    
    挖坑埋了你
    

    典型的应用场景:

    创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中

    当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源

    这与文件处理是一个道理:

    f=open('a.txt') #做了两件事,在用户空间拿到一个f变量,在操作系统内核空间打开一个文件
    del f #只回收用户空间的f,操作系统的文件还处于打开状态
    
    #所以我们应该在del f之前保证f.close()执行,即便是没有del,程序执行完毕也会自动del清理资源,于是文件操作的正确用法应该是
    f=open('a.txt')
    读写...
    f.close()
    很多情况下大家都容易忽略f.close,这就用到了with上下文管理
    

     __call__

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

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

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

    metaclass元类

    链接:http://www.cnblogs.com/linhaifeng/articles/8029564.html

  • 相关阅读:
    jquery之自定义data属性
    js获取显示器、页面等高度 (转)
    A网页高度随B内容而自然变化兼容各种浏览器
    DIV+ul+LI实现表格效果以及div带滑动条
    不同人对待问题不同态度
    MySQL,SqlServer数据库关键字在程序中处理
    一款连接SqlServer的数据库工具
    VB.Net日期格式化的5种使用方法
    MySQL与SqlServer中update操作同一个表问题
    SqlServer中存储过程 returnC#代码处理以及对应的MySQL如何改写
  • 原文地址:https://www.cnblogs.com/taostaryu/p/8866633.html
Copyright © 2011-2022 走看看