两句话掌握 Python 最难知识点——元类出处( 三 )


class MyList(list, metaclass=ListMetaclass):
pass
# 二生三
L = MyList()
# 三生万物
L.add(1)
现在我们打印一下L
Python
1
2
3
print(L)
>>> [1]
而普通的list没有add()方法
Python
1
2
3
4
L2 = list()
L2.add(1)
>>>AttributeError: 'list' object has no attribute 'add'
太棒了!学到这里,你是不是已经体验到了造物主的乐趣?

python世界的一切,尽在掌握 。
 
两句话掌握 Python 最难知识点——元类出处

文章插图
 
年轻的造物主,请随我一起开创新世界 。
我们选择两个领域,一个是Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM 。
这是Django的一大难点,但学完了元类,一切变得清晰 。你对Django的理解将更上一层楼!
另一个领域是爬虫领域(黑客领域),一个自动搜索网络上的可用代理,然后换着IP去突破别的人反爬虫限制 。
这两项技能非常有用,也非常好玩!
挑战一:通过元类创建ORM准备工作,创建一个Field类Python
 class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name)
它的作用是
在Field类实例化时将得到两个参数,name和column_type,它们将被绑定为Field的私有属性,如果要将Field转化为字符串时,将返回“Field:XXX”,XXX是传入的name名称 。
准备工作:创建StringField和IntergerFieldPython
 
class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)')
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint')
它的作用是
在StringField,IntegerField实例初始化时,时自动调用父类的初始化方式 。
道生一Python
 
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name=='Model':
return type.__new__(cls, name, bases, attrs)
print('Found model: %s' % name)
mappings = dict()
for k, v in attrs.items():
if isinstance(v, Field):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)
它做了以下几件事
  1. 创建一个新的字典mapping
  2. 将每一个类的属性,通过.items()遍历其键值对 。如果值是Field类,则打印键值,并将这一对键值绑定到mapping字典上 。
  3. 将刚刚传入值为Field类的属性删除 。
  4. 创建一个专门的__mappings__属性,保存字典mapping 。
  5. 创建一个专门的__table__属性,保存传入的类的名称 。
一生二Python
 
class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kwarg):
super(Model, self).__init__(**kwarg)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError("'Model' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
# 模拟建表操作
def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v.name)
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join([str(i) for i in args]))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))
如果从Model创建一个子类User:Python
 
class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
这时
id= IntegerField(‘id’)就会自动解析为:
Model.__setattr__(self, ‘id’, IntegerField(‘id’))


推荐阅读