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()
python中的元类_理解python中的元类相关推荐
- java中字符流 字节流_理解Java中字符流与字节流的区别
1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个"流动的方向",通常可 ...
- python中get啥意思_理解Python中的.get()方法
本问题已经有最佳答案,请猛点这里访问. sentence ="The quick brown fox jumped over the lazy dog." characters = ...
- python中加入绝对路径_理解Python中的绝对路径和相对路径
本文介绍了Python中的绝对路劲和相对路径,分享给大家,也给自己留个笔记 1.绝对路径 os.path.abspath("文件名"): 显示的是一个文件的绝对路劲 eg: > ...
- python无返回值函数_理解Python 中无返回值函数的问题
例如 list 的 append 操作就是无返回值的,换句话说就是不能进行形如 list = [] list.append(1).append(2) 这样的连续操作 注意函数返回的数据类型注意是 li ...
- python迭代器是什么意思_理解Python的迭代器
首先,廖雪峰老师的教程中解释了迭代器和生成器,这篇文章只是补充和我个人的总结. 什么是迭代 可以直接作用于for循环的对象统称为可迭代对象(Iterable). 可以被next()函数调用并不断返回下 ...
- python正则表达式是什么意思_理解python正则表达式
在python中,对正则表达式的支持是通过re模块来支持的.使用re的步骤是先把表达式字符串编译成pattern实例,然后在使用pattern去匹配文本获取结果. 其实也有另外一种方式,就是直接使用r ...
- java的弱引用_理解Java中的弱引用(Weak Reference)
本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出, ...
- 无法从套接字中获取更多数据_数据科学中应引起更多关注的一个组成部分
无法从套接字中获取更多数据 介绍 (Introduction) Data science, machine learning, artificial intelligence, those terms ...
- C# - 类_使用新成员隐藏基类成员
1 using System; 2 3 namespace 类_使用新成员隐藏基类成员 4 { 5 // 基类 : Animal 6 public class Animal 7 { 8 // 基类的普 ...
最新文章
- 一维卷积filter_面试题:CNN的卷积核是单层的还是多层的?
- 排序算法之(7)——堆排序
- mysql command line client闪一下消失
- 【今日CS 视觉论文速览】Thu, 14 Feb 2019
- vue输入框输入触发事件_.vue文件中监听input输入事件oninput详解
- 关于渲染流水线的几何变化
- webpack文件夹打包_webpack多入口文件页面打包详解
- 车险三者险可以垫付医药费吗?
- python爬虫代码示例 动态_python动态爬虫的实例分享
- C# 给picturebox添加滚动条
- 软件测试 -- 入门 4 软件测试原则
- TestNG基础教程 - IntelliJ IDEA中配置TestNG.xml, 查看TestNG Report
- office和flash计算机课程,Powerpoint和Flash制作教学课件技巧
- 计算机查询成绩微信公众号,怎么在微信公众号上设置查询成绩?
- 【HTML】【JS】【CSS】实现可移动div窗体,超出浏览器大小将返回边缘。
- GetDC() ReleaseDC()引起的内存泄漏
- GNSS原理及技术(三)——差分定位技术
- python 1、输入a,b,c解二元一次方程;2、克莱姆法则解线性方程;3、输入今天之后未来的天数,显示今天是星期几;4、输入一个数,检测是否能被5和6整除;5、输入人民币和美元的汇率和转换金额;
- 手机App开发的基础概念
- 黄芽菜和大白菜的区别 黄芽菜的做法
热门文章
- MySQL5.5.27使用Restore From SQL Dump功能导入数据库表中出现Row size too large
- oracle生成存储过程示例,oracle创建简单存储过程示例
- 离散方程式matlab,matlab离散型数据拟合方程,求系数,哪个大神能说说方法
- android怎么查看方法被谁调用,Android中查看布局文件中的控件(view,id)在哪里被调用(使用)...
- php hashids思路,使用composer添加hashids加密数字
- sqlserver varchar 对于 sum 运算符无效_在sqlserver上实现自定义函数四舍六入五成双...
- taskkill 命令:
- MySQL 8数据导入 MySQL 5.7
- Git master branch has no upstream branch的解决
- IDEA本地项目与SVN项目关联