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
)
print
(
type
(
monster1
)
)
print
(
yaml
.
dump
(
Monster
(
name
=
'Cave lizard'
,
hp
=
[
3
,
6
]
,
ac
=
16
,
attacks
=
[
'BITE'
,
'HURT'
]
)
)
上面的代码调用yaml.load(),就能把任意一个 yaml 序列载入成一个 Python Object;而调用yaml.dump(),就能把一个 YAMLObject 子类序列化。对于 load() 和 dump() 的使用者来说,他们完全不需要提前知道任何类型信息,这让超动态配置编程成了可能。
只要简单地继承 yaml.YAMLObject,就能让你的 Python Object 具有序列化和逆序列化能力。
metaclass 的超越变形特性怎么用?
YAML 怎样用 metaclass 实现动态序列化 / 逆序列化功能,看其源码
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
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
)
class
YAMLObject
(
metaclass
=
YAMLObjectMetaclass
)
:
yaml_loader
=
Loader
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
)
)
print
(
type
(
MyClass
)
)
instance 是 MyClass 的实例,而 MyClass 不过是“上帝”type 的实例。
第二,用户自定义类,只不过是 type 类的__call__运算符重载。
class MyClass:
data = 1
instance = MyClass()
print(MyClass, instance)
print(instance.data)
MyClass = type('MyClass', (), {'data': 1})
instance = MyClass()
print(MyClass, instance)
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