反射 reflect
反射 reflect
什么是反射, 其实是反省,自省的意思
反射就是通过字符串操作属性
涉及的四个函数,这四个函数就是普通的内置函数 没有双下划綫,与print等等没有区别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class Preson: def __init__( self ,name,age): self .name = name self .age = age p = Preson( "joke" , 12 ) # 判断该类中是否有name和namexxx这个属性 # 如果有就返回 True,如果没有就返回 False # print(hasattr(p,"name")) # print(hasattr(p,"namexxx")) # 取出该对象中的属性,如果有就返回值,如果没有就报错 # print(getattr(p,"name")) # # print(getattr(p,"name.xsss")) # 将该对象添加一个属性 # setattr(p,"id",123) # print(getattr(p,"id")) # 删除该对象的一个属性 # 删除过后,再访问该属性,报错 # delattr(p,"id") |
使用场景:
反射其实就是对属性的增删改查,但是如果直接使用内置的dict来操作,语法繁琐,不好理解
另外一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法
框架设计方式:
框架代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import importlib import settings def run(user): while True : cwd = input ( "请输入指令" ) if cwd = = "exit" : break # 判断出入的类中是否有我们输入的这个方法 if hasattr (user,cwd): # 将类中的方法通过这个方法取出来 func = getattr (user,cwd) # 执行 func() else : print ( "指令错误" ) print ( "。。。。。。" ) # 拿到用户给的路径,和模块 path = settings.path # 将路径,和模块分隔开 module_path,module_name = path.rsplit( "." , 1 ) # 通过这个调用这个方法,拿到路径对应的模块 mk = importlib.import_module(module_path) # 然后通过模块拿到里面的类 cls = getattr (mk,module_name) # 然后将类实例化 obj = cls () # 将实例化对象,传给我们写好的框架 run(obj) |
用户提供的模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 用户的类 class Wind: def cd( self ): print ( "----------cd---------" ) def de( self ): print ( "----------del---------" ) def rm( self ): print ( "----------rm---------" ) class Lniux: def cd( self ): print ( "----------cd---------" ) def de( self ): print ( "----------del---------" ) def rm( self ): print ( "----------rm---------" ) |
用户将提供的代码的位置,和类名,写入我们规定好的配置文件中,注意;格式需要严格按照我们的要求书写
1
2
|
# 用户告诉我们的路径,用字符串放在这个配置文件中 path = "model.info.Wind" |
元类 metaclass
万物皆对象,类当然也是对象
对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的
默认情况下所有类的元类都是type
学习元类的目的:
高度的自定义一个类,例如控制类的名字必须以大驼峰的方式来书写
类也是对象,也有自己的类,
我们的需求是创建类对象做一些限制
想到了初始化方法 我们只要找到类对象的类(元类),覆盖其中 init方法就能实现需求
当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求
元类中init方法
1
2
3
4
5
6
7
8
9
10
11
|
# 定义一个类,让它继承与元类type class MyType( type ):<br> # self 是类Pig这个类对象,class_name 是类的名字(注意,这个只是类的名字,不是对象,self传入的才是类对象) bases 是继承的父类以元组的形式,dict 是对象的属字典 def __init__( self ,class_name,bases, dict ): # 我们重写了元类中的init方法,要调用父类中的init方法 super ().__init__(class_name,bases, dict ) # 判断字符串是第一个字母是否是大写 if not class_name.istitle(): raise Exception( "asdasdasd" ) class Pig(metaclass = MyType): pass |
元类中call方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class MyType( type ): def __call__( self , * args, * * kwargs): print ( self ) new_args = [] for i in args: new_args.append(i.upper())<br> # 注意,当我们重写了call方法,一定要返回元类中的call方法,,还需哟将我们改过的参数一并返回给元类,用来创建对象 return super ().__call__( * new_args, * * kwargs) class Preson(metaclass = MyType): def __init__( self ,name,age): self .name = name self .age = age p = Preson( "jake" , "rose" ) print (p.name) print (p.age) |
当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身(类对象)作为第一个参数传入,以及后面的一堆参数
覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建
并返回其返回值
注意,init方法也是将这个类本身传入第一个参数
init与call使用场景:
当你想要控制对象的创建过程时,就覆盖call方法
当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作
注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class MyType( type ): def __new__( cls , * args, * * kwargs): obj = type .__new__( cls , * args, * * kwargs) return obj def __init__( self ,clss_name,bases, dict ): super ().__init__(clss_name,bases, dict ) if not clss_name.istitle(): raise Exception( "asdasdasda" ) class A(metaclass = MyType): def __init__( self ,name,age): self .name = name self .age = age # 当元类中有new方法,会直接调用new方法 # 通过type.__new__得到一个空对象 # 空对象会直接调用__init__方法 # 修改类的创建方式 # 应为第二个参数就会类的字符,我们可以通过类的支付来约束类 # 首字母是否大写,如果不是,就抛出异常 |
设计模式?用于解决某种固定问题的套路
例如:MVCMTV等
单例:指的是一个类产生一个对象
为什么要使用单例:单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
class MyType( type ): def __call__( self , * args, * * kwargs): if hasattr ( self , "obj" ): return getattr ( self , "obj" ) obj = super ().__call__( * args, * * kwargs) self .obj = obj return obj class Student(metaclass = MyType): def __init__( self ,name): self .name = name s1 = Student( "jason" ) print (s1.name) s2 = Student( "jason" ) print (s2.name) s3 = Student( "jason" ) print (s3.name) s4 = Student( "jason" ) print (s4.name) |
总结
所有的类都是元类的实例化对象
我们所学的基于对象的所有方法都有用
在init nwe call 中的self都是我们下面创建的类对象,这个类对象是元类的实例对象
posted on 2019-07-30 20:51 so_interesting 阅读(181) 评论(0) 编辑 收藏 举报