理解python中的元类
一,理解类也是对象
在python中类同样也是一种对象,只要使用关键字class,Python解释器在执行的时候就会创建一个对象,这个对象(类)自身拥有创建对象(类实例)的能力,这就是为什么他是一个类的原因,但是,他的本质任然是一个对象。
class objectCreator(object):
pass my_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关键字即可。
def choose_class(name):
if name == "foo":
class Foo(object):
pass return Foo
else:
class Bar(object):
pass return Bar MyClass = choose_class("foo")
print(MyClass) # 返回是类,不是类的实例 print(MyClass()) # 类的创建
2,通过type函数构造类,重新认识不一样的type
type可以动态创建类。type可以接受一个类的描述作为参数, 然后返回一个类。
type的语法:
type(类名,父类的元祖(针对继承的情况,可以为空), 包含属性的字典(名称和值))
如下代码:
class MyShinClass(object):
pass
可以手动通过type创建,其实
MyShinyClass = type("MyShinyClass", (), {}) # 返回一个类对象
print(MyShinyClass)
print(MyShinClass())
type创建类的范例:
1, 构建Foo类
class Foo(object):
bar = True Foo = type("Foo", (), {"bar": True}) 2, 继承Foo类
class FooChild(Foo):
pass FooChild = type("FooChild", (Foo,), {}) # 3, 为FooChild类增加方法
def echo_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__就定义了这个类的元类
class Foo(object):
__metaclass__ = something class Foo(metaclass=something):
__metaclass__ = something
例如:如下代码
class Foo(Bar):
pass
在该类并定义的时候,他还没有在内存中生成,直到他被调用,Python做了如下的操作:
1)Foo中有__mataclass__这个属性吗?如果有,python会在内存中通过__metaclass__创建一个名字为Foo的类对象
2)如果Python没有找到__metaclass__,他就会在父类中寻找__metaclass__属性,并尝试做同样的操作。
3)如果Python没有找到__metaclass__,他就会在模块层中寻找__metaclass__,并尝试做同样的操作。
4)如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象
三,自定义元类
元类的主要目的就是当创建类的时候能自动地改变类,通常,你会为API做这样的事情, 你希望可以创建符合上下文的类。假象一个你的模块里所有累的属性都应该是大写形式,有好几种方法可以办到,但其中一种就是通过设定__metaclass__。采用这种方法,这个模块中所有的类都会通过这个元类创建。我们只需要告诉元类吧所有的属性都改成大写形式就万事大吉
class UpperAttrMetaClass(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 in attrs) 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__方法和元类方式分别实现单例模式
class Singleton(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 is None:
self._instance = super(Singleton, self).__call__(*args, **kwargs)
return self._instance class Foo(metaclass=Singleton):
pass foo1 = Foo()
foo2 = Foo() print(Foo.__dict__)
print(foo1 is foo2) # __init__
# __call__
# __call__ # {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>,
# '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None,
# '_instance': <__main__.Foo object at 0x102a034e0>} # True
基于这个例子:
我们知道元类生成的实例是一个类,而这里我们仅仅需要对这个实例增加一个属性来判断和保存生成的单例。
关于__call__方法的调用,因为Foo是Singleton的一个实例,所以Foo()这样的方式就调用了Singleton的__call__方法。
实现:
定义一个元类方法,实现函数方法的扩展自动识别,加入类方中中
class MetaClassTest(type):
def __new__(cls, name, bases, attrs):
count = 0
attrs["__FuncTest__"] = []
for k, v in attrs.items():
if "Chen_" in k:
attrs["__FuncTest__"].append(k)
count += 1
attrs["__FuncCount__"] = count return type.__new__(cls, name, bases, attrs) class MainTest(object, metaclass=MetaClassTest): def get_data(self, callback):
if hasattr(self, callback):
result = getattr(self, callback)()
print(result, "执行完毕~~~") # 以后只要每次扩展Chen_开头的函数,就会自动执行。
def Chen_Run(self):
return "Chenrun" def Chen_Peng(self):
return "ChenPeng" def run():
obj = MainTest()
for func in range(obj.__FuncCount__):
obj.get_data(callback=obj.__FuncTest__[func]) if __name__ == '__main__':
run()
理解python中的元类的更多相关文章
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- 深入理解Python中的元类(metaclass)
原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...
- 深度理解python中的元类
本文转自:(英文版)https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python (翻译版) http:// ...
- python——深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉 ...
- 理解 Python 中的元类
本文编程环境:Jupyter NoteBook python3 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在 Python 中这一点仍然成立: class Objec ...
随机推荐
- 洛谷P2192HXY玩卡片
题目大意 给你n个数,只包括5和0. 从中取一些数,要求组成的数是90的倍数. 如: 4 5 0 5 0 结果是0 题解 90=9*10,如果一个是90的倍数一定末尾有0,那么这个 数一定是10的倍数 ...
- 相对导入中Attempted relative import in non-package问题
这一篇应该是解释的比较清楚: http://stackoverflow.com/questions/14664313/attempted-relative-import-in-non-package- ...
- 看了redis想一下
redis总结 要想在python中使用redis,要先在本地安装redis,并开启redis-server,然后再导入python的redis包,pip install redis 怎么在Linux ...
- [LeetCode系列] 二叉树最大深度求解问题(C++递归解法)
问: 给定二叉树, 如何计算二叉树最大深度? 算法描述如下: 如果当前节点为空, 返回0(代表此节点下方最大节点数为0) 如果当前节点不为空, 返回(其左子树和右子树下方最大节点数中的最大值+1) 上 ...
- 搭建Spring Cloud+Dubbo
公司要测试一下zipkin是否可以跟踪全流程,项目的架构比较复杂,不要问我为什么,基本架构如下:前端门户,调用spring cloud组件,spring cloud在调用dubbo,这样一套流程.于是 ...
- B-tree & B+tree & B*Tree 结构浅析——转
转自http://www.cnblogs.com/coder2012/p/3330311.html http://blog.sina.com.cn/s/blog_6776884e0100ohvr.ht ...
- 常见企业IT支撑【5、内网DNS cache轻量服务dnsmasq】
可参考http://www.centoscn.com/CentosServer/dns/2014/0113/2355.html 布署keepalive高可用方式 此方案只适合小型企业,规模少的情况下使 ...
- ShowDialog窗体的return问题
最近的一个项目里,打开新窗口用到了ShowDialog()这种方式,发现在新窗口做保存操作的时候,保存按钮事件下的程序执行完(无论有没有return)都会关闭子窗口. 网上查了一下,发现大家说的方法在 ...
- python 冒泡排序,二分法
a = 0 lst = [13,5,1,7,2,6,4,5,6] while a < len(lst): # 控制次数 for i in range(len(lst)-1): if lst[i] ...
- Java-Runoob-高级教程:Java 实例
ylbtech-Java-Runoob-高级教程:Java 实例 1.返回顶部 1. Java 实例 本章节我们将为大家介绍 Java 常用的实例,通过实例学习我们可以更快的掌握 Java 的应用. ...