灵虚御风
醉饮千觞不知愁,忘川来生空余恨!

导航

 

24.反射,元类,call new 单例

1.反射
2.元类

1.反射 reflect

什么是反射 ,其实是反省,自省的意思

反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力

反射就是通过字符串操作属性

涉及的四个函数,这四个函数就是普通的内置函数,没有双下划綫,与print 等等没有区别

    hasattr #判断某个对象是否存在某个属性
    getattr # 从对象中取出属性,第三个值位默认值 当属性不存在是返回默认值
    setattr # 为对象添加新的属性
    delattr # 从对象中删除属性

使用场景:
    反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解

    另一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法

反射的应用案例: # 2.反射的应用案例.py


4.元类 metaclass
    元类是什么,用来创建类的类
    万物皆是对象 ,类当然也是对象

    对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的

    默认情况下所有类的元类都是type

    """直接调用type类来产生类对象"""
"""
一个类的三个基本组成
    1.类的名字(字符类型)
    2.类的父类们(是一个元组或者列表)
    3.类的名称空间(字典类型)

    验证:4.类的类是谁.py


5.学习元类的目的:
    高度的自定义一个类,,例如控制类的名字必须以大驼峰的方式来书写
    类也是对象,也有自己的类,

    我们的需求是创建类对象做一些限制

    想到了初始化方法  我们只要找到类对象的类(元类),覆盖其中 init方法就能实现需求

    当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求

代码: 5.自己来定义元类.py

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

   覆盖元类 call 后 这个类就无法产生对象,必须调用 super().__call__来完成对象的创建

   并返回其返回值

   使用场景:
        1.当你想要控制对象创建过程时,就覆盖call方法
        2.当你想要控制类的创建过程时就覆盖init方法
       案例:6.call方法的应用.py


7.元类中new方法
    当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作
注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象

测试:7.元类的new方法.py

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

8.单例设计模式
24.反射,元类,call new 单例

lib/plugins.py

class WinCMD:

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

    def delete(self):
        print("wincmd 要不要删库跑路?")

    def dir(self):
        print("wincmd 列出所有文件....")


class LinuxCMD:

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

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

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

settingss.py

""""""
"""该文件作为框架的配置文件"""
"""作为框架使用者 在配置文件中指定你配合框架的类是哪个

"""
CLASS_PATH = "libs.plugins.LinuxCMD"
settingss.py
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")

# 创建一个插件对象 调用框架来使用它
# wincmd = settings.Plugins.WinCMD()

# 框架之外的部分就有自定义对象来完成

# 框架 得根据配置文件拿到需要的类

path = settings.CLASS_PATH
# 从配置中单独拿出来 模块路径和 类名称
module_path,class_name = path.rsplit(".",1)

#拿到模块
mk = importlib.import_module(module_path)

# 拿到类
cls = getattr(mk,class_name)
# 实例化对象
obj = cls()
#调用框架
run(obj)

"""

如此一来,框架就与实现代码彻底解耦了,只剩下配置文件
"""
2.0.myframework.py
class Person:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

p = Person("jack",18,"man")
print(p.name) # jack

"hasattr 判断某个对象是否存在某个属性"
print(hasattr(p,"name")) # True

"getattr 从对象中取出属性,第三个值为默认值.当属性不存在时返回默认值"
if hasattr(p,"name"):
    print(getattr(p,"names",None)) # None
    print(getattr(p,"gender",None)) # man

"setattr 为对象添加新的属性"
setattr(p,"id_card","123") # (对象 ,k,v)
print(p.__dict__)
"""
{'name': 'jack', 'age': 18, 'gender': 'man', 'id_card': '123'}

"""

"delattr 从对象中删除属性"
delattr(p,"id_card")
print(p.__dict__) # {'name': 'jack', 'age': 18, 'gender': 'man'}
1.反射的四个方法的使用.py
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")

# 创建一个插件对象 调用框架来使用它
# wincmd = settings.Plugins.WinCMD()

# 框架之外的部分就有自定义对象来完成

# 框架 得根据配置文件拿到需要的类

path = settings.CLASS_PATH
# 从配置中单独拿出来 模块路径和 类名称
module_path,class_name = path.rsplit(".",1)

#拿到模块
mk = importlib.import_module(module_path)

# 拿到类
cls = getattr(mk,class_name)
# 实例化对象
obj = cls()
#调用框架
run(obj)

"""

如此一来,框架就与实现代码彻底解耦了,只剩下配置文件
"""
2.反射的应用案例.py
""""""
"""
在框架设计中 我们不可能提前知道 框架的用户要提供类相关的信息
"""
import importlib

import abc

"拿到模块 根据模块的路径"
p1 = importlib.import_module("libs.plugins")
print(p1)
"从模块中取出来"
cls = getattr(p1,"WinCMD")
print(cls)


"实例化产生对象"
obj = cls()
obj.cd()

"""
<module 'libs.plugins' from 'D:\\面试整理\\重新开始\\6.面向对象(20-24)\\24.反射,元类,call new 单例\\libs\\plugins.py'>
<class 'libs.plugins.WinCMD'>
wincmd 切换目录....
"""
3.动态导入.py
#
#
# class Person(object):
#     name = "123"
#     pass
#
#
# p = Person()
# #
# print(type(p))# <class '__main__.Person'>
# print(type(Person)) # <class 'type'>


# class Student:
#     pass
# print(type(Student))

""""""
"""直接调用type类来产生类对象"""
"""
一个类的三个基本组成
    1.类的名字(字符类型)
    2.类的父类们(是一个元组或者列表)
    3.类的名称空间(字典类型)
"""
cls_obj = type("dog",(),{})
print(cls_obj) # <class '__main__.dog'>

class Person:
    pass
4.类的类是谁.py
""""""
"""
只要继承了type 那么这个类就变成了一个元类

"""
"""定义了一个元类"""

class MyType(type):
    def __init__(self,clss_name,bases,dict):
        super().__init__(clss_name,bases,dict)
        print(clss_name,bases,dict)
        if not clss_name.istitle():
            raise Exception("你丫的 类名不会写...")

"为pig类指定了元类为MyType"
class Pig(metaclass=MyType):
    pass

class Duck(metaclass=MyType):
    pass

MyType('pig',(),{})
5.自己来定义元类.py
""""""
"""
想要把这个对象的所有属性变成大写
"""
class MyMeta(type):
    def __init__(self,name,bases,dict):
        super().__init__(name,bases,dict)
        print("init run")

    def __call__(self, *args, **kwargs):
        print("元类 call run")
        print(self)
        print(args)
        print(kwargs)
        return super().__call__(*args,**kwargs)



class Dog(metaclass=MyMeta): # Dog = MyMate("Dog",(),{})

    def __init__(self,name):
        self.name = name

    def __call__(self, *args, **kwargs):
        print("call run")

d = Dog("大黄")
print(d.name)
"""
init run
元类 call run
<class '__main__.Dog'>
('大黄',)
{}
大黄

"""

class MyType(type):
    def __call__(self, *args, **kwargs):
        new_args = []
        for a in args:
            new_args.append(a.upper())

        print(new_args)
        print(kwargs)
        return super().__call__(*new_args,**kwargs)

class Person(metaclass=MyType):
    def __init__(self,name,gender):
        self.name = name
        self.gender = gender

p = Person(name="jack",gender="woman")
print(p.name)
print(p.gender)
"""
[]
{'name': 'jack', 'gender': 'woman'}
jack
woman
"""
"""
# 要求创建对象时必须以关键字参数形式来传参
# 覆盖元类的__call__
# 判断你有没有传非关键字参数 == 不能有位置参数
# 有就炸

"""

class Mate(type):
    # def __call__(self, *args, **kwargs):
    #     if args:
    #         raise Exception("不好意思 不允许使用位置参数!")
    #     return super().__call__(*args,**kwargs)
    #
    def __call__(self, *args, **kwargs):
        obj = object.__new__(self) # 创建一个空对象
        self.__init__(obj,*args,**kwargs) # # 让对象去初始化
        return obj

class A(metaclass=Mate):
    def __init__(self,name):
        self.name = name

a = A(name="jack")
print(a.name)
6.call方法的应用.py
class Meta(type):

    def __new__(cls, *args, **kwargs):
        print(cls) # 元类自己
        print(args)  # 创建类需要的几个参数  类名,基类,名称空间
        print(kwargs)  # 空的
        print("new run")
        # return super().__new__(cls,*args,**kwargs)
        obj = type.__new__(cls, *args, **kwargs)
        return obj
    def __init__(self,a,b,c):
        super().__init__(a,b,c)
        print("init run")


class A(metaclass=Meta):
    pass

print(A)
# a = A()
"""
<class '__main__.Meta'>
('A', (), {'__module__': '__main__', '__qualname__': 'A'})
{}
new run
init run
<class '__main__.A'>
"""
7.元类的new方法.py
""""""
"""
设计模式?
用于解决某种固定问题的套路

MVC
MTV


单例:指的是一个类产生一个对象

为什么要使用单例:
单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象

"""

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

    def say_hi(self):
        print("hello im %s" % self.name)

    # 用于获取对象的方法
    @staticmethod
    def get_instance():
        # 判断是否已经有了对象
        if hasattr(Person,"obj"):
            return getattr(Person,"obj")
        obj = Person("jack",18)
        Person.obj = obj
        print("new 了")
        return obj

p = Person.get_instance()
p.say_hi()

p2 = Person.get_instance()
p2.say_hi()

p3 = Person.get_instance()
p3.say_hi()


"""
单例元类
"""
class Single(type):
    def __call__(self, *args, **kwargs):
        if hasattr(self,'obj'):# #判断是否存在已经有的对象
            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()
Student("llx")
8.单例设计.py

三层结构.png

 

posted on 2022-03-25 17:06  没有如果,只看将来  阅读(20)  评论(0编辑  收藏  举报