python高级学习:动态类Type,元类Metaclass

1. Type动态类

在Python的机制里,所有Class都是type的一个实例。所以,只要我们动态创建了一个type的实例,我们就能用它定义一个类,用这个类就能创建一个对象。

初始版本:适合类实现方法简单,跟类创建在一个.py文件中。
进阶和高级版本:类实现方法复杂,调用模块多,使用反射机制。

1. 初始版本实现

在同一个模块.py中。

def __init__(self):
	pass
def sayHello(self):
	pass
A = type("类名",
            ("继承",),
            {"counter":"类变量",
            "__init__": "构造函数", 
            "sayHello": "其他方法"
            })

2. 进阶版实现

类的实现方法在另一个模块中,用户指定类名,构造变量的输入参数,以及类有哪些方法。

func[key]=getattr(helper,value)
function_name = getattr(A,key)

这两个语句都是通过函数名获取可执行的函数对象,但是可执行的对象不同。
第1个是helper模块的对象:<function get_info at 0x000002B6CD11CDC0>;
第2个是类的对象:<bound method get_info of <main.A_type object at 0x000002B6CD192F50>>

"""
类方法在helper.py中实现:__init__,sayHello
"""
import helper
# 指定类变量和方法
class_name = "类名"
func= {"__init__":"__init__","sayHello":"sayHello"}

# 在不同的模块中,要利用反射机制,将func变为可执行的函数
for key,value in func.items():
	func[key]=getattr(helper,value)
	
# 实例化对象
A = type(class_name ,("继承",),func)
            
# 调用类中的方法
for key,value in func.items():
	if key is "__init__":
		continue
	function_name = getattr(A,key)
	function_name()            

3. 高级版实现

类的实现方法在另一个模块中,用户仅指定类名,构造变量的输入参数,类的方法名不再指定,根据模块而变化。
helper.py文件,用于实现类的方法

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

def get_info(self):
    info = get_info_from_name(self.name)
    print(str(self.name)+"信息如下:")
    print(info)

def get_info_from_name(name):
    info = {}
    info["age"] = 15
    info["sex"] = "男"
    info["job"] = "开发"
    return info

主函数

import importlib
import inspect
def create_dynamic_class(class_name,parameter):
    "输入参数:类名和输入参数"
    class_dict = {}
    # 1. 利用反射机制,h=获取helper 模块
    helper_moudle = importlib.import_module("helper")
    # 2. 从模块中获取类方法函数名及函数对象
    fun_names = [i for i in dir(helper_moudle) if not i.startswith("__")]
    
    for fun_name in fun_names:
        # 3. 获取类方法对象
        exe_fun = getattr(helper_moudle,fun_name)
        # 4. 获取类方法的参数
        input_paras = list(inspect.signature(getattr(helper_moudle,fun_name)).parameters.keys())
        # 5. 判断是否包含self来确定是否为类方法还是普通函数?
        if fun_name == "init":
            fun_name = "__init__"
        if "self" in input_paras:
            class_dict.update({fun_name:exe_fun})
            
    # 6. 创建类并实例化对象
    type_class = type(class_name, (), class_dict)
    type_obj = type_class(parameter)            
    
    # 7. 调用类中的方法
    for key in class_dict.keys():
        if key == "__init__":
            continue
        function = getattr(type_obj,key)
        function()
        
if __name__ =="__main__":
    class_name = "A_type"
    parameter="小溪"
    create_dynamic_class(class_name,parameter)

在这里插入图片描述

元类Metaclass

Class是所有对象的模板,它定义了对象的行为。
Metaclass,可以做为Class的模板,它可以定义Class的行为/结构。

也就是通过Metaclass,可以给Class做一些预定义:如定义一下所有类必须实现的方法,或者是给类的方法加个前后处理,类似其它别的语言的AOP编程.

要想把一个类设计成元类必须满足:1.显示的继承自type类 ,2.类中要实现且定义__new__()方法,返回一个该类的实例对象。看下面的简单示例:

class Person(type):
    def __new__(cls, name, bases, attrs):
        attrs["name"] = "我是模板"
        attrs["getName"] = lambda self: self.name
        return  super().__new__(cls, name, bases, attrs)
        # super代表调父类type的new方法。
        	
class Person1(object, metaclass=Person):
    def __init__(self,local_name):
        self.local_name = local_name
    def get_Name(self):
            a = self.getName()
            return a+self.local_name
    
a = Person1("我是自己")
print(a.name)
print(a.local_name)

print(a.getName())
print(a.get_Name())

"""
	输出:
	我是模板
	我是自己
	我是模板
	我是模板我是自己
"""

init 和 __new__区别:

  • <font size=> 参数不同,new参数如下:
    1.cls代表动态修改的类
    2.name代表动态修改的类名
    3.bases代表被动态修改的类的所有父类
    4.attr代表被动态修改的类的所有属性、方法组成的字典
  • 从传递参数角度看
    __init__第一个参数是实例本身self, __new__传递的是类本身cls。
  • 从执行顺序角度看
    __new__方法执行在 __init__方法之前。
  • 从功能角度看:
    __new__是控制对象实例过程,在对象生成之前就执行完毕, 即创建对象并传给__init__的self对象;
    __init__是用来完成对象的实例化,在对象生成之后给对象初始化参数,即初始化对象。
  • 从差异性角度看
    __new__不返回 super().new(cls),则不会执行 __init__方法,也就是通过父类中的__new__启动 __init__函数实例化也就是object类。

new 是在我们调用类名进行实例化时自动调用的,init 是在这个类的每一次实例化对象之后调用的,new 方法创建一个实例之后返回这个实例对象并传递给 init 方法的 self 参数。

附加知识:理解变量

python 如何创建变量
a = 3
python将会执行三步去完成上面这个请求。
1.创建一个对象代表3
2.创建一个变量a,如果a未创建。
3.将变量a与对象3相连接。
可以将变量a看作对象3的一个引用,多个变量可以指向同一个对象,在Python中叫共享引用。

a = 3
b = a

由于共享引用的存在,有一些对象和操作会在原处修改对象。
Python中对象可分为可变类型对象和不可变类型对象。
可变对象:列表,字典
不可变对象:数字,字符串,元组
如果变量b是不可变对象a的引用,对变量名a的修改不会影响变量b,而是直接连接到修改的对象a。
如果变量b是可变对象a的引用,对变量名a的修改会影响其他变量b。

a=1,b=a,a=4,输出b还是1。
a=[1,2],b= a,a[0]=3.b也改变

不可变的引用是深拷贝。
可变的引用是浅拷贝

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值