元类

反射 reflect:
反射 其实不是我们字面意思的折射,而是反省,自检的意思
反射指的是一个对象应具备,可以检测,修改,增加自身属性的能力
反射就是通过字符串操作属性
涉及了四个函数,这四个函数其实就是普通的内置函数,没有双下划线
和print() len()一样没有什么其他的特殊区别
这四个函数分别是:
hasattr: 判断某个对象是否存在某种属性
getattr: 从对象中获取属性,第三个值为默认值,当属性不存在时返回默认值
setattr: 往对象里面添加新的属性
delattr: 从对象里面删除属性
实例:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("哨兵", 18)
# print(p.name)
if hasattr(p,"name"):
    print("对象P里面存在'name'这个属性") # >>>对象P里面存在'name'这个属性
    print(getattr(p,'age',None))   # 执行结果>>>哨兵  最后的返回值None属性存在时不写也可以
    print(getattr(p, 'asd',None))  #  当属性不存在时,会返回None,如果这个时候没有写None会报错
setattr(p,"id",23456)  # setattr 为对象添加新的属性
setattr(p,"age",23456) # 当属性存在时,会覆盖老的值
print(p.age)

delattr(p,"age")  # 从对象里面删除指定的值
print(p.age)   #>>>  AttributeError: 'Person' object has no attribute 'age'

  



使用场景:
反射其实就是对属性的增删改查,但是如果直接使用内置的dict来操作,语法繁琐,而且不便于阅读理解
另外最重要的问题是:
如果对象不是我们自己写的是另外一方提供的,那么我们就要必须判断这个对象是否可以满足我们的需求
也就是说是否使我们所需要的属性和方法
框架设计方式:
框架代码:
#反射的四个函数实例:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("哨兵", 18)
# print(p.name)
if hasattr(p,"name"):
    print("对象P里面存在'name'这个属性") # >>>对象P里面存在'name'这个属性
    print(getattr(p,'age',None))   # 执行结果>>>哨兵  最后的返回值None属性存在时不写也可以
    print(getattr(p, 'asd',None))  #  当属性不存在时,会返回None,如果这个时候没有写None会报错
setattr(p,"id",23456)  # setattr 为对象添加新的属性
setattr(p,"age",23456) # 当属性存在时,会覆盖老的值
print(p.age)

delattr(p,"age")  # 从对象里面删除指定的值 
print(p.age)   #>>>  AttributeError: 'Person' object has no attribute 'age'
'''
"""

  



反射被称之为框架基石,因为框架的设计者不可能提前知道你的对象到底是怎么设计的
所以你提供框架的对象,必须通过判断验证之后才可以正常使用,而3判断和验证就是反射需要做的事情
当然也可以使用__dict__来实现,期是这种方法就是把__dict__的操作进行了封装
实例说明:
需求: 要实现一个用于处理用户终端指令的模拟小框架
首先分为框架部分
插件部分
配置文件部分
#框架部分:
import importlib
import settings

def run(plugin):
    while True:
        cmd = input("请输入命令").strip()
        if cmd == "exit":
            break
        if hasattr(plugin,cmd): # 判断对象是否具有处理这个指令的方法
            # 如果有
            func = getattr(plugin,cmd)
            func()
        else:
            print("该指令不存在")
    # print("see you la la ")
    return "hahaha"

path = settings.CLASS_PATH
# 从配置文件setings中拿到模块的路径和类的名字
module_path, class_name = path.rsplit(".",1)
#拿到模块
lk = importlib.import_module(module_path)
# 拿到类
cls = getattr(lk,class_name)
res = cls()
run(res)

配置文件部分settings文件
###这个文件作为框架的配置文件###
CLASS_PATH = "lib.plugins.LinuxCMD"
插件部分在LIB文件下的plugins


属于插件部分

class WinCMD:
    def cd(self):
        print("wincod 切换目录")

    def delete(self):
        print("wincod 删除文件")

    def dir(self):
        print("wincod 列出所有文件")
class LinuxCMD:

    def cd(self):
        print("Linuxcmd 切换目录....")

    def rm(self):
        print("Linuxcmd 要不要删库跑路?")

    def ls(self):
        print("Linuxcmd 列出所有文件....")

  


元类:
元类就是用于创建类的类,也就是原始类,大多数情况下都是type
万物皆对象,类也就是对象了,那么对象是有类实例化产生的,那么类也就是
另一个类实例化产生的,所以说默认情况下所有的类元类就是TYPE
#元类验证实例
class A:
pass
a = A()
print(type(a)) # a 的元类是 <class '__main__.A'>
print(type(A)) # A 的元类是 <class 'type'>

学习元类的目的:
高度自定义一个类,类也是对象,也有自己的类也就是元类
我们可以对类创建对象多一些限制,那么我们就可以在初始化上面做一些手脚
只要我们找到类对象的元类,覆盖其中的__init__方法就可以实现
因为我们不能修改源代码,所以我们应该是用继承元类的方式来编写自己,同时
覆盖__init__来实现
元类的实例
'''
直接调用元类type类来产生对象
cls = type("泰迪",(),{})
print(cls)
一个类的三个基本组成部分
1.类的名字(字符串类型的)
2.父类的名字(列表或者元祖组成)
3.类的名称空间(字典类型)

'''

  

class MyTypt(type):
    def __init__(self,class_name,bases, dict ):
        super().__init__(class_name,bases, dict) # 元类的__init__方法
        print(class_name,bases, dict)
        if not class_name.istitle(): # 限制类的首字母大写
            raise Exception("类名请单词首字母大写")
class Dig(metaclass=MyTypt):
    pass

class Duck(metaclass=MyTypt):
    pass

class ds(metaclass=MyTypt):
    pass
<   raise Exception("类名请单词首字母大写")
Exception: 类名请单词首字母大写  >

  


元类中的__call__方法
当你调用类对象时会自动制行元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数

覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建
并返回其返回值
首先使用场景:
想要控制对象的创造过程时需要使用__call__方法
想要控制类创造过程中时候,就要覆盖__init__方法
实例:
class Da(type):
    def __call__(self, *args, **kwargs):
        new_args = []
        for i in args:
            new_args.append(i.upper())
        print(new_args)
        print(kwargs)
        return super().__call__(*new_args,**kwargs)
class Ap(metaclass=Da):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    # def __call__(self, *args, **kwargs):


a = Ap("jack","n")
print(a.name)
print(a.gender)
实例2:
class Mate(type):
    def __call__(self, *args, **kwargs):
        if args:
            raise Exception("不好意思不能使用未知参数")
        return super().__call__(*args, **kwargs)

class A(metaclass=Mate):
    def __init__(self,name ):
        self.name = name
a = A(name = "jack")
print(a.name)
注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象

  


new的方法
当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作
注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象
class Meta(type):
    def __new__(cls, *args, **kwargs):
        print(cls) # 元类自己
        print(*args) # 创建需要的几个参数,类名,基类,名称空间
        print(**kwargs) # 空的
        print("new_run")
        res = type.__new__(cls,*args,**kwargs)
        return res
    def __init__(self,a,b,c):
        super().__init__(a,b,c)
        print("init_run")
class A(metaclass=Meta):
    pass
print(A)

  


总结new方法和init 都可以实现控制类的创建过程,init更简单

单例涉及模式:
设计模式,用于解决问题的方式的某种套路
单例:指的是一个类产生一个对象
为什要使用单例:
单例是为了节省资源,当一个类的所有对象属性全部相同时,测没有必要创建多对象
实例:
class Single(type):
    def __call__(self, *args, **kwargs):
        if hasattr(self,"obj"): #判断是否存在已经有的对象
            return getattr(self,"obj") # 有就返回

        obj = super().__call__(*args,**kwargs) # 没有则创建
        print("new 了")
        self.obj = obj # 并存入类中
        return obj


class Student(metaclass=Single):
    def __init__(self,name):
        self.name = name


class Person(metaclass=Single):
    pass

# 只会创建一个对象
Person()
Person()    

  

原文地址:https://www.cnblogs.com/ioipchina/p/11273340.html