04 -- 元类和ORM

  本篇主要介绍元类,为什么说一切皆对象;如何动态的创建类等;以及ORM,即什么是ORM等知识

一、元类

  1.1 在Python中一切皆对象

  在学习元类中我们首先需要了解一个概念-- python中一切皆对象,那么为什么这么说呢?

  扩展:通过globals()--查看所有的全局变量,当我们定义全局变量时,python会将这些全局变量存放至一个字典中;而其中包含 __builtin__内嵌模块,当我们 globals()["__builtin__"].__dict__,可以看到内嵌模块中的所有内置函数或者内置模块即其对应的引用指针,例如:(只截取了小部分)

  

  类也是对象,当我们定义一个类,其实也是通过另外一个类(type)类创建一个实例对象,只是这个对象比较特殊,拥有着创建实例对象的特殊功能。而可能你就会问了,那么type是由什么类实例化得到的呢? type就是元类,其自身实例对象了其自身。

  

  1.2  使用type创建类

  通常我们定义类有使用以下的方式创建类:

>>> class ObjectCreator(object):
…       pass

  而同时 我们也可以通过type实例化得到类对象,其效果是一摸一样的,这种创建类的方式我们称为动态的创建类;

class Test1(object):
    name="alex"
    age = 30

Test2 = type("Test2",(object,),{"name":"alex","age":30})

  以上两种形式定义的类是完全一样的(除了类名),前者是通过关键字定义的类对象,而后者是通过type类实例化得到的类对象;

  当然也可以为该类定义实例方法、类方法、以及静态方法等,例如:

# 析构方法
def __init__(self,name,age):
    self.name = name
    self.age = age

# 实例方法
def foo(self):
    print("in the foo",self)

# 类方法
@classmethod
def bar(cls):
    print("in the foo",cls)

#静态方法
@staticmethod
def cal():
    print("in the cal")

Test =type("Test",(object,),{"info":"这是一个type实例化的类","foo":foo,"bar":bar,"cal":cal,"__init__":__init__})

test = Test("alex",22)
test.bar()
test.foo()
test.cal()

  1.3  什么是元类?

  元类:通俗来将 元类就是可以创建类的"东西";准确来说:元类就是可以实例化得到类对象的一种类,上述的type类就是元类;

MyClass = MetaClass()  # 使用元类创建出一个对象,这个对象称为“类”
my_object = MyClass()  # 使用“类”来创建出实例对象

 即:

  1、可以这样理解:元类通过实例化得到类对象,类通过实例化得到实例化对象。

  例如上述你看到的:

MyClass = type(‘MyClass‘, (), {})

  这种方式便是:通过元类type传入参数(参数1-- 得到类对象的名称 , 参数二----该类对象的父类们的父类名,参数三-- 存储该类对象的类属性、类方法),即便是通过这种方式得到一个类对象。

  Python中所有的东西,注意,我是指所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type。

  1.4  自定义元类

  在上述我们知道可以通过type动态的创建类,那么我们是否可以定义一个类,利用继承或者组合的方式,通过派生来为创建的类对象增设一些新的功能呢?

   1.4.1 metaclass

  在自定义元类之前我们需要了解以下 metaclass:

class MyType(type):
    def __new__(cls,name,prants,attrs):
        print("in the MyType..")
        return type(name,prants,attrs)
    pass

class Foo(object,metaclass=MyType):
    pass

print(Foo.__class__)

  Python做了如下的操作:

  1. Foo中有 metaclass=MyType 这个属性吗?如果是,Python会通过 meteclass=MyType 创建一个名字为Foo的类(对象)
  2. 如果Python没有找到 metaclass=xxx ,它会继续在Bar(父类)中寻找metaclass=xxx 属性,并尝试做和前面同样的操作。
  3. 如果Python在任何父类中都找不到 metaclass=xxx ,它就会在模块层次中去寻找metaclass=xxx ,并尝试做同样的操作。
  4. 如果还是找不到metaclass=xxx ,Python就会用内置的type来创建这个类对象。

  1.4.2 自定义元类

  自定义元类的主要目的就是为了当创建类时能够自动地改变类。接下来我们实现 元类把所有的属性都改成大写形式,即相当于为原来通过type类创建类对象添加或修改其方法,而不改变源代码的效果,优点类似于装饰器的效果;

class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被调用的特殊方法
    # __new__是用来创建对象并返回之的方法
    # 而__init__只是用来将传入的参数初始化给对象
    # 你很少用到__new__,除非你希望能够控制对象的创建
    # 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
    # 如果你希望的话,你也可以在__init__中做些事情
    # 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
    def __new__(cls, class_name, class_parents, class_attr):
        # 遍历属性字典,把不是__开头的属性名字变为大写
        new_attr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value

        # 方法1:通过‘type‘来做类对象的创建
        return type(class_name, class_parents, new_attr)

        # 方法2:复用type.__new__方法
        # 这就是基本的OOP编程,没什么魔法
        # return type.__new__(cls, class_name, class_parents, new_attr)

# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
    bar = ‘bip‘

# python2的用法
# class Foo(object):
#     __metaclass__ = UpperAttrMetaClass
#     bar = ‘bip‘

print(hasattr(Foo, ‘bar‘))
# 输出: False
print(hasattr(Foo, ‘BAR‘))
# 输出:True

f = Foo()
print(f.BAR)
# 输出:‘bip‘

 其本质是:

  就是这样,除此之外,关于元类真的没有别的可说的了。但就自定义元类本身而言,它们其实是很简单的:

  1. 拦截类的创建
  2. 修改类
  3. 返回修改之后的类

二、ORM

 2.1 什么是ORM?

  ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。

  一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,用它实例化传入的实例属性作为记录,当对这个实例对象操作时,能够对应MySQL语句。

  

  

  1. 所谓的ORM就是让开发者在操作数据库的时候,能够像操作对象时通过xxxx.属性=yyyy一样简单,这是开发ORM的初衷;
  2. 只不过ORM的实现较为复杂,Django中已经实现了 很复杂的操作,本节知识 主要通过完成一个 insert相类似的ORM,理解其中的道理就就可以了;例如:
class ModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        mappings = dict()
        # 判断是否需要保存
        for k, v in attrs.items():
            # 判断是否是指定的StringField或者IntegerField的实例对象
            if isinstance(v, tuple):
                print(‘Found mapping: %s ==> %s‘ % (k, v))
                mappings[k] = v

        # 删除这些已经在字典中存储的属性
        for k in mappings.keys():
            attrs.pop(k)

        # 将之前的uid/name/email/password以及对应的对象引用、类名字
        attrs[‘__mappings__‘] = mappings  # 保存属性和列的映射关系
        attrs[‘__table__‘] = name  # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)

class User(metaclass=ModelMetaclass):
    uid = (‘uid‘, "int unsigned")
    name = (‘username‘, "varchar(30)")
    email = (‘email‘, "varchar(30)")
    password = (‘password‘, "varchar(30)")
    # 当指定元类之后,以上的类属性将不在类中,而是在__mappings__属性指定的字典中存储
    # 以上User类中有
    # __mappings__ = {
    #     "uid": (‘uid‘, "int unsigned")
    #     "name": (‘username‘, "varchar(30)")
    #     "email": (‘email‘, "varchar(30)")
    #     "password": (‘password‘, "varchar(30)")
    # }
    # __table__ = "User"
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def save(self):
        fields = []  # 用来存储获取的字段名
        args = []  # 用来存储值
        for k, v in self.__mappings__.items():
            fields.append(v[0])
            args.append(getattr(self, k, None))

        # 由于传入的值需为字符串类型则进行转换
        args_temp = list()
        for temp in args:
            # 判断入如果是数字类型
            if isinstance(temp, int):
                args_temp.append(str(temp))
            elif isinstance(temp, str):
                args_temp.append("""‘%s‘""" % temp)
        sql = ‘insert into %s (%s) values (%s)‘ % (self.__table__, ‘,‘.join(fields), ‘,‘.join(args_temp))
        print(‘SQL: %s‘ % sql)

u = User(uid=12345, name=‘Michael‘, email=‘[email protected]‘, password=‘my-pwd‘)
# print(u.__dict__)
u.save()

  优化如下:

class ModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        mappings = dict()
        # 判断是否需要保存
        for k, v in attrs.items():
            # 判断是否是指定的StringField或者IntegerField的实例对象
            if isinstance(v, tuple):
                print(‘Found mapping: %s ==> %s‘ % (k, v))
                mappings[k] = v

        # 删除这些已经在字典中存储的属性
        for k in mappings.keys():
            attrs.pop(k)

        # 将之前的uid/name/email/password以及对应的对象引用、类名字
        attrs[‘__mappings__‘] = mappings  # 保存属性和列的映射关系
        attrs[‘__table__‘] = name  # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)

class Model(object, metaclass=ModelMetaclass):
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def save(self):
        fields = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v[0])
            args.append(getattr(self, k, None))

        args_temp = list()
        for temp in args:
            # 判断入如果是数字类型
            if isinstance(temp, int):
                args_temp.append(str(temp))
            elif isinstance(temp, str):
                args_temp.append("""‘%s‘""" % temp)
        sql = ‘insert into %s (%s) values (%s)‘ % (self.__table__, ‘,‘.join(fields), ‘,‘.join(args_temp))
        print(‘SQL: %s‘ % sql)

class User(Model):
    uid = (‘uid‘, "int unsigned")
    name = (‘username‘, "varchar(30)")
    email = (‘email‘, "varchar(30)")
    password = (‘password‘, "varchar(30)")

u = User(uid=12345, name=‘Michael‘, email=‘[email protected]‘, password=‘my-pwd‘)
# print(u.__dict__)
u.save()

  over~~~

  

原文地址:https://www.cnblogs.com/littlefivebolg/p/9420153.html

时间: 2024-08-30 15:46:05

04 -- 元类和ORM的相关文章

Python 元类实现ORM

ORM概念 ORM(Object Ralational Mapping,对象关系映射)用来把对象模型表示的对象映射到基于 SQL  的关系模型数据库结构中去.这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQL 语句打交道,只需简单的操作实体对象的属性和方法. 一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句. 示例: class User(父类省略): uid = ('uid', "i

元类实现ORM

1. ORM是什么 ORM 是 python编程语言后端web框架 Django的核心思想,"Object Relational Mapping",即对象-关系映射,简称ORM. 一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句 demo: class User(父类省略): uid = ('uid', "int unsigned") name = ('username'

元类应用ORM实现

首先看下一个简单的例子 # 需求 import numbers class Field: pass class IntField(Field): # 数据描述符 def __init__(self, db_column, min_value=None, max_value=None): self._value = None self.min_value = min_value self.max_value = max_value self.db_column = db_column if min

Python中的元类

从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象. class C(object): pass c = C() print c.__class__ print C.__class__ 代码中,通过"__class__"属性来查看对象的类型,对于类C对象本身,它的类型是type. 由于类也是对象,所以就可以在运行时动态的创建类,那么这时候就要用到内建函数type了. 再看type 从前面的文章了解到,可以通过

Python高级编程 面向对象、元类、多线程、异步IO、asyncio

—— 面向对象 —— 鸭子类型抽象基类类变量.对象变量的查找顺序静态方法.类方法.实例方法数据封装和私有属性对象的自省机制上下文管理器contextlib实现上下文管理器super函数的查找顺序mixin继承模式的应用 —— asyncio并发编程 —— 事件循环协程嵌套call_soon.call_later.call_atcall_soon_threadsafeThreadPoolExecutor+asyncioasyncio 模拟 http 请求future 和 taskasyncio 同

Python元类

学懂元类,首先要知道两句话: 道生一,一生二,二生三.三生万物 我是谁?我从哪里来?我要到那里去? 在Python的世界里,拥有一个永恒的道:type,如此广袤无垠的Python生态圈,都是由type产生出来的. 道生一,一生二,二生三,三生万物. 道:即就是type 一:即是metaclass 二:即是class(或者实例生成器) 三:即是instance 1 关于类 道和一,是我们今天讨论的命题,而二.三.和万物,则是我们常常使用的类.实例.属性和方法,用hello world来举例: 1

Python之元类ORM

什么是元类在Python中一切皆对象,类也是一个对象,实例对象由类创建出来的,类是由元类创建出来的.简而言之,用来创建类的类就叫元类(metaclass). 函数type其实就是一个元类,type就是Python在背后用来创建所有类的元类. globals()的作用globals()函数返回的是一个字典,里面保存的是所有当前位置的全部全局变量. type()动态创建类type('类名', (父类,) ,{属性}) 什么是ORM?ORM 即Object Relational Mapping,全称对

Django—— ORM查询(sql优化)优化了解,Django(元信息)元类建索引

Django(元信息)元类建索引 索引:索引的一个主要目的就是加快检索表中数据,索引是经过某种算法优化过的,因而查找次数要少的多.可见,索引是用来定位的. class Book(models.Model) name = models.CharField(max_length=64) class Meta: # 自定义表名 db_table = 'table_name' # 联合索引: 索引的一个主要目的就是加快检索表中数据 index_together = ('tag1', 'tag2') #

python中通过元类(TYPE)简单实现对象关系映射(ORM)

ORM是创建一个实例对象,用创建他的类名当做数据表名,用创建他的类属性对应数据表的字段,不需要在自己写复杂的sql语句,而是通过对实例对象的操作时,能让代码自动帮我们整理为对应的sql语句. class User(父类): uid = ("uid", "int unsigned") name = ("username", "varchar(20)") password = ("password", &quo