python 3 黑色魔法元类初探
最近读django源码,发现必须了解元类才能理解一些很神奇的行为.
发现元类实际上是控制class的创建过程.比如类B继承某个看似平淡无奇的类A之后,你在类B中定义的属性或方法可能会遭到彻底改变.
假设我们想实现这么一种需求:
创建一个类Child,在这个类中定义的种种字符串属性,都可以当做对应的函数那样调用.例如:
class Child():
f1='print'
随后,Child.f1就完全和内建函数print等价了.Child.f1('abc')能够打印出abc这个字符串.
这样来说,元类的用途看起来可以是:一些高手设计了一个在幕后做了很多工作的元类,另一些开发人员只需要简单地继承这个元类或者这个元类的子类,敲几个属性定义的代码,就能实现很多复杂的功能.django就是这样的.比如它的model.Models就充分利用了这种魔法.
下面从代码层面展示元类具体是怎么运作的:
class MyMeta(type):
def __new__(cls, name, parents, attrs):
for k,v in locals().items():
if isinstance(v,dict):
for k2,v2 in v.items():
print(k,'|',k2,'|',type(v2),'|',v2)
else:
print(k,'|',v)
return type.__new__(cls, name, parents, attrs) class Parent1(type):
pass class Parent2(object):
pass class Parent3():
pass class AbstractChild(Parent1,Parent2,Parent3,metaclass=MyMeta):
pass class Child(AbstractChild): f1 = 1
f2 = sorted
f3 = int class classinchild():
pass @staticmethod
def stcm():
pass @classmethod
def clsm(cls):
pass def insm(self):
pass print('-'*60) class EvalMeta(type):
def __new__(cls, name, parents, attrs):
new_attrs={}
for k,v in attrs.items():
if not k.startswith('__') and isinstance(v,str):
new_attrs[k] = eval(v)
else:
new_attrs[k] = v
return type.__new__(cls, name, parents, new_attrs) class AbstractChild(metaclass=EvalMeta):
pass class Child(AbstractChild):
f1='print'
f2='sorted' if __name__=='__main__':
x=Child()
x.f1('invoke f1 as print function')
print('invoke f2 as sorted function:',Child.f2([3,2,1]))
结果:
>>>
name | AbstractChild
cls | <class '__main__.MyMeta'>
parents | (<class '__main__.Parent1'>, <class '__main__.Parent2'>, <class '__main__.Parent3'>)
attrs | __module__ | <class 'str'> | __main__
attrs | __qualname__ | <class 'str'> | AbstractChild
name | Child
cls | <class '__main__.MyMeta'>
parents | (<class '__main__.AbstractChild'>,)
attrs | stcm | <class 'staticmethod'> | <staticmethod object at 0x0000000003075C50>
attrs | clsm | <class 'classmethod'> | <classmethod object at 0x000000000309CA58>
attrs | __module__ | <class 'str'> | __main__
attrs | insm | <class 'function'> | <function Child.insm at 0x0000000003139400>
attrs | __qualname__ | <class 'str'> | Child
attrs | f1 | <class 'int'> | 1
attrs | f3 | <class 'type'> | <class 'int'>
attrs | f2 | <class 'builtin_function_or_method'> | <built-in function sorted>
attrs | classinchild | <class 'type'> | <class '__main__.Child.classinchild'>
------------------------------------------------------------
invoke f1 as print function
invoke f2 as sorted function: [1, 2, 3]
>>>
python 3 黑色魔法元类初探的更多相关文章
- python基础——使用元类
python基础——使用元类 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello. ...
- Python基础:元类
一.概述 二.经典阐述 三.核心总结 1.类的创建过程 2.元类的使用惯例 四.简单案例 1.默认行为 2.使用元类 五.实践为王 一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯 ...
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 什么是python中的元类
所属网站分类: python高级 > 面向对象 作者:goodbody 原文链接: http://www.pythonheidong.com/blog/article/11/ 来源:python ...
- Python之面向对象元类
Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...
- [Python之路] 元类(引申 单例模式)
一.类也是对象 当我们定义一个变量或者函数的时候,我们可以在globals()的返回值字典中找到响应的映射: def A(): print("This is function A" ...
- Python 中的元类到底是什么?这篇恐怕是最清楚的了
类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...
- Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法
Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 目录 Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 1. 元类type 2. 反射 3 ...
随机推荐
- ES6 new syntax of let and const (one)
variable declarations : let, const,and block scope why we redefine the way about declarations? funct ...
- [LeetCode] Kill Process 结束进程
Given n processes, each process has a unique PID (process id) and its PPID (parent process id). Each ...
- [ZJOI 2008]泡泡堂BNB
Description 题库链接 双方 \(n\) 人,给出每人的战斗力,赢一场加 \(2\) 分,平局 \(1\) 分,失败不得分.求最大和最小的得分. \(1\leq n\leq 100000\) ...
- [HNOI 2016]网络
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
- Fliptile 翻格子游戏
问题 B: [Usaco2007 Open]Fliptile 翻格子游戏 时间限制: 5 Sec 内存限制: 128 MB 题目描述 Farmer John knows that an intell ...
- 【LSGDOJ 1333】任务安排 dp
题目描述 N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti.在每批任务开始 ...
- hdu 5463(水水)
Sample Input 2 3 2 33 3 33 2 33 10 5 467 6 378 7 309 8 499 5 320 3 480 2 444 8 391 5 333 100 499 S ...
- Qone 正式开源,使 javascript 支持 .NET LINQ
Qone 下一代 Web 查询语言,使 javascript 支持 LINQ Github: https://github.com/dntzhang/qone 缘由 最近刚好修改了腾讯文档 Excel ...
- Java transient关键字使用小结
1.transient关键字只能修饰变量,而不能修饰方法和类.注意,本地变量是不能被transient关键字修饰的.2.被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被t ...
- JNI 方法注册与签名+BufferedReader使用readLine问题
最近了解了关于JavaJNI接口的一些关于方法注册与签名相关的知识,在此进行一下总结. 使用JNI接口时,我们首先需要把Java方法声明为native: public native void f(); ...