学习完了python中元类编程与数据描述符一章节,写一个demo记录学习成果。下面是一个简单的ORM模型。数据描述符还算是可以理解。就元类传递参数有__init__,new__以及__prepare。理解代码首先了解基本原理:
- __new__方法的返回值就是类的实例对象,这个实例对象会传递给 init 方法中定义的 self 参数,以便实例对象可以被正确地初始化。可以知道本例中如何使用type.__new__方法创建user对象的,
Filed = type('Filed', (object,), {})
。 - 元类基本作用:拦截类的创建,修改类,返回修改之后的类
- 也可以使用super().init(name, bases, dic)代替super().new(cls, name, bases, dic)。
class MyMetaClass(type):
def __new__(cls, name, bases, dic):
if name == 'BaseModule':
return super().__new__(cls, name, bases, dic)
fileds = {}
for key , value in dic.items():
if isinstance(value, Filed):
fileds.update({key:value})
meta_name = dic.get('Meta', None)
if meta_name is not None:
db_table = getattr(meta_name, 'db_table')
else:
db_table = name.lower()
dic['db_table'] = db_table
dic['fileds'] = fileds
return super().__new__(cls, name, bases, dic)
Filed = type('Filed', (object,), {})
class IntFiled(Filed):
def __init__(self, name, max, min):
self.storage_name = name
self.max = max
self.min = min
def __get__(self, instance, owner):
return instance.__dict__[self.storage_name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('value must be int')
if not(value > self.max or value < self.min):
raise TypeError('value must be in range {} and {}'.format(self.min, self.max))
instance.__dict__[self.storage_name] = value
class BaseModule(metaclass=MyMetaClass):
def __init__(self,**kwargs):
# for key, value in kwargs.items():
# setattr(self, key, value)
super().__init__()
class User(BaseModule):
age = IntFiled('age', 1, 100)
class Meta:
db_table = 'user'
user = User(age =20)
user.age = 10
print(user.age)
元类的单例模式:
class Singleton(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print(id(foo1))
print(id(foo2))