从小白到小黑 python学习之旅 日常总结 33(反射机制 内置方法 元类)

反射机制

 

  什么是反射

        指的是在程序运行过程中可以"动态(比如查看对象信息是否存在)"获取对象的信息

 

  为何要用反射

   要用在调用时判断对象的信息(变的更智能,减少报错)

 

  如何实现反射

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

    def say(self):
        print('<%s:%s>' %(self.name,self.age))

obj=People('cool',18)




# 四个内置函数的使用:通过字符串来操作属性值
# 1、hasattr()  #判断是否存在
print(hasattr(obj,'name'))
#True
print(hasattr(obj,'x'))
#False

# 2、getattr()  #查看
print(getattr(obj,'name'))
#cool

# 3、setattr()   #修改
setattr(obj,'name','EGON') # obj.name='EGON'
print(obj.name)
#EGON

# 4、delattr()   #删除
delattr(obj,'name') # del obj.name
print(obj.__dict__)
#{'age': 18}

 

 

 补充

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

    def say(self):
        print('<%s:%s>' %(self.name,self.age))

obj=People('cool',18)

print(getattr(obj,'user',None))    # 如果说 obj里面没有'user'的属性 得不到的话    就返回None
#None


getattr(obj,'user',setattr(obj,'name','EGON'))# 如果说 obj里面没有'user'的属性 得不到的话       就把obj里的属性'name'的值改为EGON
print(obj.name)
#EGON

 

 

 反射案例

class Ftp:
    def put(self):
        print('正在执行上传功能')

    def get(self):
        print('正在执行下载功能')

    def interactive(self):
        method=input(">>>: ").strip() # method='put'

        if hasattr(self,method):
            getattr(self,method)()
        else:
            print('输入的指令不存在')


obj=Ftp()
obj.interactive()


#>>>: xxxxx
#输入的指令不存在


#>>>: put
#正在执行上传功能

 

 

 内置方法

 

 

什么是内置方法

定义在类内部,以__开头并以__结果的方法
特点:会在某种情况下自动触发执行

为何要用内置方法

为了定制化我们的类or对象

 

    如何使用内置方法

__str__:在打印对象时会自动触发,然后将返回值(必须是字符串类型)当做本次打印的结果输出
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):     
        # print('运行了...')
        return "<%s:%s>" %(self.name,self.age)


obj = People('辣白菜同学', 18)
print(obj)            #如果没有__str__的话  那么打印的是对象obj的内存地址
#<辣白菜同学:18>

 

 

__del__:在清理对象时触发,会先执行该方法  #应用场景有在应用程序关闭前要提醒操作系统:应用程序调用的操作系统功能需要关闭  比如说要在应用系统关闭前把文件关闭 等等...
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.x = open('a.txt',mode='w')
        # self.x = 占据的是操作系统资源

    def __del__(self):
        print('run...')
        # 发起系统调用,告诉操作系统回收相关的系统资源
        self.x.close()

obj = People('辣白菜同学', 18)
print('============>')

#程序运行完会清理内存  就会触发__del__ 触发代码print('run...')
#============>  
#run...

 

 
元类

引入:
一切皆为对象

什么是元类
元类就是用来实例化产生类的类
关系:元类---实例化---->类(People)---实例化---->对象(obj)

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

    def say(self):
        print('%s:%s' %(self.name,self.name))

obj=People('egon',18)

#查看对象 obj 的类
print(type(obj))
#<class '__main__.People'>

#如果说类(people)也是对象
#那我们查看一下 类/对象 people 的类
print(type(People))
#<class 'type'>

# 1、type是内置的元类
# 2、我们用class关键字定义的所有的类以及内置的类都是由元类type实例化产生

#我们来试一下
print(type(int))
#<class 'type'>

class机制分析  #class关键字创造类People的步骤
类有三大特征:

# 1、类名
class_name="People"

# 2、类的基类
class_bases=(object,)

# 3、执行类体代码拿到类的名称空间
class_dic={}
class_body="""
def __init__(self,name,age):
    self.name=name
    self.age=age

def say(self):
    print('%s:%s' %(self.name,self.name))
"""

exec(class_body,{},class_dic)  #{}模拟全局空间
print(class_dic)
#{'__init__': <function __init__ at 0x00000000026D91F0>, 'say': <function say at 0x00000000026D9430>}



# 4、调用元类
People=type(class_name,class_bases,class_dic)
print(People)
#<class '__main__.People'>   #没有用class关键字 造出的类

 type元类   (类) --- class  (obj=类(参数#三大特征)) --- 类    (被class造出来的对象obj)



如何自定义元类来控制类的产生  #造元类
#造元类
class Mymeta(type): # 只有继承了type类的类才是元类

    def __init__(self,x,y,z):  #x(类名)  y(类的基类)  z(类的名称空间地址)
        print('run...')
#run...

        print(self)

        print(x)
#People

        print(y)
#()

        print(z)
#{'__module__': '__main__', '__qualname__': 'People', '__init__': <function People.__init__ at 0x00000000026F9310>, 'say': <function People.say at 0x00000000026F94C0>}



class People(metaclass=Mymeta):  #默认metaclass=type
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s:%s' %(self.name,self.name))


print(type(People))
#<class '__main__.Mymeta'>


# People=Mymeta("People",(object,),{...})
# 调用Mymeta发生三件事
# 1、先造一个空对象=>People
# 2、调用Mymeta这个类内的__init__方法,完成初始化对象的操作
# 3、返回初始化好的对象

 


__new__方法 #造一个类的对象
# 强调:
# 只要是调用类,那么会依次调用
# 1、类内的__new__
# 2、类内的__init__


class Mymeta(type): # 只有继承了type类的类才是元类
    def __init__(self,x,y,z):
        print('run22222222222....')

    #          当前所在的类,调用类时所传入的参数
    def __new__(cls, *args, **kwargs):
        # 造Mymeta的对象
        print('run1111111111.....')
        print(cls,args,kwargs)
        return super().__new__(cls,*args, **kwargs)  #  返回值 就是造的对象 不返回就没造好
        # return type.__new__(cls,*args, **kwargs) # 指名道姓式


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

    def say(self):
        print('%s:%s' %(self.name,self.name))
 

#执行结果 

#run1111111111.....  # 先执行__new__


#当前所在的类,调用类时所传入的参数
#<class '__main__.Mymeta'> ('People', (), {'__module__': '__main__', '__qualname__': 'People', '__init__': <function People.__init__ at 0x00000000026E94C0>, 'say': <function People.say at 0x00000000026E9550>}) {}   


#run22222222222....  # 再执行__init__


     
        
        
# People=Mymeta("People",(object,),{...})
# 调用Mymeta发生三件事
# 1、先造一个空对象=>People,调用Mymeta类内的__new__方法
# 2、调用Mymeta这个类内的__init__方法,完成初始化对象的操作
# 3、返回初始化好的对象

 

 

 
__call__
方法

class Foo:
    def __init__(self,x,y):
        self.x=x
        self.y=y

    #            obj,1,2,3,a=4,b=5,c=6
    def __call__(self,*args,**kwargs):
        print('===>',args,kwargs)
#===> (1, 2, 3) {'a': 4, 'b': 5, 'c': 6}
        return 123

obj=Foo(111,222)
# print(obj) # obj.__str__
res=obj(1,2,3,a=4,b=5,c=6) # res=obj.__call__()  #括号里是传给__call__的参数
print(res)
#123  #__call__的返回值

 




自定义元类控制类的调用=》类的对象的产生 #模板

class Mymeta(type): # 只有继承了type类的类才是元类
    def __call__(self, *args, **kwargs):
        # 1、Mymeta.__call__函数内会先调用People内的__new__
        people_obj=self.__new__(self)
        # 2、Mymeta.__call__函数内会调用People内的__init__
        self.__init__(people_obj,*args, **kwargs)
        # 3、Mymeta.__call__函数内会返回一个初始化好的对象
        return people_obj

# 类的产生  __new__、__init__
# People=Mymeta()=》type.__call__=>干了3件事
# 1、type.__call__函数内会先调用Mymeta内的__new__
# 2、type.__call__函数内会调用Mymeta内的__init__
# 3、type.__call__函数内会返回一个初始化好的对象

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

    def say(self):
        print('%s:%s' %(self.name,self.name))

    def __new__(cls, *args, **kwargs):
        # 产生真正的对象
        return object.__new__(cls)

# 类的调用   __call__
# obj=People('egon',18) =》Mymeta.__call__=》干了3件事
# 1、Mymeta.__call__函数内会先调用People内的__new__
# 2、Mymeta.__call__函数内会调用People内的__init__
# 3、Mymeta.__call__函数内会返回一个初始化好的对象

obj=People('egon',18)
print(obj.__dict__)

元类下的属性查找
属性查找的原则:对象-》类-》父类
切记:父类 不是 元类
对象>>>类>>>父类>>>父类的父类(等等)
类>>>父类>>>
父类的父类(等等)>>>元类(因为对于元类来说 类 就是元类的对象)





 

posted @ 2020-04-15 20:08  It's_cool  阅读(129)  评论(0)    收藏  举报