当前位置:网站首页>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
边栏推荐
- 2837xd code generation - Supplement (1)
- Project practice, redis cluster technology learning (VIII)
- ue虚幻引擎程序化植物生成器设置——如何快速生成大片森林
- Eslint reports an error
- Brief analysis of edgedb architecture
- [illusory] automatic door blueprint notes
- Error reporting on the first day of work (error reporting when Nessus installs WinPcap)
- A model can do two things: image annotation and image reading Q & A. VQA accuracy is close to human level | demo can be played
- Pycaret | a few lines of code to solve machine learning modeling
- Illusion -- Animation blueprint, state machine production, character walking, running and jumping action
猜你喜欢
TD conducts functional simulation with Modelsim
Sil/pil test of matlab code generation
[unreal] animation notes of the scene
虚幻——动画蓝图、状态机制作人物走跑跳动作
渗透测试的介绍和防范
Skywalking theory and Practice
Configuration programmée du générateur de plantes du moteur illusoire UE - - Comment générer rapidement une grande forêt
ESLint 报错
Personal experience & blog status
Matlab generates DSP program -- official routine learning (6)
随机推荐
Bugkuctf-web16 (backup is a good habit)
2837xd code generation module learning (1) -- GPIO module
Beautiful and intelligent, Haval H6 supreme+ makes Yuanxiao travel safer
Remember the use of add method once
PI control of three-phase grid connected inverter - off grid mode
2837xd code generation - Summary
The primary market project galaxy will conduct public offering on coinlist on February 17
Project practice, redis cluster technology learning (IX)
Project practice, redis cluster technology learning (11)
【虚幻】按键开门蓝图笔记
Project practice, redis cluster technology learning (VII)
[ue5] two implementation methods of AI random roaming blueprint (role blueprint and behavior tree)
2837xd 代碼生成——補充(1)
Record the interesting process of using Xray for the first time
MySQL transaction
A model can do two things: image annotation and image reading Q & A. VQA accuracy is close to human level | demo can be played
Blender海洋制作
Applet development summary
Bugkuctf-web24 (problem solving ideas and steps)
Career planning and development