class Monster ( yaml . YAMLObject ) : yaml_tag = u '!Monster' def __init__ ( self , name , hp , ac , attacks ) : self . name = name self . hp = hp self . ac = ac self . attacks = attacks def __repr__ ( self ) : return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % ( self . __class__ . __name__ , self . name , self . hp , self . ac , self . attacks ) monster1 = yaml . load ( """ --- !Monster name: Cave spider hp: [2,6] # 2d6 ac: 16 attacks: [BITE, HURT] """ , Loader = yaml . Loader ) print ( monster1 ) #Monster(name='Cave spider', hp=[2, 6], ac=16, attacks=['BITE', 'HURT']) print ( type ( monster1 ) ) #<class '__main__.Monster'> print ( yaml . dump ( Monster ( name = 'Cave lizard' , hp = [ 3 , 6 ] , ac = 16 , attacks = [ 'BITE' , 'HURT' ] ) ) # dump() 返回 str # !Monster # ac: 16 # attacks: [BITE, HURT] # hp: [3, 6] # name: Cave lizard

上面的代码调用yaml.load(),就能把任意一个 yaml 序列载入成一个 Python Object;而调用yaml.dump(),就能把一个 YAMLObject 子类序列化。对于 load() 和 dump() 的使用者来说,他们完全不需要提前知道任何类型信息,这让超动态配置编程成了可能。

只要简单地继承 yaml.YAMLObject,就能让你的 Python Object 具有序列化和逆序列化能力。

metaclass 的超越变形特性怎么用?

YAML 怎样用 metaclass 实现动态序列化 / 逆序列化功能,看其源码

遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴, 互帮互助,群里还有不错的视频学习教程和PDF电子书! #Python 2/3 相同部分 class YAMLObjectMetaclass ( type ) : def __init__ ( cls , name , bases , kwds ) : super ( YAMLObjectMetaclass , cls ) . __init__ ( name , bases , kwds ) if 'yaml_tag' in kwds and kwds [ 'yaml_tag' ] is not None : cls . yaml_loader . add_constructor ( cls . yaml_tag , cls . from_yaml ) # 省略其余定义 # Python 3 class YAMLObject ( metaclass = YAMLObjectMetaclass ) : yaml_loader = Loader # 省略其余定义 # Python 2 class YAMLObject ( object ) : __metaclass__ = YAMLObjectMetaclass yaml_loader = Loader # 省略其余定义

YAMLObject 把 metaclass 都声明成了 YAMLObjectMetaclass

在你定义任何 YAMLObject 子类时,Python 会强行插入运行下面这段代码
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)

Python 底层语言设计层面是如何实现 metaclass 的?

第一,所有的 Python 的用户定义类,都是 type 这个类的实例。

遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴, 互帮互助,群里还有不错的视频学习教程和PDF电子书! class MyClass : instance = MyClass ( ) print ( type ( instance ) ) #<class '__main__.MyClass'> print ( type ( MyClass ) ) #<class 'type'>

instance 是 MyClass 的实例,而 MyClass 不过是“上帝”type 的实例。

第二,用户自定义类,只不过是 type 类的__call__运算符重载。

class MyClass:
  data = 1
instance = MyClass()
print(MyClass, instance)
#(__main__.MyClass, <__main__.MyClass instance at 0x7fe4f0b00ab8>)
print(instance.data)
MyClass = type('MyClass', (), {'data': 1})
instance = MyClass()
print(MyClass, instance)
#(__main__.MyClass, <__main__.MyClass at 0x7fe4f0aea5d0>)
print(instance.data)

可以看出,定义Myclass的时候Python实际调用的是type(classname, superclasses, attributedict),就是 type 的__call__运算符重载,接着会进一步调用

type.__new__(typeclass, classname, superclasses, attributedict)
type.__init__(class, classname, superclasses, attributedict)

第三,metaclass 是 type 的子类,通过替换 type 的__call__运算符重载机制,“超越变形”正常的类。
一旦你把一个类型 MyClass 的 metaclass 设置成 MyMeta,MyClass 就不再由原生的 type 创建,而是会调用 MyMeta 的__call__运算符重载。

class = type(classname, superclasses, attributedict) 
# 变为了
class = MyMeta(classname, superclasses, attributedict)

使用 metaclass 的风险

正如你所看到的那样,metaclass 会"扭曲变形"正常的 Python 类型模型。所以,如果使用不慎,对于整个代码库造成的风险是不可估量的。换句话说,metaclass 仅仅是给小部分 Python 开发者,在开发框架层面的 Python 库时使用的。而在应用层,metaclass 往往不是很好的选择。

本文来自博客园,作者:I'm_江河湖海,转载请注明原文链接:https://www.cnblogs.com/jhhh/p/16763660.html