4月17日 python学习总结 反射、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  #只有在使用点调用属性且属性不存在的时候才会触发
x=getattr(People,'country1',None)
print(x)

f=getattr(obj,'tell',None)#obj.tell
print(f == obj.tell)
f()
obj.tell()


3、setattr   
People.x=111
setattr(People,'x',111)
print(People.x)

obj.age=18
setattr(obj,"age",18)
print(obj.__dict__)

4、delattr
del People.country
delattr(People,"country")
print(People.__dict__)

del obj.name
delattr(obj,"name")
print(obj.__dict__)

  

 

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 Foo:
    def run(self):
        while True:
            cmd=input('cmd>>: ').strip()
            # print('%s run...' %cmd)
            if hasattr(self,cmd):
                func=getattr(self,cmd)
                func()

    def download(self):
        print('download....')

    def upload(self):
        print('upload...')

# obj=Foo()
# obj.run()

 

二、object内置方法

    __str__ 、__del__、__call__等没有设置也是默认就有的,从object类中继承来,不做任何操作,此处是在重写父类方法

  1、__str__()方法 在打印对象时触发     

class People:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def __str__(self):
        # print('========>')
        return '<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex)

obj=People('egon',18,'male')
print(obj)            #执行时相当于print(obj.__str__())

# l=list([1,2,3])
# print(l)

  2、__del__()  析构函数    对象删除时触发  

      eg:  

       1. del 对象名 删除对象 2. 程序结束释放内存空间时  3. 对象被垃圾回收机制回收时

      在对象被创建时,若有打开文件或手动开辟内存空间等操作,在删除对象,这些系统资源没有被释放,就必须要用__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__()

time.sleep(5)

应用      

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=open('a.txt',mode='r',encoding='utf-8')

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)

 

  3、__call__ 方法  调用对象时触发(可用于元类控制类的实例化

class Foo:
     def __init__(self):
         pass
     def __str__(self):
         return '123123'

     def __del__(self):
         pass

     # 调用对象,则会自动触发对象下的绑定方法__call__的执行,
     # 然后将对象本身当作第一个参数传给self,将调用对象时括号内的值
     #传给*args与**kwargs
     def __call__(self, *args, **kwargs):
         print('__call__',args,kwargs)

 

三、元类

  1、cexec()函数

    exec(code , global , local) 将第一个参数code中的代码解析,其中的全局变量以字典形式放到第二个参数global中,局部变量以字典形式放到第三个参数 local中

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)

  2、一切皆对象,类也是对象,类的类是什么呢?

     类的类就是元类     

  我们用class定义的类使用来产生我们自己的对象

  内置元类type是用来专门产生class定义的类的

 

1、用内置的元类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)

 

 2、自定义元类:

class Mymeta(type):
    # 来控制类Foo的创建
    def __init__(self,class_name,class_bases,class_dic): #self=Foo
        # print(class_name)
        # print(class_bases)
        # print(class_dic)
        if not class_name.istitle():
            raise TypeError('类名的首字母必须大写傻叉')

        if not class_dic.get('__doc__'):
            raise TypeError('类中必须写好文档注释,大傻叉')

        super(Mymeta,self).__init__(class_name,class_bases,class_dic)

    # 控制类Foo的调用过程,即控制实例化Foo的过程
    def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={}
        # print(self)
        # print(args)
        # print(kwargs)

        #1 造一个空对象obj
        obj=object.__new__(self)

        #2、调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__
        self.__init__(obj,*args,**kwargs)

        return obj



#Foo=Mymeta('Foo',(object,),class_dic)
class Foo(object,metaclass=Mymeta):
    """
    文档注释
    """
    x=1
    def __init__(self,y):
        self.Y=y

    def f1(self):
        print('from f1')


obj=Foo(1111) #Foo.__call__()

# print(obj)
# print(obj.y)
# print(obj.f1)
# print(obj.x)

 

 

单例设计模式:就是只有一个对象的模式,就算是创建多次对象指向的也是同一个对象地址

 第一种实现方式:

# 单例模式
import settings

class MySQL:
    __instance=None
    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)        #setting中的IP 和PORT是固定值
            cls.__instance=obj
        return cls.__instance



# 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)

 

第二种:通过元类

  

#方式二:定制元类实现单例模式
# 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) #Fals

 

 

作业:    

'''
4-17日作业
'''
'''
    1、判断一个对象是否属于str类型,判断一个类是否是另外一个类的子类
'''
a='123'
print(isinstance(a,str))
print(issubclass(str,object))

'''
    2、有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类(放到了另外一个文件中),但是egon去跟女朋友度蜜月去了,还没有完成他写的类,
        class FtpClient:
            """
            ftp客户端,但是还么有实现具体的功能
            """
            def __init__(self,addr):
                print('正在连接服务器[%s]' %addr)
                self.addr=addr

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

class FtpClient:
    """
    ftp客户端,但是还么有实现具体的功能
    """

    def __init__(self, addr):
        print('正在连接服务器[%s]' % addr)
        self.addr = addr
f=FtpClient('egon')
addr=getattr(f,'addr')
print(addr)


'''

    3、定义一个老师类,定制打印对象的格式为‘<name:egon age:18 sex:male>’
'''
class Teacher:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def __str__(self):
        return '<name: %s  age: %s  sex: %s>'%(self.name,self.age,self.sex)
t=Teacher('egon',18,'male')
print(t)

'''
 4、定义一个自己的open类,控制文件的读或写,在对象被删除时自动回收系统资源
'''
class MyOpen:
    def __init__(self,file,io,encoding):
        self.file=file
        self.io=io
        self.encoding=encoding
        self.my_open=open(self.file,self.io,encoding=self.encoding)
    def __del__(self):
        self.my_open.close()
        print('guan bi wen jian')

mo=MyOpen(r'F:\python\object\days2\days23\setting.py','rt','utf-8')
del mo

'''
  5、自定义元类,把自定义类的数据属性都变成大写,必须有文档注释,类名的首字母必须大写
'''
class Mymeta(type):
    def __init__(self,class_name,class_base,class_dict):
        dict={}
        for name in class_dict:
            if not name.istitle():
                new_name=name.capitalize()
            dict.update({new_name:class_dict[name]})
        print(dict)
        super().__init__(class_name,class_base,dict)
        if not class_name.istitle():
            raise TypeError('类名必须首字母大写')
        if not class_dict.get('__doc__'):
            raise TypeError('类必须有文档注释')
class My(object,metaclass=Mymeta):
    '''
    MY 1233123
    '''
    char='123'
    def abc(self):
        print(self.char)
m=My()
print(My.__dict__)



'''

    6、用三种方法实现单例模式,参考答案:http://www.cnblogs.com/linhaifeng/articles/8029564.html#_label5
'''



class Mymeta(type):
    __obj = ''
    def __call__(self, *args, **kwargs):
        if self.__obj=='':
            self.__obj=self.__new__(self)
            self.__obj.__init__(*args, **kwargs)
        return self.__obj
class My(object,metaclass=Mymeta):
    '''
    MY 1233123
    '''
    char='123'
    def abc(self):
        print(self.char)
m = My()
m2 = My()
m3 = My()
print(m, m2, m3)

 

 

 

 

 

 

 

 

 

    

 

posted @ 2018-04-18 08:26  道友请多指教  阅读(293)  评论(0编辑  收藏  举报