python--基础知识点--object、type以及自定义元类

一、object和type
1、概念

python中一切皆对象,类也是对象。

总的来说,面向对象体系里,有两种关系,一种是父子关系,通过父类与子类来描述,另一种是类型实例关系,通过类和实例来描述。而两条规则,是将类之间,类与实例之间的关系联系在一起。

object: object类是所有类的超类。因继承具有传递性,所以object派生出其它所有类,包括type类。

type: type类实现了python中的所有的类, 包括object类和type类本身。

2、虚线向上和虚线向下规则

虚线向上规则:如果X是A的实例,同时A又是B的子类,那么,X也是B的实例

虚线向下规则:如果B是M的实例,同时A是B的子类,那么,A也是M的实例。
在这里插入图片描述
虚线:代表实例关系,即由某个类的实例对象用虚线指向该类。如上图实例X用虚线指向实现它的类A。

实线:代表父子关系(继承关系),即由某个派生类用实线指向它的父类。如上图派生类A用虚线指向它的父类B。

虚线向上规则:上图中X是A的实例对象,A又是B的派生类,则X也是B的实例对象。即将X端射向A端的虚线,向上抬,射向B端(你应该可以看到上图右上方有一条标志为implied[这个单词意思是隐藏]的向上虚线),就实现了表述X也是是B的实例的目的。

同理虚线向下规则也是这样推出。

3、object和type之间的关系

在这里插入图片描述
上图中的关系:

print(issubclass(type, object))    # type继承自object
print(issubclass(object, object))  # object继承自object
print(issubclass(type, type))      # type继承自type
print(isinstance(object, type))    # type 实例化出object
print(isinstance(type, type))      # type实例化出type
print(isinstance(object, object))  # object 实例化出object


"""
运行结果:
True
True
True
True

Process finished with exit code 0
"""
二、自定义元类
1、概念

元类:创建类的类,即type。

自定义元类:继承type。可通过自定义元类创建一个满足自己需求的类

2、自定义元类创建自定义类的原理

(i) 自定义元类__new__方法实现创建自定义类对象
(ii) 自定义元类__init__方法实现初始化自定义类对象
(iii) 自定义元类__call__方法实现实例化自定义类对象,即实例化自定义类对象时会运行自定义元类中重写的__call__方法,并在此过程中会调用自定义类对象中重写的__new__和__init__,进行创建所创建类对象的实例对象和初始化该实例对象。

3、type、object、自定义元类、自定义类、自定义类实例之间的关系

在这里插入图片描述

4、示例
class A(type):
    def __new__(cls, class_name, bases_name, attribute_dict):
        print("A.__new__++++start")
        b_class = super().__new__(cls, class_name, bases_name, attribute_dict)
        print("A.__new__++++end")
        return b_class

    def __init__(self, class_name, bases_name, attribute_dict):
        print("A.__init__++++start")
        super().__init__(class_name, bases_name, attribute_dict)
        print("A.__init__++++end")

    def __call__(self, *args, **kwargs):
        print("A.__call__++++start")
        test = super(A, self).__call__(*args, **kwargs)
        print("A.__call__++++end")
        return test


"""
metaclass=A 解析:
在解释器执行到class B(object, metaclass=A)时运行过程如下
下面的csl_、bases_、attritube_解释器会自动传递
相当于 B = A(cls_, bases_, attritube_), B指向转变为A的实例对象。这也解释了:
(1)为什么加上该语句后B的属性会改变为A的属性,如:print(B.__class__)为A;
(2)为什么A的__new__和__init__只会执行一次;
(3)后期调用B实际上调用该A实例所绑定的__call__方法。

此过程与装饰函数为装饰某个类的过程类似
不同之处在于对于外函数解释器自动传递的参数不同,装饰函数为装饰某个类时解释器只为其传递所要装饰的类的cls。
"""
class B(object, metaclass=A):
    name = "zhangsna"
    def __new__(cls):
        print("B.__new__++++start")
        print("B.__new__++++end")
        return super(B, cls).__new__(cls)

    def __init__(self):
        print("B.__init__++++start")
        super(B, self).__init__()
        print("B__init__++++end")


if __name__ == '__main__':
    print(B.__class__)
    B()  # 其实调用的时B所绑定的A的__call__方法


"""
运行结果:
A.__new__++++start
A.__new__++++end
A.__init__++++start
A.__init__++++end
<class '__main__.A'>
A.__call__++++start
B.__new__++++start
B.__new__++++end
B.__init__++++start
B__init__++++end
A.__call__++++end

Process finished with exit code 0
"""
5、应用

使用自定义元类创建ORM的实例,通过创建一个类似Django中的ORM来熟悉一下元类的使用,通常元类用来创建API是非常好的选择,使用元类的编写很复杂但使用者可以非常简洁的调用API。

#我们想创建一个类似Django的ORM,只要定义字段就可以实现对数据库表和字段的操作。
class User(Model):
    # 定义类的属性到列的映射:
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

例如:

# 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
# 保存到数据库:
u.save()

接下来我么来实现这么个功能:

# 一、首先来定义Field类,它负责保存数据库表的字段名和字段类型:
class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self):
        return '<%s:%s>' % (self.__class__.__name__, self.name)


class StringField(Field):
    def __init__(self, name):
        super(StringField, self).__init__(name, 'varchar(100)')


class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'bigint')


# 二、定义元类,控制Model对象的创建,将接口类转化为逻辑处理所需的类
class ModelMetaclass(type):
    """
    定义元类
    """
    def __new__(cls, name, bases, attrs):
        print(name)
        print(bases)
        print(attrs)
        if name == 'Model':
            return super(ModelMetaclass, cls).__new__(cls, name, bases, attrs)
        mappings = dict()
        for k, v in attrs.items():
            # 保存类属性和列的映射关系到mappings字典
            if isinstance(v, Field):
                print('Found mapping: %s==>%s' % (k, v))
                mappings[k] = v
        for k in mappings.keys():
            # 将类属性移除,使定义的类字段不污染User类属性,只在实例中可以访问这些key
            attrs.pop(k)
        attrs['__table__'] = name.lower()  # 假设表名和为类名的小写,创建类时添加一个__table__类属性
        attrs['__mappings__'] = mappings  # 保存属性和列的映射关系,创建类时添加一个__mappings__类属性
        return super(ModelMetaclass, cls).__new__(cls, name, bases, attrs)


# 三、编写Model基类
class Model(dict, metaclass=ModelMetaclass):

    def __init__(self, **kw):
        print("ccccccccc")
        print(kw)
        print("dddddddd")
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))
        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))


# 最后,我们使用定义好的ORM接口,使用起来非常的简单。
class User(Model):
    # 定义类的属性到列的映射:
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')


if __name__ == '__main__':
    print("aaaaaaaaa")
    print(User.__table__)
    print((User.__mappings__))
    print("bbbbbb")
    # 创建一个实例:
    u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
    # 保存到数据库:
    u.save()



"""
运行结果:
Model
(<class 'dict'>,)
{'__module__': '__main__', '__qualname__': 'Model', '__init__': <function Model.__init__ at 0x000001EC52D5CA60>, '__getattr__': <function Model.__getattr__ at 0x000001EC52D5CAF0>, '__setattr__': <function Model.__setattr__ at 0x000001EC52D5CB80>, 'save': <function Model.save at 0x000001EC52D5CC10>, '__classcell__': <cell at 0x000001EC52D6BBB0: empty>}
User
(<class '__main__.Model'>,)
{'__module__': '__main__', '__qualname__': 'User', 'id': <__main__.IntegerField object at 0x000001EC52D6BAC0>, 'name': <__main__.StringField object at 0x000001EC52D6BA60>, 'email': <__main__.StringField object at 0x000001EC52D6BA00>, 'password': <__main__.StringField object at 0x000001EC52D6B9A0>}
Found mapping: id==><IntegerField:id>
Found mapping: name==><StringField:username>
Found mapping: email==><StringField:email>
Found mapping: password==><StringField:password>
aaaaaaaaa
user
{'id': <__main__.IntegerField object at 0x000001EC52D6BAC0>, 'name': <__main__.StringField object at 0x000001EC52D6BA60>, 'email': <__main__.StringField object at 0x000001EC52D6BA00>, 'password': <__main__.StringField object at 0x000001EC52D6B9A0>}
bbbbbb
ccccccccc
{'id': 12345, 'name': 'Michael', 'email': 'test@orm.org', 'password': 'my-pwd'}
dddddddd
SQL: insert into user (id,username,email,password) values (?,?,?,?)
ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']

Process finished with exit code 0
"""

[参考博客]
https://www.cnblogs.com/tkqasn/p/6524879.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值