您好,登錄后才能下訂單哦!
?
?
目錄
meta ?programming,元編程:... 1
ORM:... 5
字段類的實現:... 5
session類的實現:... 8
自定義Model類的實現:... 9
使用元類改造Model:... 10
引擎類:... 12
總結:... 13
?
?
?
概念來自LISP和smaltalk;
我們寫程序是直接寫代碼,是否能用代碼來生成未來我們需要的代碼?這就是元編程;
用來生成代碼的程序稱為元程序meta program,編寫這種程序就稱為元編程meta programming;
py能通過反射實現元編程(元語言);
在框架中用的多;
?
?
type類:
type與object糾纏在一起,關系復雜;
所有自定義的類都是type的子類,即type類的實例;
?
class type(object):
??? def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__?? #what類名字,bases繼承列表,dict類對象(類屬性字典),這些與class定義的類相關
??????? """
??????? type(object_or_name, bases, dict)?? #借助type構造任何類,用代碼來生成代碼即元編程
??????? type(object) -> the object's type?? #返回對象的類型,如type(10)
??????? type(name, bases, dict) -> a new type?? #返回一個新的類型
??????? # (copied from class doc)
??????? """
??????? pass
?
總結:
元類是制造類的工廠,是生成類的類;
定義一個元類,需要使用type(name,bases,dict),也可以繼承type;
構造好元類,就可以在類定義時使用關鍵字參數metaclass指定元類,可使用最原始的metatype(name, bases, dict)方式構造一個元類;
元類的__new__()方法中,可獲取元類信息、當前類、基類、類變量信息;
元編程一般用于框架開發中;
開發中,除非明確知道自己在干什么,否則不要隨便使用元編程,99%的情況下用不到元類,可能有些程序員一輩子都不會使用元類;
Django、SQLAlchemy使用了元類,這樣我們使用起來很方便;
?
?
例:
XClass = type('myclass', (object,), {'a': 100, 'b': 'string'})
print(XClass)
print(type(XClass))
print(XClass.__dict__)
print(XClass.mro())
輸出:
<class '__main__.myclass'>
<class 'type'>
{'b': 'string', '__dict__': <attribute '__dict__' of 'myclass' objects>, '__weakref__': <attribute '__weakref__' of 'myclass' objects>, 'a': 100, '__module__': '__main__', '__doc__': None}
[<class '__main__.myclass'>, <class 'object'>]
?
例1:
def __init__(self):
??? self.x = 100
?
def show(self):
??? print(self.__dict__)
?
XClass = type('myclass', (object,), {'a': 100, 'b': 'string', '__init__': __init__, 'show': show})
print(XClass)
print(type(XClass))
print(XClass.__dict__)
print(XClass.mro())
輸出:
<class '__main__.myclass'>
<class 'type'>
{'a': 100, '__weakref__': <attribute '__weakref__' of 'myclass' objects>, '__dict__': <attribute '__dict__' of 'myclass' objects>, 'b': 'string', 'show': <function show at 0x0000000000801488>, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x00000000008012F0>}
[<class '__main__.myclass'>, <class 'object'>]
?
例2:
同例1;
class MyClass:
??? def __init__(self):
??????? print('init')
?
??? def show(self):
??????? print('show')
?
print(MyClass)
print(type(MyClass))
print(MyClass.__dict__)
print(MyClass.mro())
輸出:
<class '__main__.MyClass'>
<class 'type'>
{'show': <function MyClass.show at 0x00000000011B1598>, '__module__': '__main__', '__doc__': None, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__init__': <function MyClass.__init__ at 0x00000000011B1510>}
[<class '__main__.MyClass'>, <class 'object'>]
?
例:
class XMeta(type):
??? # pass
??? def __new__(cls, *args, **kwargs):?? #__new__()可用作攔截;cls,不是普通的類,而是與type類等同,稱為元類;參數(cls,*args,**kwargs)等同于(cls,what,bases,dict)
??????? print(1, cls)?? #打印元類
??????? print(2, args)?? #what,打印三元組(what,bases,dict)
??????? print(3, kwargs)?? #bases,{}
??????? print(4, super())?? #dict
??????? print(5, type(cls))
??????? return super().__new__(cls, *args, **kwargs)
??????? # return 1
??????? # return super().__new__(cls, what, bases, dict)
?
??? # def __new__(cls, name, bases, dict):
??? #???? print(1, cls)
??? #???? print(2, name)
??? #???? print(3, bases)
??? #???? print(4, dict)
??? #???? return super().__new__(cls, name, bases, dict)
?
print(XMeta)
print(type(XMeta))
print(XMeta.__dict__)
# print(XMeta.mro())
?
class A(metaclass=XMeta):?? #方式一,通過metaclass關鍵字指定元類,此處不是繼承而是替換元類
??? # pass
??? id = 100
??? def __init__(self):
??????? print('###A init###')
?
A()
print(A)
print(type(A))
?
class B(A):?? #方式二,通過繼承方式得到元類
??? # pass
??? def __init__(self):
??????? super().__init__()
??????? print('###B init###')
?
B()
?
C = XMeta('tom', (), {})?? #方式三,用元類構建其它類
?
print(type(A), type(B))
輸出:
<class '__main__.XMeta'>
<class 'type'>
{'__doc__': None, '__module__': '__main__', '__new__': <staticmethod object at 0x000000000076E278>}
1 <class '__main__.XMeta'>
2 ('A', (), {'__init__': <function A.__init__ at 0x0000000000761598>, '__module__': '__main__', '__qualname__': 'A', 'id': 100})
3 {}
4 <super: <class 'XMeta'>, <XMeta object>>
5 <class 'type'>
###A init###
<class '__main__.A'>
<class '__main__.XMeta'>
1 <class '__main__.XMeta'>
2 ('B', (<class '__main__.A'>,), {'__init__': <function B.__init__ at 0x0000000000761730>, '__module__': '__main__', '__qualname__': 'B'})
3 {}
4 <super: <class 'XMeta'>, <XMeta object>>
5 <class 'type'>
###A init###
###B init###
1 <class '__main__.XMeta'>
2 ('tom', (), {})
3 {}
4 <super: <class 'XMeta'>, <XMeta object>>
5 <class 'type'>
<class '__main__.XMeta'> <class '__main__.XMeta'>
?
?
?
object relation map,對象關系映射,對象和關系之間的映射,使用面向對象的方式來操作DB;
關系模型和py對象之間的映射;
?
table-->class?? #表映射為類
row-->object?? #行映射為實例
column-->property?? #字段映射為類屬性
?
例:
實現ORM框架;
表由字段構成,表對應類,類屬性對應字段;
?
?
字段特征有:name,column,type,pk,uk(unique key),index,nullable,default,auto_increment,所以字段可用類來描述;
字段類要提供對數據的校驗功能,如聲明字段是int類型,應要判斷數據是不是整型;
字段有多種類型,不同類型有差異,使用繼承的方式實現;
字段現定義為類屬性,而這個類屬性適合使用類來描述,即描述器;
?
例:
class Field:
??? def __init__(self, name, column=None, pk=False, unique=False, index=False, nullable=True, default=None):
??????? self.name = name
??????? if column is None:
??????????? self.column = name
??????? else:
??????????? self.column = column
??????? self.pk = pk
??????? self.unique = unique
??????? self.index = index
??????? self.nullable = nullable
??????? self.default = default
?
??? def validate(self, value):
??????? raise NotImplementedError
?
??? def __get__(self, instance, owner):
??????? if instance is None:
??????????? return self
??????? return instance.__dict__[self.name]
?
??? def __set__(self, instance, value):
??????? self.validate(value)
??????? instance.__dict__[self.name] = value
?
??? def __str__(self):
??????? return '{} <{}>'.format(self.__class__.__name__, self.name)
?
??? __repr__ = __str__
?
class IntField(Field):
??? def __init__(self, name, column=None, pk=False, unique=False, index=False, nullable=True, default=None, auto_increment=False):
??????? super().__init__(name, column, pk, unique, index, nullable, default)
??????? self.auto_increment = auto_increment
?
??? def validate(self, value):
??????? # pass
??????? if value is None:
??????????? if self.pk:
??????????????? raise TypeError('{} is pk, not None'.format(self.name))
??????????? if not self.nullable:
??????? ????????raise TypeError('{} required'.format(self.name))
??????? else:
??????????? if not isinstance(value, int):
??????????????? raise TypeError('{} should be integer'.format(self.name))
?
class StringField(Field):
??? def __init__(self, name, column=None, pk=False, unique=False, index=False, nullable=True, default=None, length=False):
??????? super().__init__(name, column, pk, unique, index, nullable, default)
??????? self.length = length
?
??? def validate(self, value):
??????? # pass
??????? if value is None:
??????????? if self.pk:
??????????????? raise TypeError('{} is pk, not None'.format(self.name))
??????????? if not self.nullable:
??????????????? raise TypeError('{} required'.format(self.name))
??????? else:
??????????? if not isinstance(value, str):
??????????????? raise TypeError('{} should be string'.format(self.name))
??????????? if len(value) > self.length:
??????????????? raise ValueError('{} is too long'.format(value))
?
例:
Student類的操作對應表的CRUD操作,若使用pymysql,應用cursor對象的execute方法;
增加、修改數據自定義為save()方法,數據庫連接從外部傳入,這應是一個全局變量;
class Student:
??? id = IntField('id', 'id', True, nullable=False, auto_increment=True)
??? name = StringField('name', nullable=False, length=64)
??? age = IntField('age')
?
??? def __init__(self, id, name, age):
??????? self.id = id
??????? self.name = name
??????? self.age = age
?
??? def __str__(self):
??????? return 'Student({}, {}, {})'.format(self.id, self.name, self.age)
?
??? __repr__ = __str__
?
??? def save(self, conn:pymysql.connections.Connection):
??????? sql = 'insert into student (id, name, age) values (%s, %s, %s)'
??????? with conn as cursor:
??????????? cursor.execute(sql, (self.id, self.name, self.age))
?
?
每一次數據庫操作都是在一個會話中完成,將cursor的操作封裝到會話中;
?
例:
class Session:
??? def __init__(self, conn: pymysql.connections.connection):
??????? self.conn = conn
??????? self.cursor = None
?
??? def execute(self, query, *args):
??????? if self.cursor is None:
??????????? self.cursor = self.conn.cursor()
??????? self.cursor.execute(query, args)
?
??? def __enter__(self):
??????? self.cursor = self.conn.cursor()
??????? return self
?
??? def __exit__(self, exc_type, exc_val, exc_tb):
??????? self.cursor.close()
??????? if exc_type:
??????????? self.conn.rollback()
??????? else:
?????? ?????self.conn.commit()
?
class Student:
??? id = IntField('id', 'id', True, nullable=False, auto_increment=True)
??? name = StringField('name', nullable=False, length=64)
??? age = IntField('age')
?
??? def __init__(self, id, name, age):
??????? self.id = id
??????? self.name = name
??????? self.age = age
?
??? def __str__(self):
??????? return 'Student({}, {}, {})'.format(self.id, self.name, self.age)
?
??? __repr__ = __str__
?
??? def save(self, session: Session):
??????? sql = 'insert into student (id, name, age) values (%s, %s, %s)'
??????? session.execute(sql, self.id, self.name, self.age)
?
?
Student這樣的類,若多建幾個,可發現千篇一律,每一個這樣的類,得定義一個名稱,對應不同的表,都要先定義好類屬性,再__init__()初始化值,而這些值正好是定義好的類屬性;
CRUD操作也一樣;
?
設計一個Model類,增加一個__table__類屬性用來保存不同的表名;
?
例:
class Model:
??? def save(self, session: Session):
??????? names = []
??????? values = []
?
??????? for k, v in self.__class__.__dict__.items():
??????????? if isinstance(v, Field):
??????????????? if k in self.__dict__.keys():
??????????????????? names.append(k)
??????????????????? values.append(v)
?
??????? query = 'insert into {} ({}) values({})'.format(
??????????? self.__table__,
??????????? ','.join(names),
??????????? ','.join(['%s']*len(values)))
??????? print(query)
???? ???print(values)
?
class Student(Model):
??? __table__ = 'student'
??? id = IntField('id', 'id', True, nullable=False, auto_increment=True)
??? name = StringField('name', nullable=False, length=64)
??? age = IntField('age')
?
??? def __init__(self, id, name, age):
??????? self.id = id
??????? self.name = name
??????? self.age = age
?
??? def __str__(self):
??????? return 'Student({}, {}, {})'.format(self.id, self.name, self.age)
?
??? __repr__ = __str__
?
s = Student(1, 'tom', 20)
s.save(None)
輸出:
insert into student (name,age,id) values(%s,%s,%s)
[StringField <name>, IntField <age>, IntField <id>]
?
?
通過元類編程,增加了mapping類變量,里面存儲著已經過濾出來的,字段類變量名=>Field對象映射;
例:
class ModelMeta(type):
??? def __new__(cls, name, bases, attrs: dict):?? #name類名,attrs類屬性字典
??????? if '__table__' not in attrs.keys():
??????????? attrs['__table__'] = name?? #默認添加表名為類名
?
??????? mapping = {}?? #方便以后查詢屬性名和字段實例
??????? primarykey = []
??????? for k, v in attrs.items():?? #k,類變量名稱字符串;v,對象
??????????? if isinstance(v, Field):
????? ??????????print(k, v)
??????????????? v.name = k
??????????????? if v.column is None:
??????????????????? v.column = k?? #沒有給字段名
?
??????????????? mapping[k] = v
?
??????????????? if v.pk:
??????????????????? primarykey.append(v)
?
??????? attrs['__mapping__'] = mapping?? #增加屬性
??????? attrs['__primary__'] = primarykey
?
??????? return super().__new__(cls, name, bases, attrs)
?
class Model(metaclass=ModelMeta):
??? def save(self, session: Session):
??????? names = []
??????? values = []
?
??????? for k, v in self.__class__.__dict__.items():
??????????? if isinstance(v, Field):
??????????????? if k in self.__dict__.keys():
??????????????????? names.append(k)
??????????????????? values.append(v)
?
??????? query = 'insert into {} ({}) values({})'.format(
??????????? self.__table__,
??????????? ','.join(names),
??????????? ','.join(['%s']*len(values)))
??????? print(query)
??????? print(values)
??????? # session.execute(query, *values)
?
class Student(Model):
??? __table__ = 'student'?? #有了元類,此句可省
??? id = IntField('id', 'id', True, nullable=False, auto_increment=True)
??? name = StringField('name', nullable=False, length=64)
??? age = IntField('age')
?
??? def __init__(self, id, name, age):
??????? self.id = id
??????? self.name = name
??????? self.age = age
?
??? def __str__(self):
??????? return 'Student({}, {}, {})'.format(self.id, self.name, self.age)
?
??? __repr__ = __str__
?
s = Student(1, 'tom', 20)
s.save(None)
print(Student.__dict__)
print(Model.__dict__)
輸出:
insert into student (id,age,name) values(%s,%s,%s)
[IntField <id>, IntField <age>, StringField <name>]
{'__doc__': None, '__primary__': [IntField <id>], 'id': IntField <id>, '__init__': <function Student.__init__ at 0x0000000002DC7158>, '__table__': 'student', '__repr__': <function Student.__str__ at 0x0000000002DC71E0>, '__module__': '__main__', 'age': IntField <age>, '__str__': <function Student.__str__ at 0x0000000002DC71E0>, 'name': StringField <name>, '__mapping__': {'id': IntField <id>, 'age': IntField <age>, 'name': StringField <name>}}
{'__doc__': None, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Model' objects>, '__weakref__': <attribute '__weakref__' of 'Model' objects>, '__primary__': [], '__table__': 'Model', 'save': <function Model.save at 0x0000000002DC70D0>, '__mapping__': {}}
?
?
?
實體類沒有提供數據庫連接,它也不應該提供,實例類就應只完成表和類的映射;
提供一個數據庫的包裝類:
1、負責數據庫連接;
2、負責CRUD操作,取代實體類的CRUD方法;
?
例:
class Engine:
??? def __init__(self, *args, **kwargs):
??????? self.conn = pymysql.connect(*args, **kwargs)
?
??? def save(self, instance: Student):
??????? names = []
??????? values = []
??????? for k, v in instance.__mapping__.items():
??????????? names.append('`{}`'.format(k))
??????????? values.append(instance.__dict__[k])
?
??????? query = "insert into {} ({}) values ({})".format(
??????????? instance.__table__,
??????????? ','.join(names),
??????????? ','.join(['%s']*len(values))
??????????? )
??????? print(query)
??????? print(values)
?
??????? # with self.conn as cursor:
??????? #???? with cursor:
??????? #? ???????cursor.execute(query, values)
?
s = Student(1, 'tom', 20)
# s.save(None)
print(Student.__dict__)
print(Model.__dict__)
print(s.__dict__)
?
engine = Engine('10.113.129.2', 'root', 'rootqazwsx', 'test1')
engine.save(s)
輸出:
id IntField <id>
age IntField <age>
name StringField <name>
{'__primary__': [IntField <id>], '__doc__': None, '__repr__': <function Student.__str__ at 0x0000000002DC81E0>, 'name': StringField <name>, '__table__': 'student', '__init__': <function Student.__init__ at 0x0000000002DC8158>, '__module__': '__main__', '__str__': <function Student.__str__ at 0x0000000002DC81E0>, 'id': IntField <id>, 'age': IntField <age>, '__mapping__': {'id': IntField <id>, 'age': IntField <age>, 'name': StringField <name>}}
{'save': <function Model.save at 0x0000000002DC80D0>, '__dict__': <attribute '__dict__' of 'Model' objects>, '__module__': '__main__', '__doc__': None, '__mapping__': {}, '__primary__': [], '__weakref__': <attribute '__weakref__' of 'Model' objects>, '__table__': 'Model'}
{'id': 1, 'name': 'tom', 'age': 20}
insert into student (`id`,`age`,`name`) values (%s,%s,%s)
[1, 20, 'tom']
?
?
這是一個ORM框架的雛形,從這個例子就可以明白ORM框架的內部原理;
學習一個ORM框架:
1、看Model類如何描述表、屬性和字段如何映射;
2、增刪改查方法調用如何轉化為SQL語句并執行;
?
?
?
?
?
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。