Python元类的使用

前言

本文以廖雪峰网页的元类示例为基础,进行一些补充注解,原文参见文末链接。

使用type()创建类

def fn(self, name="word"):
	print("hello, %s" % name)


Hello = type('Hello', (object, ), dict(hello=fn))

type()依次接收3个参数

  1. class名称
  2. 继承的父类的集合, 如果只有一个父类,注意tuple的单元素写法
  3. class的方法名称与函数绑定

MetaClass

定义类的时候要显式指明metaclass=xxx

这样会指示python解释器在创建类时,调用xxxMetaclass.__new__()来创建

class ListMetaclass(type):
	def __new__(cls, name, bases, attrs):
		attrs['add'] = lambda self, value: self.append(value)
		return type.__new__(cls, name, bases, attrs)

__new__()接收

  1. 当前准备创建的对象 cls
  2. 类名
  3. 类继承的父类集合
  4. 类的方法集合

ORM(Object Relational Mapping)

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)


class StringField(Field):
	def __init__(self, name):
		super(StringField, self).__init__(name, 'varchar(1000)')


class IntegerField(Field):
	def __init__(self, name):
		super(IntegerField, self).__init__(name, 'bigint')


class ModelMetaclass(type):
	def __new__(cls, name, bases, attrs):
		if name == 'Model':
			# 先在User中找Meta, 没有找到
			# 然后到父类Model里找, 发现可以找到
			# 就会使用Model的MetaClass先初始化User()
			# 因为在本例中MetaClass不打算修改Model, 所以要在代码中排除掉Model
			return type.__new__(cls, name, bases, attrs)
		print('Found model: %s' % name)
		mappings = dict()
		'''
		attr = {
		'__module__': '__main__', 
		'__qualname__': 'User', 
		'id': <__main__.IntegerFieldobject at 0x00000000028094E0>, 
		'name': <__main__.StringField object at 0x0000000002809518>, 
		'email': <__main__.StringField object at 0x00000000028094A8>, 
		'password': <__main__.StringField object at 0x0000000002809550>}
		'''
		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)  # 此时只剩__module__ 和 __qualname__
		attrs['__mappings__'] = mappings
		attrs['__table__'] = name  # 类名
		return type.__new__(cls, name, bases, attrs)


class Model(dict, metaclass=ModelMetaclass):

	def __init__(self, **kw):
		super(Model, self).__init__(**kw)

	def __getattr__(self, key):
		try:
			return self[key]
		except KeyError:
			raise AttributeError(r"'Model' object has no attribute '%s'" % key)

	def __setattr__(self, key, value):  # 注释了也行,没用到
		self[key] = value

	def save(self):
		fields = []
		params = []
		args = []
		for k, v in self.__mappings__.items():
			fields.append(v.name)  # id, username, email, password
			params.append('?')
			args.append(getattr(self, k, None))
		sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
		print('SQL: %s'%sql)
		print('ARGS: %s'%str(args))


class User(Model):
	id = IntegerField('id')  #
	name = StringField('username')
	email = StringField('email')
	password = StringField('password')

u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()
# out:
Found model: User
Found mapping: id ==> <IntegerField:id>
Found mapping: name ==> <StringField:username>
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
SQL: insert into User (id,username,email,password) values (?,?,?,?)
ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']

引用

https://www.liaoxuefeng.com/wiki/1016959663602400/1017592449371072

原文地址:https://www.cnblogs.com/sayiqiu/p/10968234.html