python中的元类_理解python中的元类

一,理解类也是对象

在python中类同样也是一种对象,只要使用关键字class,Python解释器在执行的时候就会创建一个对象,这个对象(类)自身拥有创建对象(类实例)的能力,这就是为什么他是一个类的原因,但是,他的本质任然是一个对象。

classobjectCreator(object):passmy_object=objectCreator()print(my_object) #可以打印一个类,因为他其实就是一个对象

def echo(obj): #可以将类作为参数传给函数

print(obj)

echo(objectCreator)

objectCreator.new_attribute= "foo" #可以增加属性

print(hasattr(objectCreator, "new_attribute"))

objectCreatorMirror= objectCreator #可以赋值给你个变量

print(objectCreatorMirror())

二,动态地创建类

1,通过return class动态的构建需要的类

因为类也是对象,你可以在运行时动态的创建他们,就像他们任何对象一样,首先,你可以在函数中创建类,使用class关键字即可。

defchoose_class(name):if name == "foo":classFoo(object):pass

returnFooelse:classBar(object):pass

returnBar

MyClass= choose_class("foo")print(MyClass) #返回是类,不是类的实例

print(MyClass()) #类的创建

2,通过type函数构造类,重新认识不一样的type

type可以动态创建类。type可以接受一个类的描述作为参数, 然后返回一个类。

type的语法:

type(类名,父类的元祖(针对继承的情况,可以为空), 包含属性的字典(名称和值))

如下代码:

classMyShinClass(object):pass

可以手动通过type创建,其实

MyShinyClass = type("MyShinyClass", (), {}) #返回一个类对象

print(MyShinyClass)

print(MyShinClass())

type创建类的范例:

1, 构建Foo类classFoo(object):

bar=True

Foo= type("Foo", (), {"bar": True})2, 继承Foo类classFooChild(Foo):passFooChild= type("FooChild", (Foo,), {})#3, 为FooChild类增加方法

defecho_bar(self):print(self.bar)

FooChild= type("FooChild", (Foo,), {"echo_bar": echo_bar})print(hasattr(FooChild, "echo_bar"))

my_foo=FooChild()

my_foo.echo_bar()

可以看到,在python中,类也是对象,你可以动态的创建类。这就是当我们使用关键字class时python在幕后做的事情,而这就是通过元类实现的

三,元类

1,什么时元类

通过上文的描述,可以得到python中的类也是对象,元类就是用来创建这些类(对象)的。元类就是类的类。

函数type实际上就是一个元类,type就是python在背后用来创建所有类的元类。

元类就是创建类这种对象的东西。type就是python的内建元类,当然了,你也可以创建自己的元类

2, __metaclass__属性

可以在写一个类的时候为其添加__metaclass__属性,定义了__metaclass__就定义了这个类的元类

classFoo(object):__metaclass__ =somethingclass Foo(metaclass=something):__metaclass__ = something

例如:如下代码

classFoo(Bar):pass

在该类并定义的时候,他还没有在内存中生成,直到他被调用,Python做了如下的操作:

1)Foo中有__mataclass__这个属性吗?如果有,python会在内存中通过__metaclass__创建一个名字为Foo的类对象

2)如果Python没有找到__metaclass__,他就会在父类中寻找__metaclass__属性,并尝试做同样的操作。

3)如果Python没有找到__metaclass__,他就会在模块层中寻找__metaclass__,并尝试做同样的操作。

4)如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象

三,自定义元类

元类的主要目的就是当创建类的时候能自动地改变类,通常,你会为API做这样的事情, 你希望可以创建符合上下文的类。假象一个你的模块里所有累的属性都应该是大写形式,有好几种方法可以办到,但其中一种就是通过设定__metaclass__。采用这种方法,这个模块中所有的类都会通过这个元类创建。我们只需要告诉元类吧所有的属性都改成大写形式就万事大吉

classUpperAttrMetaClass(type):def __new__(cls, name, bases, dic):#获取传入的属性值

attrs = ((name, value) for name, value in dic.items() if not name.startswith("__"))#将属性值变成大写,转换成字典

uppercase_attr = dict((name.upper(), value) for name, value inattrs)return type.__new__(cls, name, bases, uppercase_attr)#python3之后必须这样写

class Foo(metaclass=UpperAttrMetaClass):

bar= "bip"f=Foo()print(hasattr(Foo, 'bar')) #False

print(hasattr(Foo, 'BAR')) #True

2,使用class来当作元类

由于__metaclass__必须返回一个类

四,使用__new__方法和元类方式分别实现单例模式

classSingleton(type):def __init__(self, *args, **kwargs):print("__init__")

self._instance=None

super(Singleton, self).__init__(*args, **kwargs)def __call__(self, *args, **kwargs):print("__call__")if self._instance isNone:

self._instance= super(Singleton, self).__call__(*args, **kwargs)returnself._instanceclass Foo(metaclass=Singleton):passfoo1=Foo()

foo2=Foo()print(Foo.__dict__)print(foo1 isfoo2)#__init__#__call__#__call__

#{'__module__': '__main__', '__dict__': ,#'__weakref__': , '__doc__': None,#'_instance': <__main__.Foo object at 0x102a034e0>}

#True

基于这个例子:

我们知道元类生成的实例是一个类,而这里我们仅仅需要对这个实例增加一个属性来判断和保存生成的单例。

关于__call__方法的调用,因为Foo是Singleton的一个实例,所以Foo()这样的方式就调用了Singleton的__call__方法。

实现:

定义一个元类方法,实现函数方法的扩展自动识别,加入类方中中

classMetaClassTest(type):def __new__(cls, name, bases, attrs):

count=0

attrs["__FuncTest__"] =[]for k, v inattrs.items():if "Chen_" ink:

attrs["__FuncTest__"].append(k)

count+= 1attrs["__FuncCount__"] =countreturn type.__new__(cls, name, bases, attrs)class MainTest(object, metaclass=MetaClassTest):defget_data(self, callback):ifhasattr(self, callback):

result=getattr(self, callback)()print(result, "执行完毕~~~")#以后只要每次扩展Chen_开头的函数,就会自动执行。

defChen_Run(self):return "Chenrun"

defChen_Peng(self):return "ChenPeng"

defrun():

obj=MainTest()for func in range(obj.__FuncCount__):

obj.get_data(callback=obj.__FuncTest__[func])if __name__ == '__main__':

run()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值