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

文章插图
年轻的造物主,请随我一起开创新世界 。
我们选择两个领域,一个是Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM 。
这是Django的一大难点,但学完了元类,一切变得清晰 。你对Django的理解将更上一层楼!
另一个领域是爬虫领域(黑客领域),一个自动搜索网络上的可用代理,然后换着IP去突破别的人反爬虫限制 。
这两项技能非常有用,也非常好玩!
挑战一:通过元类创建ORM准备工作,创建一个Field类Python
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)
它做了以下几件事
- 创建一个新的字典mapping
- 将每一个类的属性,通过.items()遍历其键值对 。如果值是Field类,则打印键值,并将这一对键值绑定到mapping字典上 。
- 将刚刚传入值为Field类的属性删除 。
- 创建一个专门的__mappings__属性,保存字典mapping 。
- 创建一个专门的__table__属性,保存传入的类的名称 。
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’))
推荐阅读
- 首播破亿,口碑两极,《三体》能否帮B站走出“暗黑森林”?
- 丝袜两条线的在哪一边
- 16岁女生标准身高
- 马桶两个孔怎么堵图解
- 钱塘江大潮形成原因是哪两点 钱塘江大潮形成原因
- 辣椒酱的做法
- 豆瓣酱拌茄子的做法
- kamille hand cream_德国的护手霜 一个是Herbacin Wuta Kamille 俗称小甘菊 另一个就叫Kamill 这两种有啥区别
- 淘宝可以同时在两个手机上登录吗
- 湖光秋月两相和的拼音 湖光秋月两相和
