参考文档
note_t
参考代码
preview/demo_metaclass
使用
demo_type.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/5/27 15:41
# @Author : donghuan
# @File : demo1_type.py
# @Software: PyCharm
# step1:
Test2 = type("Test2", (), {}) # 定了一个Test2类
print(Test2) # <class '__main__.Test2'>
# step2: 使用type创建带有属性的类
Foo = type('Foo', (), {'bar': True})
print(Foo)
print(Foo.bar)
# 并且可以将Foo当成一个普通的类一样使用:
f = Foo()
print(f)
print(f.bar)
# 等价于
# class Foo(object):
# bar = True
# 当然,你可以继承这个类,代码如下:
FooChild = type('FooChild', (Foo,), {})
print(FooChild)
print(FooChild.bar) # bar属性是由Foo继承而来
# 注意:
# type的第2个参数,元组中是父类的名字,而不是字符串
# 添加的属性是类属性,并不是实例属性
# step3: 使用type创建带有方法的类
class A(object):
num = 100
# 就是这样的,不是在class A中
def print_b(self):
print(self.num)
@staticmethod
def print_static():
print("----haha-----")
@classmethod
def print_class(cls):
print(cls.num)
B = type("B", (A,), {"print_b": print_b, "print_static": print_static, "print_class": print_class})
b = B()
b.print_b()
b.print_static()
b.print_class()
print(hasattr(b, "num"))
# 结果
# 100
# ----haha-----
# 100
# true
demo_metaclass1.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/5/27 19:26
# @Author : donghuan
# @File : demo2_metaclass.py
# @Software: PyCharm
"""
元类就是用来创建这些类(对象)的,元类就是类的类
type就是Python的内建元类
print(a.__class__.__class__)
# <type 'type'>
class Foo(Bar):
pass
Python做了如下的操作:
Foo中有__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象)
如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
如果还是找不到__metaclass__, Python就会用内置的type来创建这个类对象。
元类的主要目的就是为了当创建类时能够自动地改变类。
"""
# 遍历属性字典,把不是__开头的属性名字变为大写
def upper_attr(class_name, class_parents, class_attr):
print("class_name:", class_name)
print("class_parents:", class_parents)
print("class_attr:", class_attr)
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 调用type来创建一个类
return type(class_name, class_parents, new_attr)
class Foo(object, metaclass=upper_attr):
bar = 'bip'
@property
def page_offset(self):
return "page_offset"
print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))
f = Foo()
print(f.BAR)
f.page_offset = 111
print(f.page_offset)
"""
但就元类本身而言,它们其实是很简单的:
1.拦截类的创建
2.修改类
3.返回修改之后的类
元类就是深度的魔法
"""
demo_metaclass2
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/5/27 19:36
# @Author : donghuan
# @File : demo3_metaclass2.py
# @Software: PyCharm
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
def __new__(cls, class_name, class_parents, class_attr):
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 方法1:通过'type'来做类对象的创建
return type(class_name, class_parents, new_attr)
# 方法2:复用type.__new__方法
# 这就是基本的OOP编程,没什么魔法
# return type.__new__(cls, class_name, class_parents, new_attr)
# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
bar = 'bip'
# python2的用法
# class Foo(object):
# __metaclass__ = UpperAttrMetaClass
# bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'
demo_metaclass_orm.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/5/27 19:37
# @Author : donghuan
# @File : demo4_metaclass_orm.py
# @Software: PyCharm
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的格式
if isinstance(v, tuple):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
# 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k)
# 将之前的uid/name/email/password以及对应的对象引用、类名字保存
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)
class Model(object, metaclass=ModelMetaclass):
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self, k, None))
args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
# 判断入如果是字符串类型
elif isinstance(temp, str):
args_temp.append("""'%s'""" % temp)
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
print('SQL: %s' % sql)
class User(Model):
uid = ('uid', "int unsigned")
name = ('username', "varchar(30)")
email = ('email', "varchar(30)")
password = ('password', "varchar(30)")
u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()
demo_metaclass4.py
# pip install pyyaml
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)
print(yaml.dump(Monster(name=u'Cave lizard', hp=[3, 6], ac=16, attacks=[u'BITE', u'HURT'])))
# 输出
"""
!Monster
ac: 16
attacks: [BITE, HURT]
hp: [3, 6]
name: Cave
lizard
"""
result = yaml.load("""
--- !Monster
name: Cave spider
hp: [2, 6]
ac: 16
attacks: [BITE, HURT]
""", Loader=yaml.FullLoader)
print(result)
result = yaml.load("""
--- !Monster
name: Cave spider
hp: [2, 6]
ac: 16
attacks: [BITE, HURT]
""", Loader=yaml.BaseLoader)
print(result)
# yaml源码
# 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