最终的阿玛格顿,螃蟹的营养价值,兽拳战队国语
import yaml 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 怎样用 metaclass 实现动态序列化 / 逆序列化功能,看其源码
#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
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
第一,所有的 python 的用户定义类,都是 type 这个类的实例。
class myclass: pass instance = myclass() print(type(instance)) # 输出 #<class '__main__.myclass'> print(type(myclass)) # 输出 #<class 'type'>
instance 是 myclass 的实例,而 myclass 不过是“上帝”type 的实例。
class myclass: data = 1 instance = myclass() print(myclass, instance) # 输出 #(__main__.myclass, <__main__.myclass instance at 0x7fe4f0b00ab8>) print(instance.data) # 输出 #1 myclass = type('myclass', (), {'data': 1}) instance = myclass() print(myclass, instance) # 输出 #(__main__.myclass, <__main__.myclass at 0x7fe4f0aea5d0>) print(instance.data) # 输出 #1
可以看出,定义myclass的时候python实际调用的是type(classname, superclasses, attributedict),就是 type 的__call__运算符重载,接着会进一步调用
type.__new__(typeclass, classname, superclasses, attributedict) type.__init__(class, classname, superclasses, attributedict)
class = type(classname, superclasses, attributedict) # 变为了 class = mymeta(classname, superclasses, attributedict)
极客时间《python 核心技术与实战》
class mymeta(type): def __init__(self, name, bases, dic): super().__init__(name, bases, dic) print('===>mymeta.__init__') print(self.__name__) print(dic) print(self.yaml_tag) def __new__(cls, *args, **kwargs): print('===>mymeta.__new__') print(cls.__name__) return type.__new__(cls, *args, **kwargs) def __call__(cls, *args, **kwargs): print('===>mymeta.__call__') obj = cls.__new__(cls) obj.testperporet = 'change' #修改子类的属性 cls.__init__(cls, *args, **kwargs) return obj class foo(metaclass=mymeta): yaml_tag = '!foo' testperporet = 'orig' def __init__(self, name): print('foo.__init__') self.name = name def __new__(cls, *args, **kwargs): print('foo.__new__') return object.__new__(cls) foo = foo('foo') print(foo.__dict__)
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
python求numpy中array按列非零元素的平均值案例
网友评论