本博文通过对以下链接进行理解后,编写。

https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python

1. 类

类也是对象,具有对象的特点:

  • 你可以将它赋值给变量
  • 你可以copy它
  • 你可以给它添加属性
  • 你可以把它作为函数参数进行传递

类定义语法:

class Foo(object): pass

说明:
1. 这是一种语法糖,一种对类对象的声明方式,与def func, a = 123, 本质上没有区别,都是为了创建一个对象。
2. 对象的创建都关联到一个类,比如 a = 123 关联的类是 'int', b = 'hello' 关联的类是 'str', def func(): pass 关联的类是 'function', 而 class Foo(object): pass 关联的类就是元类 'metaclass', 默认为 'type'

对象重要特性:动态创建,你可以随时随地在你需要的地方创建对象,类也可以动态创建。

2. 动态创建

根据函数参数来创建类,看起来像是类工厂,但是动态性不够。

def choose_class(name):
if name == 'foo':
class Foo(object): pass
return Foo # return the class, not an instance
else:
class Bar(object): pass
return Bar >>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>

真正的动态创建,是通过元类(默认type类构造函数)来创建:

# 创建类
>>> Foo = type('Foo', (), {'bar':True})
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True # 创建子类
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True # 给子类分配实例方法
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True # 再分配一个实例方法
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True

3. 动态创建语法糖

为此 python 语言本身又提供了一个语法糖,在声明类的时候,就指定后台自动创建这个类的方法,方法就是 __metaclass__ 变量(python2.7), metaclass=xxx(python3.x)。示例:

# 文件保存为:mymetaclass.py
# 执行 python2 metaclass.py def upper_attr(name, parents, attributes):
new_attributes = {}
for n, v in attributes.items():
if not n.startswith('__'):
uppercase_attr[n.upper()] = v
else:
uppercase_attr[n] = v
return type(name, parents, new_attributes) __metaclass__ = upper_attr # py3这个无法工作 class Foo(): # py3,需要使用这个语法:class Foo(metaclass=upper_attr):
bar = 'bip' def __init__(self):
self.link = "link"
def func(self):
print("Enter func") # 类属性,函数都被转换为大写了
print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True print(hasattr(Foo, 'func')) # False
print(hasattr(Foo, 'FUNC')) # True # 元类转换了类属性,但是没有转换实例属性, __init__ 内的变量没有被转换
print(hasattr(Foo, 'link')) # False
print(hasattr(Foo, 'LINK')) # False print(hasattr(Foo(), 'link')) # True
print(hasattr(Foo(), 'LINK')) # False

以上使用的是函数作为元类实现方式,也可以直接使用类作为元类,元类中实现的是 __new__ 方法,在生成类对象之前会被调用的方法即为 __new__ 方法。而不是 __init__ 方法, __init__ 方法是操作的类对象返回之后,创建的实例对象的初始化行为。

# metaclass 控制的是 __new__ 方法,而不是 __init__ 方法
class UpperAttrMetaclass(type):
def __new__(cls, name, parents, attributes):
new_attributes = {}
for n, v in attributes.items():
if not n.startswith('__'):
new_attributes[n.upper()] = v
else:
new_attributes[n] = v
#以下返回值推荐使用super方法,对当前示例两者效果相同,使用super可以使
#当前元类能够继承其他元类
#return type.__new__(cls, name, parents, new_attributes)
#return super(UpperAttrMetaclass, cls).__new__(cls, name, parents, new_attributes)
return type.__new__(cls, name, parents, new_attributes) class Foo(object, metaclass=upper_attr):
bar = 'bip'
def __init__(self):
self.link = "link"
def func(self):
print("Enter func") # 效果与使用函数的元类实现一致!!!
# 类属性,函数都被转换为大写了
print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True print(hasattr(Foo, 'func')) # False
print(hasattr(Foo, 'FUNC')) # True # 元类转换了类属性,但是没有转换实例属性, __init__ 内的变量没有被转换
print(hasattr(Foo, 'link')) # False
print(hasattr(Foo, 'LINK')) # False print(hasattr(Foo(), 'link')) # True
print(hasattr(Foo(), 'LINK')) # False

4. 写作最后

99%用户用不到元类,所以大家洗洗睡吧,了解就行。

[TimLinux] Python 再谈元类 metaclass的更多相关文章

  1. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  2. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  3. python中的元类metaclass

    本文是一个转载的,因为原文写的太好了,所以直接copy过来吧. 原文请看:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上 很热的帖子.提问 ...

  4. 深刻理解Python中的元类metaclass(转)

    本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...

  5. 深刻理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  6. [转] 深刻理解Python中的元类(metaclass)

    非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...

  7. 深刻理解Python中的元类(metaclass)【转】

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  8. 深入理解Python中的元类(metaclass)

    原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...

  9. python——深刻理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉 ...

随机推荐

  1. html5 微信真机调试方法vConsole

    html5 微信真机调试方法 vConsolehttps://blog.csdn.net/weixin_36934930/article/details/79870240

  2. Hazel,自动整理文件,让你的 Mac 井井有条

    原文地址 https://sspai.com/post/35225 让我们从实际需求出发,看看问题出在哪里,并在此基础上认识和学习使用 Hazel. 电脑随着使用时间的增长,其中的文件也在疯狂的增长, ...

  3. C# IV: 数据库基础操作2

    需上一篇C# III:数据库基础操作 另外一个经常碰到的数据库操作是,单次执行多个SQL语句,譬如,一次性插入多条数据. 方法一,拼凑长SQL语句 拼凑长SQL语句实际上是String的操作.如下示例 ...

  4. [Bootstrap] Bootstrap学习笔记

    1.因为bootstrap用到了html5的特性,为了正常使用,需要在最开头加上<!DOCTYPE html> 2.Bootstrap需要JQuery才能正常工作,所以需要导入jquery ...

  5. PowerMock学习之PoweMock的入门(二)

    前言 在上一篇<PowerMock学习之PoweMock的入门(一)>文章中,已经简单提及一些关于powermock的用法,但是入门还未完,我还要坚持把它学习并坚持更新到博客中. Mock ...

  6. nyoj 208 + poj 1456 Supermarket (贪心)

    Supermarket 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 A supermarket has a set Prod of products on sal ...

  7. PHP的global和$GLOBALS的区别

    global是关键字,通常添加在变量前,可以使变量的作用域为全局. $GLOBALS预定义的超全局变量,把变量扔到里面一样可以变成全局变量. $GLOBALS 是一个关联数组,每一个变量为一个元素,键 ...

  8. TreeMap的源码学习

    TreeMap的源码学习 一).TreeMap的特点 根据key值进行排序. 二).按key值排序的两种排序算法实现 1).在构造方法中传入比较器 public TreeMap(Comparator& ...

  9. Python3 之 with语句(高效、便捷)

    在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要python3 with出场了,with能够对这样的需求进行一个比较优雅的处理,最常用的例子就是对访问文件的处理. 文 ...

  10. 小白学习python第一天,Pycharm破解与用法(持续更新)

    目录 Pycharm安装与破解及汉化 Pycharm安装 Pycharm破解 Pycharm汉化 Pycharm使用 添加作者.时间等信息 补充 @ Pycharm安装与破解及汉化 本人最近开始找到了 ...