设为首页 收藏本站
查看: 711|回复: 0

[经验分享] Python-深入理解元类(metaclass)

[复制链接]

尚未签到

发表于 2015-11-30 08:45:26 | 显示全部楼层 |阅读模式
  1.使用 type 动态创建类(type 是一个类, 用来创建类对象的元类, 所以也可以继承)



type("Person", (), {"name": "John"})
  2.元类
  Python 中类也是对象, 元类就是创建这些类对象的类, 可以理解为



MyClass = MetaClass()
MyObject = MyClass()
  3.type实际上是一个元类, type就是Python在背后用来创建所有类的元类, 类似 str 是创建字符串对象的类, int 是创建整数的类, type 就是创建类的类
  4.Python 中所有东西都是对象!



>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>>foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
  那么对于任何一个 __class__ 的 __class__ 属性又是什么呢?



>>> a.__class__.__class__
<type 'type'>
>>> age.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
  结论: 元类就是创建类这种对象的东西, type就是Python的内建元类(xx.__class__.__class__为 type )
  5.__metaclass__ 属性
  可以在写一个类的时候为其添加 __metaclass__ 属性



class Foo(object):
__metaclass__ = something…
  pass
  如果你这么做了, Python就会用元类来创建类Foo, 小心点, 这里面有些技巧, 你首先写下class Foo(object), 但是类对象Foo还没有在内存中创建, Python会在类的定义中寻找__metaclass__属性, 如果找到 了, Python就会用它来创建类Foo, 如果没有找到, 就会用内建的type来创建这个类
  6.深入理解下上一步中的 __metaclass__



class Foo(Bar):
pass
  Foo中有__metaclass__这个属性吗?如果是, Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象, 请紧跟我的思路), 如果Python没有找到__metaclass__, 它会继续在Bar(父类)中寻找__metaclass__ 属性, 并尝试做和前面同样的操作, 如果Python在任何父类中都找不到__metaclass__, 它就会在模块层次中去寻找 __metaclass__, 并尝试做同样的操作, 如果还是找不到__metaclass__, Python就会用内置的type来创建这个类对象
  现在的问题就是, 你可以在__metaclass__中放置些什么代码呢?答案就是: 可以创建一个类对象的东西, 那么什么可以用来创建一个类呢?type, 或者任何使用到type或者子类化type的东东都可以(像1中使用type创建类对象)
  7.自定义元类
  条件:模块里所有的类的属性都应该是大写形式
  实现(__metaclass__实际上可以被任意调用, 它并不需要一定是一个正式的类):



# 元类会自动将你通常传给‘type’的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
'''返回一个类对象,将属性都转为大写形式'''
#  选择所有不以'__'开头的属性
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
# 将它们转为大写形式
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
# 通过'type'来做类对象的创建
return type(future_class_name, future_class_parents, uppercase_attr)
__metaclass__ = upper_attr  #  这会作用到这个模块中的所有类
class Foo(object):
# 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中
bar = 'bip'
print hasattr(Foo, 'bar')
# 输出: False
print hasattr(Foo, 'BAR')
# 输出:True

f = Foo()
print f.BAR
# 输出:'bip'
  用OOP实现:



# 请记住,'type'实际上是一个类,就像'str'和'int'一样
# 所以,你可以从type继承
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return type(future_class_name, future_class_parents, uppercase_attr)
  8.为什么要使用元类?
  现在回到我们的大主题上来, 究竟是为什么你会去使用这样一种容易出错且晦涩的特性?好吧, 一般来说, 你根本就用不上它:
  “元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”  —— Python界的领袖 Tim Peters
  元类的主要用途是创建API, 一个典型的例子是Django ORM, 它允许你像这样定义:



class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
  但是如果你像这样做的话:



guy  = Person(name='bob', age='35')
print guy.age
  这并不会返回一个IntegerField对象, 而是会返回一个int, 甚至可以直接从数据库中取出数据, 这是有可能的, 因为 models.Model定义了__metaclass__, 并且使用了一些魔法能够将你刚刚定义的简单的Person类转变成对数据库的一个复杂hook, Django框架将这些看起来很复杂的东西通过暴露出一个简单的使用元类的API将其化简, 通过这个API重新创建代码, 在背后完成真正的工作
  9.小结
  Python中的一切都是对象, 它们要么是类的实例, 要么是元类的实例, 除了type, type实际上是它自己的元类
  摘抄自:http://python.jobbole.com/21351/

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-145119-1-1.html 上篇帖子: Python——hashlib 下篇帖子: python 列表与元组的操作简介
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表