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也改变
不可变的引用是深拷贝。
可变的引用是浅拷贝