当前位置:网站首页>Metaclass type and using metaclass to implement model class ORM
Metaclass type and using metaclass to implement model class ORM
2022-07-02 10:15:00 【chuntian_ tester】
Python The built-in metaclass in is :type
type: It's a metaclass , All classes are passed through type created .
object: Top level base class , The top-level parent class of the inheritance of all classes is boject.
It can be done by class To define a class , It can also be done through type To define a class .
type(name,bases,attr_dict) call type():
name: Specify class name , Will become the name attribute .
bases: Specify the ancestor of the base class of the inherited class , Will become the bases attribute .
attr_dict: Specify the namespace dictionary that contains the class body definition , Will become the dict attribute .
"""
type Create class three parameters :
1. Name :str
2. Inherited parent class :tupe
3. Properties and methods : Dictionaries , Express attributes and methods in the form of key value pairs
"""
# type Create method :
def func(self):
print('--- Add methods to metaclasses ----')
Test = type('Test999', (object,), {'name': " Springfield ", 'age': 4, "function666": func})
class Info(object):
attr = 100
__attr1 = 200
if __name__ == '__main__':
t = Test()
i = Info()
print(Test) # <class '__main__.Test999'>
print(Info) # class '__main__.Info'>
print(t) # <__main__.Test999 object at 0x7fb5400b7e20>
print(i) # <__main__.Info object at 0x7fb5400b7eb0>
# Look at the parent class
print(Test.__base__) # <class 'object'>
# View the current file path
print(__file__) # /Users/jeanettian/PycharmProjects/demo/dataType/ The metaclass Type.py
# Judgment type
print(isinstance(t,Test)) # True
By inheriting the built-in metaclass type To implement custom metaclasses
class MyMetaClass(type):
""" By inheritance python Built in metaclass type, To implement custom metaclasses """
def __new__(cls, name, bases, attr_dict, *args, **kwargs):
"""
To implement a custom metaclass , Also rewrite python Built in metaclass type Of __new__ Method ,tupe Create a class
There are three parameters , adopt type When you customize , Should also be introduced. type Three parameters of :
1.name: Class name ( character string )
2.bases: Inherited parent class ( Put it in Yuanzu )
3.attr_dict: Properties and methods ( Put it in the dictionary )
"""
print('---- This is a custom metaclass -----')
return super().__new__(cls, name, bases, attr_dict)
class Test(metaclass=MyMetaClass):
"""
Inherited custom metaclasses must pass metaclass Keyword assignment , Can inherit custom metaclass
"""
name = " Springfield "
class Test2(Test):
attr = "Test2"
if __name__ == '__main__':
pass
# see Test Class inherits class
print(type(Test))
# see Test2 Class inherits class
print(type(Test2))
# Output :
---- This is a custom metaclass - ----
---- This is a custom metaclass - ----
<class '__main__.MyMetaClass'>
<class '__main__.MyMetaClass'>
Use metaclasses to control attribute names to be all uppercase
class MyMetaClass(type):
""" By inheritance python Built in metaclass type, To implement custom metaclasses , Custom metaclasses can make attribute names uppercase """
def __new__(cls, name, bases, attr_dict, *args, **kwargs):
"""
To implement a custom metaclass , Also rewrite python Built in metaclass type Of __new__ Method ,tupe Create a class
There are three parameters , adopt type When you customize , Should also be introduced. type Three parameters of :
1.name: Class name ( character string )
2.bases: Inherited parent class ( Put it in Yuanzu )
3.attr_dict: Properties and methods ( Put it in the dictionary )
"""
print('---- This is a custom metaclass -----')
attr_dict_list = [itme for itme in attr_dict.items()]
for k,v in attr_dict_list:
# for k,v in attr_dict.items(): # When the dictionary is convenient, it is not allowed to increase or decrease the dictionary data
attr_dict.pop(k) # Delete key value pair
attr_dict[k.upper()] = v # Replace with uppercase key value pairs
attr_dict["__slots__"] = ["name","age", "attr"] # Control the created attributes
return super().__new__(cls, name, bases, attr_dict)
class Test(metaclass=MyMetaClass):
name = " Springfield "
age = 4
class Test2(Test):
attr = "Test2"
if __name__ == '__main__':
print(Test.__dict__)
# Output :
# {'__MODULE__': '__main__', '__QUALNAME__': 'Test', 'NAME': ' Springfield ', 'AGE': 4, '__slots__': ['name', 'age', 'attr']
ORM Model implementation ideas :
1. Class corresponding table , When creating a class, you need to automatically generate the corresponding data table .
2. Object corresponds to a piece of data , Create an object , You need to add a piece of data to the data table .
3. Property corresponds to the field , When modifying object attributes, you need to modify the corresponding fields in the database .
example :
from define_ORM import BaseField, CharField, IntegerField, BoolField
"""
Use metaclasses to implement model classes
"""
# Define metaclass
class FieldMetaClass(type):
""" Metaclass of model class
Use this metaclass to control Uer Generation of model class objects
Through the control of metaclasses , You can generate the table corresponding to the model class in the database
"""
def __new__(cls, name, bases, attr_dict, *args, **kwargs):
print('---- Triggered metaclass ')
# When calling the metaclass production model class, you must pass in the three parameters necessary for the metaclass :name,bases,attr_dict
table_name = name.lower() # name: The metaclass 3 Class name in parameter name, Here is :User/user, Convert to lowercase , Corresponding data table name
# print(attr_dict) # {'__module__': '__main__', '__qualname__': 'User', '__doc__': ' User model class , A model class is a data table name ', 'username': <define_ORM.CharField object at 0x7f9fc02ea040>, 'pwd': <define_ORM.CharField object at 0x7f9fc02eaeb0>, 'age': <define_ORM.IntegerField object at 0x7f9fc02eaca0>, 'marry': <define_ORM.BoolField object at 0x7f9fc02eaa30>}
# Filter attr_dict Unnecessary attributes in , Leave only the attribute fields in the model class
fields = {} # filds It is used to store the corresponding relationship between the attribute fields in the model class and the fields in the data table , Attribute fields are inherited from BaseField
for k, v in attr_dict.items():
if isinstance(v, BaseField): # Judge whether the attribute value is of field type , Because field types are inherited from BaseField class
fields[k] = v
# print(fields) # {'username': <define_ORM.CharField object at 0x7f9ee01ba040>, 'pwd': <define_ORM.CharField object at 0x7f9ee01baeb0>, 'age': <define_ORM.IntegerField object at 0x7f9ee01baca0>, 'marry': <define_ORM.BoolField object at 0x7f9ee01baa30>}
# The dictionary type fields And table name attr_dict in , Pass in new,User The model class also has t_name and fields attribute , Control generation table information
attr_dict["t_name"] = table_name
attr_dict["fields"] = fields
return super().__new__(cls, name, bases, attr_dict) # call type Metaclass new Method to generate model classes
class User(metaclass=FieldMetaClass):
""" User model class , A model class is a data table name """
username = CharField()
pwd = CharField()
age = IntegerField()
marry = BoolField()
if __name__ == '__main__':
print(User.fields)
print(User.t_name)
pass
tian = User()
tian.name = ' Springfield '
print(tian.name)
# Output :
---- Triggered metaclass
{'username': < define_ORM.CharField object at 0x7fcce8183af0 >, 'pwd': < define_ORM.CharField object at
0x7fcce8183a60 >, 'age': < define_ORM.IntegerField object at 0x7fcce8183910 >, 'marry': < define_ORM.BoolField object at 0x7fcce8183760 >}
user
Springfield
There is a problem at this point , Every time we create Usr object , Bind attributes to objects one by one User.name = xxx,User.pwd= xxxx,User.marry = xxx To bind , It's too cumbersome , Is there any way to achieve it chutnian=User(name = " Springfield “,age=4,marry=False) This one-time way to add data ? Yes , The way is as follows :
Newly defined BaseModel class , Define its __init__ Method , Receive the attribute fields that his subclass needs to bind , And designate BaseModel Class substitution User Class is created for metaclass ,User Model class inheritance BaseModel that will do , such ,User And other model classes pass in keyword parameters , You can call the parent class BaseModel Of init Method , Fulfill demand
1.defin_ORM.py modular
"""
Through the descriptor ORM Model
"""
class BaseField(object):
pass
class CharField(BaseField):
def __init__(self, max_length=20):
self.max_length = max_length
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
# First, judge whether it is empty
if value is not None:
# Then judge whether it is a string
if isinstance(value, str):
# Then judge whether the length meets the requirements
if len(value) <= self.max_length:
self.value = value
else:
raise TypeError('length need less than {}'.format(self.max_length))
else:
raise TypeError('need a str')
else:
raise TypeError("can not be None")
def __delete__(self, instance):
self.value = None
class IntegerField(BaseField):
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
# First, judge whether it is empty
if value is not None:
# Then judge whether it is an integer int
if isinstance(value, int):
self.value = value
else:
raise TypeError('need a int')
else:
raise TypeError("can not be None")
def __delete__(self, instance):
self.value = None
class BoolField(BaseField):
def __init__(self):
pass
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
if isinstance(value, bool):
self.value = value
else:
raise Exception('need a boolean type')
class UserModel(object):
# Define the model class of user information
name = CharField(max_length=20) # Definition :name Can only be assigned as a string
pwd = CharField(max_length=40)
age = IntegerField() # Definition :age Can only be assigned as an integer
marry = BoolField() # Definition :marry Only Boolean types
if __name__ == '__main__':
user = UserModel()
user.name = " Springfield "
print(user.name) # Output : Springfield
user.age = 130
print(user.age) # Output : 130
user.marry = False
print(user.marry)
user.pwd = 'wsdgdgdrgerdsfs Way van der Sar sends Arthur fisaffa sfa fda fsdf sdf fg'
print(user.pwd) # Output : TypeError: length need less than 40
from define_ORM import BaseField, CharField, IntegerField, BoolField
"""
Use metaclasses to implement model classes
"""
# Define metaclass
class FieldMetaClass(type):
""" Metaclass of model class
Use this metaclass to control Uer Generation of model class objects
Through the control of metaclasses , You can generate the table corresponding to the model class in the database
"""
def __new__(cls, name, bases, attr_dict, *args, **kwargs):
# print('---- Triggered metaclass ')
if name == 'BaseModel': # Because the following definitions BaseModel Class will also call FieldMetaClass Of new Method ,
# So you need to judge whether the class name is BaseModel, If yes, create it directly , There is no need to filter field attributes
return super().__new__(cls,name,bases,attr_dict)
# When calling the metaclass production model class, you must pass in the three parameters necessary for the metaclass :name,bases,attr_dict
else: # The model class calls this part of the filter attribute binding logic
table_name = name.lower() # name: The metaclass 3 Class name in parameter name, Here is :User/user, Convert to lowercase , Corresponding data table name
# print(attr_dict) # {'__module__': '__main__', '__qualname__': 'User', '__doc__': ' User model class , A model class is a data table name ', 'username': <define_ORM.CharField object at 0x7f9fc02ea040>, 'pwd': <define_ORM.CharField object at 0x7f9fc02eaeb0>, 'age': <define_ORM.IntegerField object at 0x7f9fc02eaca0>, 'marry': <define_ORM.BoolField object at 0x7f9fc02eaa30>}
# Filter attr_dict Unnecessary attributes in , Leave only the attribute fields in the model class
fields = {} # filds It is used to store the corresponding relationship between the attribute fields in the model class and the fields in the data table , Attribute fields are inherited from BaseField
for k, v in attr_dict.items():
if isinstance(v, BaseField): # Judge whether the attribute value is of field type , Because field types are inherited from BaseField class
fields[k] = v
# print(fields) # {'username': <define_ORM.CharField object at 0x7f9ee01ba040>, 'pwd': <define_ORM.CharField object at 0x7f9ee01baeb0>, 'age': <define_ORM.IntegerField object at 0x7f9ee01baca0>, 'marry': <define_ORM.BoolField object at 0x7f9ee01baa30>}
# The dictionary type fields And table name attr_dict in , Pass in new,User The model class also has t_name and fields attribute , Control generation table information
attr_dict["t_name"] = table_name
attr_dict["fields"] = fields
return super().__new__(cls, name, bases, attr_dict) # call type Metaclass new Method to generate model classes
class BaseModel(metaclass=FieldMetaClass):
""" The parent class of the model class , Instead of the model class, the metaclass FieldMetaClass establish """
def __init__(self, **kwargs):
# Unpack , And bind properties
for k, v in kwargs.items():
# self.k =v # Will report a mistake , Therefore k For the string ,self.k Equivalent to sefl."name".
# Set properties , Traverse all object properties , Set the properties of the object
setattr(self, k, v) # The first parameter :self As object , The second parameter :k For the property name , The third parameter :v For attribute value
class User(BaseModel):
""" User model class , A model class is a data table name """
username = CharField()
pwd = CharField()
age = IntegerField()
marry = BoolField()
if __name__ == '__main__':
t =User(username =' Springfield ',age =4, marry =False,pwd = '123')
print(t.username)
# Output :
# Springfield
Generate the data t after , How to save to the data table ? adopt save() Methods to save
from define_ORM import BaseField, CharField, IntegerField, BoolField
"""
Use metaclasses to implement model classes
"""
# Define metaclass
class FieldMetaClass(type):
""" Metaclass of model class
Use this metaclass to control Uer Generation of model class objects
Through the control of metaclasses , You can generate the table corresponding to the model class in the database
"""
def __new__(cls, name, bases, attr_dict, *args, **kwargs):
# print('---- Triggered metaclass ')
if name == 'BaseModel': # Because the following definitions BaseModel Class will also call FieldMetaClass Of new Method ,
# So you need to judge whether the class name is BaseModel, If yes, create it directly , There is no need to filter field attributes
return super().__new__(cls, name, bases, attr_dict)
# When calling the metaclass production model class, you must pass in the three parameters necessary for the metaclass :name,bases,attr_dict
else: # The model class calls this part of the filter attribute binding logic
table_name = name.lower() # name: The metaclass 3 Class name in parameter name, Here is :User/user, Convert to lowercase , Corresponding data table name
# print(attr_dict) # {'__module__': '__main__', '__qualname__': 'User', '__doc__': ' User model class , A model class is a data table name ', 'username': <define_ORM.CharField object at 0x7f9fc02ea040>, 'pwd': <define_ORM.CharField object at 0x7f9fc02eaeb0>, 'age': <define_ORM.IntegerField object at 0x7f9fc02eaca0>, 'marry': <define_ORM.BoolField object at 0x7f9fc02eaa30>}
# Filter attr_dict Unnecessary attributes in , Leave only the attribute fields in the model class
fields = {} # filds It is used to store the corresponding relationship between the attribute fields in the model class and the fields in the data table , Attribute fields are inherited from BaseField
for k, v in attr_dict.items():
if isinstance(v, BaseField): # Judge whether the attribute value is of field type , Because field types are inherited from BaseField class
fields[k] = v
# print(fields) # {'username': <define_ORM.CharField object at 0x7f9ee01ba040>, 'pwd': <define_ORM.CharField object at 0x7f9ee01baeb0>, 'age': <define_ORM.IntegerField object at 0x7f9ee01baca0>, 'marry': <define_ORM.BoolField object at 0x7f9ee01baa30>}
# The dictionary type fields And table name attr_dict in , Pass in new,User The model class also has t_name and fields attribute , Control generation table information
attr_dict["t_name"] = table_name
attr_dict["fields"] = fields
# Generate sql Statement of table , And implement
print(" Here should be the operation of generating data table ")
return super().__new__(cls, name, bases, attr_dict) # call type Metaclass new Method to generate model classes
class BaseModel(metaclass=FieldMetaClass):
""" The parent class of the model class , Instead of the model class, the metaclass FieldMetaClass establish
There is no need to define in the model class init The method , Just define attribute fields
"""
def __init__(self, **kwargs):
# Unpack , And bind properties
for k, v in kwargs.items():
# self.k =v # Will report a mistake , Therefore k For the string ,self.k Equivalent to sefl."name".
# Set properties , Traverse all object properties , Set the properties of the object
setattr(self, k, v) # The first parameter :self As object , The second parameter :k For the property name , The third parameter :v For attribute value
def save(self):
"""# Saving a piece of data should generate a corresponding sql sentence """
# Get table name
t_name = self.t_name
# Get field name
fields = self.fields # self.fields It's a metaclass FieldMetaClass Of fields
print('fields',
fields) # fields {'username': <define_ORM.CharField object at 0x7f9478214f70>, 'pwd': <define_ORM.CharField object at 0x7f9478214e80>, 'age': <define_ORM.IntegerField object at 0x7f9478214d00>, 'marry': <define_ORM.BoolField object at 0x7f9478214100>}
# Create a dictionary to store key value pairs
field_dict = {}
# Get the value of the corresponding field
print('fields.keys():', fields.keys()) # dict_keys(['username', 'pwd', 'age', 'marry'])
for field in fields.keys():
print('field', field) # username username age marry
field_dict[field] = getattr(self, field) # getattr() Function to return an object property value .
print("field_dict:", field_dict) # field_dict: {'username': ' Springfield ', 'pwd': '123', 'age': 4, 'marry': False}
# Generate corresponding sql sentence
print('---field_dict.values():',
field_dict.values()) # ---field_dict.values(): dict_values([' Springfield ', '123', 4, False])
sql = 'insert into {} value{}'.format(t_name, field_dict.values())
print(sql) # insert into user valuedict_values([' Springfield ', '123', 4, False])
class User(BaseModel):
""" User model class , A model class is a data table name """
username = CharField()
pwd = CharField()
age = IntegerField()
marry = BoolField()
if __name__ == '__main__':
t = User(username=' Springfield ', age=4, marry=False, pwd='123')
t.save()
print(t.username)
# Output :
# Here should be the operation of generating data table
# fields {'username': <define_ORM.CharField object at 0x7fa6a012cf70>, 'pwd': <define_ORM.CharField object at 0x7fa6a012ce80>, 'age': <define_ORM.IntegerField object at 0x7fa6a012cd00>, 'marry': <define_ORM.BoolField object at 0x7fa6a012c100>}
# fields.keys(): dict_keys(['username', 'pwd', 'age', 'marry'])
# field username
# field pwd
# field age
# field marry
# field_dict: {'username': ' Springfield ', 'pwd': '123', 'age': 4, 'marry': False}
# ---field_dict.values(): dict_values([' Springfield ', '123', 4, False])
# insert into user valuedict_values([' Springfield ', '123', 4, False])
# Springfield 边栏推荐
- High level application of SQL statements in MySQL database (II)
- [illusory] weapon slot: pick up weapons
- Configuration programmée du générateur de plantes du moteur illusoire UE - - Comment générer rapidement une grande forêt
- Eslint reports an error
- Blender multi lens (multi stand) switching
- Blender多鏡頭(多機比特)切換
- Project practice, redis cluster technology learning (IX)
- [200 Shengxin literatures] 96 joint biomarkers of immune checkpoint inhibitor response in advanced solid tumors
- Matlab代码生成之SIL/PIL测试
- Error reporting on the first day of work (incomplete awvs unloading)
猜你喜欢
随机推荐
Judging right triangle in C language
Project practice, redis cluster technology learning (VII)
Spatial interpretation | comprehensive analysis of spatial structure of primary liver cancer
UE illusory engine programmed plant generator setup -- how to quickly generate large forests
Vs+qt set application icon
UE5——AI追逐(藍圖、行為樹)
【虚幻】武器插槽:拾取武器
go语言入门
Bugkuctf-web16 (backup is a good habit)
2837xd 代码生成——StateFlow(2)
Basic notes of illusory AI blueprint (10000 words)
【UE5】蓝图制作简单地雷教程
2837xd 代码生成——补充(1)
渗透测试的介绍和防范
Matlab代码生成之SIL/PIL测试
Blender摄像机环绕运动、动画渲染、视频合成
The primary market project galaxy will conduct public offering on coinlist on February 17
ICLR 2022: how does AI recognize "things I haven't seen"?
PI control of three-phase grid connected inverter - off grid mode
Configuration programmée du générateur de plantes du moteur illusoire UE - - Comment générer rapidement une grande forêt







