zoukankan      html  css  js  c++  java
  • 17 Apr 18 内置函数(isinstance,issubclass)反射 __str__ __del__ __call__ 元类 单例

    17 Apr 18
    一、内置函数补充 (isinstance 和 issubclass)
    class Foo:
        pass
     
    obj=Foo()
     
    print(type(obj) is Foo)   #用type可以完成但这不是type的主要用途,顾不推荐
    print(isinstance(obj,Foo)) # 推荐使用该函数来判断一个函数的类型
    print(isinstance('abc',str)) # ‘abc’是否是类str的一个对象/函数
    print(isinstance(123,int))
     
    print(issubclass(Foo,object))   #Foo是否是object的子类
     
    一、反射
    通过字符串来操作类与对象的属性,这种操作称为反射;反射也是内置函数
    下述四个函数是专门用来操作类与对象属性的
    class People:
        country="China"
        def __init__(self,name):
            self.name=name
        def tell(self):
            print('%s is aaa' %self.name)
     
    obj=People('egon')
     
    1、hasattr
    print(hasattr(People,'country')) #可用来操纵类 # print('country' in People.__dict__)
    print(hasattr(obj,'name'))     #可用来操纵对象
    print(hasattr(obj,'country'))
    print(hasattr(obj,'tell'))
     
    2、getattr
    print(getattr(People,'country1',None))  #如果没有返回None;若不写,没有报错
    f=getattr(obj,'tell',None)              #obj.tell
    f()                               #obj.tell()
     
    3、setattr
    setattr(People,'x',111)   #People.x=111
    print(People.x)
    setattr(obj,"age",18)     #obj.age=18
    print(obj.__dict__)
     
    4、delattr
    delattr(People,"country")   #del People.country
    print(People.__dict__)
    delattr(obj,"name")           #del obj.name
    print(obj.__dict__)
     
    #用户用input输入了字符串形式的指令,可以被反射以操纵类和对象的属性
    class Foo:
        def run(self):
            while True:
                cmd=input('cmd>>: ').strip()
                if hasattr(self,cmd):
                    func=getattr(self,cmd)
                    func()
     
        def download(self):
            print('download....')
     
        def upload(self):
            print('upload...')
     
    obj=Foo()
    obj.run()
     
    三、__str__方法
    __xxx__是满足一定条件时自动触发
    __str__ 当打印对象时自动触发,可用来定制打印格式
    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
     
        def __str__(self):
            return '<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex)
     
    obj=People('egon',18,'male')
    print(obj) #print(obj.__str__()),若没有__str__,返回一个内存地址(原生状态)
     
    l=list([1,2,3])
    print(l)   #[1, 2, 3], python帮忙优化的,否则返回一个内存地址
     
    四、__del__方法
    __del__在删除对象时自动触发
    import time
    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
     
        def __del__(self): #在对象被删除的条件下,自动执行
            print('__del__')
     
    obj=People('egon',18,'male')
    del obj #obj.__del__()  #若没有这一行,睡2s后会自动触发__del__,因为程序结束前会删除对象(清除资源)
    time.sleep(2)
     
    __del__的主要用途是回收系统资源
    class Mysql:
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
            self.conn=connect(ip,port) #申请系统资源, 此行为伪代码
        def __del__(self):
            self.conn.close()         #回收系统资源
     
    obj=Mysql('1.1.1.1',3306)
     
    class MyOpen:
        def __init__(self,filepath,mode="r",encoding="utf-8"):
            self.filepath=filepath
            self.mode=mode
            self.encoding=encoding
            self.fobj=open(filepath,mode=mode,encoding=encoding)
        def __str__(self):
            msg="""
            filepath:%s
            mode:%s
            encoding:%s
            """ %(self.filepath,self.mode,self.encoding)
            return msg
        def __del__(self):
            self.fobj.close()    #回收系统资源
     
    f=MyOpen('aaa.py',mode='r',encoding='utf-8')
    print(f.filepath,f.mode,f.encoding)
    print(f)
    print(f.fobj)
    res=f.fobj.read()
    print(res)
     
    以下四个皆为绑定对象的方法,在满足一定条件时,自动触发
    __init__
    __str__
    __del__
    __call__
     
    五、元类
    exec执行字符串中的代码,将产生的名字存入global_dic(全局名称空间)和local_dic(局部名称空间)
    code="""
    global x
    x=0
    y=2
    """
    global_dic={'x':100000}
    local_dic={}
    exec(code,global_dic,local_dic)
    print(global_dic)
    print(local_dic)  #没有声明都是局部的
     
    code="""
    x=1
    y=2
    def f1(self,a,b):
        pass
    """
    local_dic={}
    exec(code,{},local_dic)
    print(local_dic)  #{'x': 1, 'y': 2, 'f1': <function f1 at 0x101c60e18>}
     
    a、 一切皆对象
    元类:类的类就是元类,内置元类type是用来专门产生class定义的类的
    我们用class定义的类来产生我们自己的对象的
    class Chinese:        #Chinese=type(...)
        country="China"
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
        def speak(self):
            print('%s speak Chinese' %self.name)
    print(Chinese)        #<class '__main__.Chinese'>
    p=Chinese('egon',18,'male')
    print(type(p))        #对象p的类是类chinese   <class '__main__.Chinese'>
    print(type(Chinese))   #对象(类chinese)的类是类type  <class 'type'>
     
    class Foo:         #Foo=type(...)
        pass
    print(type(Foo))   #<class 'type'>
    f=Foo
    l=[Foo,]
    print(l)           #[<class '__main__.Foo'>]
     
    b、 用内置的元类type,来实例化得到我们的类
    class_name='Chinese'
    class_bases=(object,)
    class_body="""
    country="China"
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def speak(self):
        print('%s speak Chinese' %self.name)
    """
    class_dic={}
    exec(class_body,{},class_dic)
     
    print(class_name,class_bases,class_dic) # 类的三大要素
    Chinese=type(class_name,class_bases,class_dic)
    print(Chinese)
    p=Chinese('egon',18,'male')
    print(p.name,p.age,p.sex)
     
    c、 储备知识 __call__
    调用对象,则会自动触发对象下的绑定方法__call__的执行,然后将对象本身当作第一个参数传给self,将调用对象时括号内的值传给*args与**kwargs
    class Foo:
        def __init__(self):
            pass
        def __str__(self):
            return '123123'
        def __del__(self):
            pass
        def __call__(self, *args, **kwargs):
            print('__call__',args,kwargs)
     
    obj=Foo()
    print(obj)             #123123
    obj(1,2,3,a=1,b=2,c=3) #__call__ (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
     
    d、 自定义元类
    class Mymeta(type):
        # 来控制类Foo的创建
        def __init__(self,class_name,class_bases,class_dic): #self=Foo
            if not class_name.istitle():
                raise TypeError('类名的首字母必须大写')
            if not class_dic.get('__doc__'):  #对象.__doc__看类注释,无注释返回None
                raise TypeError('类中必须写好文档注释')
            super(Mymeta,self).__init__(class_name,class_bases,class_dic) #其他的遗传object
     
        # 控制类Foo的调用过程,即控制实例化Foo的过程
        def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={}
            obj=object.__new__(self)  #1 造一个空对象obj
            self.__init__(obj,*args,**kwargs) #2、调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__
            return obj
     
    class Foo(object,metaclass=Mymeta): # Foo=Mymeta('Foo',(object,),class_dic)
        """
        文档注释
        """
        x=1
        def __init__(self,y):
            self.y=y
        def f1(self):
            print('from f1')
     
    obj=Foo(1111)  #Foo.__call__()
    print(obj)     #<__main__.Foo object at 0x104501cf8>
    print(obj.y)   #1111
    print(obj.f1)  #<bound method Foo.f1 of <__main__.Foo object at 0x104501cf8>>
    print(obj.x)   #1
     
    e、 单例模式
    import settings
    class MySQL:
        __instance=None   #将instance隐藏使外部不能直接调用
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
     
        @classmethod
        def singleton(cls):
            if not cls.__instance:
                obj=cls(settings.IP, settings.PORT)
                cls.__instance=obj
            return cls.__instance
     
    obj1=MySQL('1.1.1.2',3306)
    obj2=MySQL('1.1.1.3',3307)
    obj3=MySQL('1.1.1.4',3308)
     
    #每次取用麻烦,且即使是相同内容,每次亦产生一个新的内存空间
    obj4=MySQL(settings.IP,settings.PORT)
    print(obj4.ip,obj4.port)
    #单例模式
    obj4=MySQL.singleton()
    obj5=MySQL.singleton()
    obj6=MySQL.singleton()
    print(obj4 is obj5 is obj6)  #True

    f. 基于元类实现单例模式的三种方式
    单例:即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省内存空间;如果我们从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了

    #settings.py文件内容如下
    HOST='1.1.1.1'
    PORT=3306
     
    #方式一:定义一个类方法实现单例模式
    import settings
     
    class Mysql:
        __instance=None
        def __init__(self,host,port):
            self.host=host
            self.port=port
     
        @classmethod
        def singleton(cls):
            if not cls.__instance:
                cls.__instance=cls(settings.HOST,settings.PORT)
            return cls.__instance
     
    obj1=Mysql('1.1.1.2',3306)
    obj2=Mysql('1.1.1.3',3307)
    print(obj1 is obj2)   #False
    obj3=Mysql.singleton()
    obj4=Mysql.singleton()
    print(obj3 is obj4)   #True
     
    #方式二:定制元类实现单例模式
    import settings
     
    class Mymeta(type):
        def __init__(self,name,bases,dic):   #定义类Mysql时就触发
     
            # 事先先从配置文件中取配置来造一个Mysql的实例出来
            self.__instance = object.__new__(self)    # 产生对象
            self.__init__(self.__instance, settings.HOST, settings.PORT)    # 初始化对象
            # 上述两步可以合成下面一步
            # self.__instance=super().__call__(*args,**kwargs)
     
            super().__init__(name,bases,dic)
     
        def __call__(self, *args, **kwargs): #Mysql(...)时触发
            if args or kwargs: # args或kwargs内有值
                obj=object.__new__(self)
                self.__init__(obj,*args,**kwargs)
                return obj
     
            return self.__instance
     
    class Mysql(metaclass=Mymeta):
        def __init__(self,host,port):
            self.host=host
            self.port=port
     
    obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,所有的实例应该指向一个内存地址
    obj2=Mysql()
    obj3=Mysql()
     
    print(obj1 is obj2 is obj3)
    obj4=Mysql('1.1.1.4',3307)
     
    #方式三:定义一个装饰器实现单例模式
    import settings
     
    def singleton(cls):   #cls=Mysql
        _instance=cls(settings.HOST,settings.PORT)
     
        def wrapper(*args,**kwargs):
            if args or kwargs:
                obj=cls(*args,**kwargs)
                return obj
            return _instance
     
        return wrapper
     
    @singleton # Mysql=singleton(Mysql)
    class Mysql:
        def __init__(self,host,port):
            self.host=host
            self.port=port
     
    obj1=Mysql()
    obj2=Mysql()
    obj3=Mysql()
    print(obj1 is obj2 is obj3)   #True
     
    obj4=Mysql('1.1.1.3',3307)
    obj5=Mysql('1.1.1.4',3308)
    print(obj3 is obj4)   #False
  • 相关阅读:
    168. Excel Sheet Column Title
    171. Excel Sheet Column Number
    264. Ugly Number II java solutions
    152. Maximum Product Subarray java solutions
    309. Best Time to Buy and Sell Stock with Cooldown java solutions
    120. Triangle java solutions
    300. Longest Increasing Subsequence java solutions
    63. Unique Paths II java solutions
    221. Maximal Square java solutions
    279. Perfect Squares java solutions
  • 原文地址:https://www.cnblogs.com/zhangyaqian/p/py20180417.html
Copyright © 2011-2022 走看看