Python学习札记(四十) 面向对象编程 Object Oriented Program 11

本文介绍Python中使用type()函数动态创建类的方法及元类的基本概念。通过实例展示了如何利用type()函数创建带有特定行为的新类,并通过元类实现类级别的拦截与修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:使用元类

NOTE:

type()

1.type()函数可以用于检查一个类或者变量的类型。

#!/usr/bin/env python3

class Myclass(object):
    """docstring for Myclass"""
    def __init__(self):
        super(Myclass, self).__init__()

    def func(self):
        pass

def main():
    h = Myclass()
    print(type(h))

if __name__ == '__main__':
    main()
sh-3.2# ./oop12.py 
<class '__main__.Myclass'>

class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。

2.因此,我们可以通过type()函数在运行时动态创建一个类,这是动态语言的一个特点:

    NewClass = type('NewClass', (Myclass,), dict(func=run))
    h1 = NewClass()
    h1.func()
running

创建一个对象,需要给type()函数传入三个参数:

type(name, bases, dict) -> a new class

第一个是类名,第二个是继承的基类,第三个是绑定该类中的函数。

通过type()函数创建的类完全和用class关键字声明的类一样,因为Python解释器遇到class定义的时候,也是通过type()方法来定义一个类的。

type()方法支持动态创建一个类,也就是说,动态语言本身支持运行时动态创建类,这与静态语言有非常大的不同。

metaclass

元类本身而言,它们其实是很简单的:

1)拦截类的创建

2)修改类

3)返回修改之后的类

1.元(猿)类:是我们创建类的模板。

创建一个对象时,我们需要依据它的类进行创建;创建一个类的时候,我们需要依据它的元类来进行创建。

也就是说,可以把类看成是metaclass创建出来的“实例”。

#!/usr/bin/env python3

class Listmetaclass(type):
    """docstring for Listmetaclass"""
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class NewClass(list, metaclass=Listmetaclass): # 指示解释器在创建类的时候通过元类的__new__()创建
    pass

def main():
    h = NewClass()
    h.add(1)
    print(h)

if __name__ == '__main__':
    main()
sh-3.2# ./oop13.py 
[1]

事实上,将函数add直接写在一个继承的子类中会好很多,这是一个十分难懂的点。

2.特殊情况:“Object Relational Mapping”,即对象-关系映射。

#!/usr/bin/env python3

class Field(object):
    """docstring for Field"""
    def __init__(self, name, column_type):
        super(Field, self).__init__()
        self.name = name
        self.column_type = column_type
        
    def __str__(self):
        print('<%s:%s>' % (self.__class__.__name__, self.name))

class IntegerField(Field):
    """docstring for IntegerField"""
    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'int')
        
class StringField(Field):
    """docstring for StringField"""
    def __init__(self, name):
        super(StringField, self).__init__(name, 'string')

class Modelmetaclass(type): # type
    """docstring for Modelmetaclass"""
    def __new__(cls, name, bases, attrs):
        if name == 'Model':
            return type.__new__(cls, name, bases, attrs)
        print('Found name:%s' % name)
        mappings = dict() # save mappings of attributes
        for i, j in attrs.items():
            if isinstance(j, Field):
                print('mapping: %s ==> %s' % (i, j))
                mappings[i] = j # name i => 'Field'
        for i in mappings.keys():
            attrs.pop(i) # delete attrs that have been transfer to 'Field'
        attrs['__mappings__'] = mappings 
        attrs['__table__'] = name 
        return type.__new__(cls, name, bases, attrs)

class Model(dict, metaclass=Modelmetaclass):
    """docstring for Model"""
    # reuse the old definitions of functions
    def __init__(self, **kw):
        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))

# User provide the interfaces
class User(Model):
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

def main():
    # Create an object
    u = User(id=9, name='Wasdns', email='952693358@qq.com', password='1234567')
    # Save the object in the Database
    u.save()

if __name__ == '__main__':
    main()

具体解释请参考原文“美3333333”的回答。

2017.3.10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值