• 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
  • 相关阅读:
    Magento速度优化
    magento-connect-manage出现404或者500内部错误的解决办法
    magento -- 给后台分类管理页的分类商品加一栏商品类型
    magento -- 添加新产品时状态默认为激活,库存状态默认为有库存
    magento -- 如何为商品分类(category)添加自定义属性
    magento -- 如何改善前台图片质量
    安装Let's Encrypt SSL证书
    centos版本查看
    ps
    设置桥接虚拟网卡
  • 原文地址:https://www.cnblogs.com/zhangyaqian/p/py20180417.html
Copyright © 2020-2023  润新知