python元类 orm_谈谈python中的元类以及实现一个简单的ORM框架

大家都说python中的元类(metaclass)在真实场景中99%的几率都用不到,但是最大熵理论告诉我们,面对未知风险,我们不能报侥幸心理,我们应该平权看待所有潜在风险,不应该放过任何一处潜在风险。

So,本文主要讲讲python的元类,为了不枯燥无味,本文以一个初级ORM框架例子来讲解。

什么是ORM

Object Relational Mapping 即 对象-关系映射,在关系型数据库中就是把关系数据库的一行映射为一个对象,即一个类对应一个表,这样,你就不需要每次都用pymysql去封装每条sql了,把重复的操作交给ORM,如sqlalchemy就是一个 ORM框架

可能这个解释有点牵强,在此举个例子把,比如说你要向一个数据表user插入数据,你可能会写: 1insert into user(name, age) values('seanlee', 21)

当插入数据到其他表时比如说course时,你又要: 1insert into course(name, teacher) values('computer sicence', 'Mr.Gates')

这时你发现每次插入数据都要自己写完所有语句,且要处理完整个逻辑过程。这真的很累,于是乎,如果有一个框架能把这些复杂的工作给做了,使用者只需封装好模型类即可自动完成复杂的流程。 你的想法可能是这样的: 1

2

3

4

5

6

7

8

9

10class User(ORM):

# 定义数据表的字段

name = CharField()

age = IntField()

if __name__ == '__main__':

user = User()

user.name = "seanlee"

user.age = 21

user.save() # 调用save函数框架自动将数据插入到数据库中

好了,上面就是ORM的大致思路了,本文要实现的目标就是完成上面代码的内部逻辑。

什么是元类

元类metaclass是类的类,简单的说就是元类是用来生产类的,可以说元类是最上层的类。可能还是很难理解,举几个例子把

1. object类

平时大家定义类时可能会继承object类,大家下意识的认为object就是最上层的类了,其实不是,我们输出object的类型看看 1print(type(object)) #

可以看到object类的类型是type类型,那么type类型又是什么呢?type类型就是指type类,大家都以为type()是一个函数,其实它是一个类,当只传一个参数时它会返回参数的类型。

其实type就是python的元类,看下面程序: 1print(type(type)) #

可以看到type的类型就是type

2. 基本数据类型

python中的基本数据类型也可看为对象,它们的直属类型的类就是 type,看下面例子:

1

2

3

4

5

6print(type(type(97))) # 整型

print(type(type(97.0))) # 浮点

print(type(type("seanlee"))) # 字符串

print(type(type((9, 7)))) # 元组

print(type(type([9, 7]))) # 列表

print(type(type({"key": "val"}))) # 字典

输出结果为: 1

2

3

4

5

元类的作用

掌握了元类,你就是“类”的老大了,你可以按照你的方式去修改类,就好比你得到了Linux的root帐号,你可以为所欲为了。也好比你是微信群的群主,拥有直接拉人入群、踢人出群的权力,python中的元类也类似可以用于对类属性的增删操作。

好啦,到这里你应该理解元类的概念了

type类

从此刻起一定要更正观念type是一个类,它有三个参数: 1type(what [, bases, dict])

可见后两个参数是可选的,各参数的意义:

what: 输入的实例

bases:类的基类,传入的是元组

dict:类的属性、方法

举几个例子说明,type的用法

直接生产类

1

2

3

4User = type('User', (object, ), {'name': 'seanlee', 'age': 21})

user = User()

print(user.name) # seanlee

print(user.age) # 21

修改类属性

1

2

3

4

5

6

7

8

9

10

11

12

13class User(object):

name = None

user = User()

print(user.name) # None

def get_name(self):

return self.name

User = type('User', (object, ), {'name':'seanlee', 'get_name': get_name})

user = User()

print(user.name) # seanlee

print(user.get_name()) # seanlee

python中类的创建

如果类中没有定义metaclass,那么直接用type创建

如果用户定义了metaclass那么以metaclass的方式创建

自定义元类的创建

1

2

3

4

5

6

7

8

9

10

11

12

13class Metaclass(type):

def __new__(cls, name, bases, attrs, **kwargs):

# do something here.

print("call Metaclass")

return super(Metaclass, cls).__new__(cls, name, bases, attrs, **kwargs)

class User(metaclass=Metaclass):

# __metaclass__ = Metaclass # python2支持的方式

def __init__(self):

print("call User")

if __name__ == '__main__':

User()

输出: 1

2call Metaclass

call User

开始打造ORM

1. 使用描述器定义字段属性

如果不了解描述器,请阅读python中的描述器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32# 定义字段属性的基类Field,它的用处主要用于识别类属性中属于字段的那些属性

class Field(object):

pass

# 整型字段属性

class IntField(Field):

def __init__(self, db_column=""):

self._value = None # 表的数据

self.db_column = db_column

def __set__(self, instance, value):

if not isinstance(value, int):

raise ValueError("input should be a Integer")

self._value = value

def __get__(self, instance, owner):

return self._value

# 字符型字段属性

class CharField(Field):

def __init__(self, db_column=""):

self._value = None

self.db_column = db_column

def __get__(self, instance, owner):

return self._value

def __set__(self, instance, value):

if not isinstance(value, str):

raise ValueError("input should be a String")

self._value = value

2. 定义元类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16class MetaModel(type):

def __new__(cls, name, bases, attrs, **kwargs):

fields = {}

for key, val in attrs.items():

# 把attrs中与数据库表字段有关的列提取出来

if isinstance(val, Field):

fields[key] = val # value 直接走描述器__get__()

_meta = {}

db_table = name.lower() # 数据表名称默认取小写类名称

_meta['db_table'] = db_table

attrs['_meta'] = _meta

attrs['_fields'] = fields

# 以上过程相当于对类进行了修改

return super(MetaModel, cls).__new__(cls, name, bases, attrs, **kwargs)

3. 定义模型基类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38class Model(metaclass=MetaModel):

def __init__(self, *args, **kwargs):

for key, val in kwargs.items():

setattr(self, key, val)

return super(Model, self).__init__()

def save(self):

fields = []

values = []

for key, val in self._fields.items():

db_column = val.db_column

if db_column is None:

db_column = key.lower()

fields.append(db_column)

value = getattr(self, key) # 字段的值

values.append(str(value))

sql = "insert {name} ({field}) values ({value})".format(name=self._meta['db_table'],

field=','.join(fields),

value=','.join(values))

return sql

def select(self):

fields = []

where = []

for key, val in self._fields.items():

db_column = val.db_column

if db_column is None:

db_column = key.lower()

fields.append(db_column)

v = getattr(self, key, None)

if v is not None:

where.append([key, str(v)])

sql = 'select {fields} from {name} where {where}'.format(name=self._meta['db_table'],

fields=','.join(fields),

where=' and '.join(['='.join(x) for x in where]),

)

return sql

上述三步就完成了简单orm的搭建了,为了简单没封装真实的数据库操作,仅返回SQL语句而已。

4. 操作实例

1

2

3

4

5

6

7

8

9

10

11

12class User(Model):

name = CharField(db_column="name", max_length=10)

age = IntField(db_column="age", min=0, max=100)

class Meta: # 使用内部类来定义数据表的其他属性

db_table = "db_user"

if __name__ == '__main__':

user = User(name='seanlee', age=15)

user.name = 'sean'

print(user.save())

print(user.select())

输出 1

2insert user (name,age) values (sean,15)

select name,age from user where name=sean and age=15

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值