python 元类,abc.ABCMeta实现的虚类

一、元类
要理解元类,需要先理解python中的类,用class修饰的都可以叫做类,例如
class Class():
pass
c = Class()
print©
<main.Class object at 0x00000221E277EBE0>

而在python中远远不止于此,众所周知在python中“一切”皆是对象,注意是“一切”,也就是说类本身也是一个对象,你可以直接打印类本身,例如
Class
Out[45]:
main.Class

你可以为类本身增加属性
c = Class()
Class.b = 2
c.b
Out[51]:
2

我们平时用的类都是实例化以后的类,可以在任何时候动态的创建类,通常情况我们都是这样c=Class(),python解释器会将它认为是创建类,可是解释器本身是如何创建类的,答案是利用type
type平时我们可能认为是查看对象的类型,例如
type©
Out[52]:
main.Class

那么Class的类型是什么呢?
type(Class)
Out[53]:
type

看到没,Class的类型是type
我们可以用type直接生成一个类
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
type(‘Class_type’,(),{‘a’:1,‘b’:2})
Out[55]:
main.Class_type
Class_type = type(‘Class_type’,(),{‘a’:1,‘b’:2})
c_t = Class_type()
c.a
Out[58]:
1

到这里,可以引入元类了,什么是元类
元类就是用来创建这些类(对象)的类,元类就是类的类
type就是所有类的元类,可以理解为所有的类都是由type创建的
我们也可以创建自己的元类,这个类需要继承自type
__metaclass__属性
当我们定义了__metaclass__属性的时候,解释器会做些什么呢
例如我们定义了
class Test(Base):
pass

Class中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Test的类对象
如果Python没有找到__metaclass__,它会继续在Base(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
那么__metaclass__是啥东西呢?
答案就是可以创建类的东西,前面提过,类是由type创建的,所以__metaclass__内部一定要返回一个类,它可以是一个函数,也可以是一个类,而这个类就是我们自定义的元类,这个类必须继承自type
如果是个函数:例如我们想把类的所有属性变成大写
def upper_attr(future_class_name,future_class_parent,future_class_attr):
attrs = ((name,value) for name,value in future_class_attr.items() if not name.startswith(’__’))
uppercase_attr = dict((name.upper(),value) for name,value in attrs)
#通过type创建类对象
return type(future_class_name,future_class_parent,uppercase_attr)
class Test(object,metaclass=upper_attr):
a = ‘1’

当然我们也可以定义自己的元类来实现这一动作
class UpperAttrMetaClass(type):
def new(upperattr_metaclass,future_class_name,future_class_parent,future_class_attr):
attrs = ((name,value) for name,value in future_class_attr.items() if not name.startswith(’__’))
uppercase_attr = dict((name.upper(),value) for name,value in attrs)
return type.new(upperattr_metaclass,future_class_name,future_class_parent,uppercase_attr)
#return super(UpperAttrMetaClass,upperattr_metaclass).new(upperattr_metaclass,future_class_name,future_class_parent,uppercase_attr)

看起来有些负载,这些参数都是啥
我们看看type的文档
def init(cls, what, bases=None, dict=None): # known special case of type.init
“”"
type(object_or_name, bases, dict)
type(object) -> the object’s type
type(name, bases, dict) -> a new type
# (copied from class doc)
“”"
pass

type(name, bases, dict) -> a new type就是创建我们的类的方法,name是要创建的类的名字,base是要创建类的基类,dict是类的属性,正是因为有这个属性,我们才可以对类的创建自定义各种动作
通常元类用来创建API是非常好的选择,使用元类的编写很复杂但使用者可以非常简洁的调用API
著名的Django的ORM用的就是元类
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,self.name)

class StringField(Field):
def init(self,name):
super(StringField,self).init(name,‘varchar(100)’)

class IntField(Field):
def init(self,name):
super(IntField,self).init(name,‘bigint’)

class ModelMetaclass(type):
def new(cls, name, bases,attrs):
if name == ‘Model’:
return type.new(cls,name,bases,attrs)
print(‘Found model :%s’ % name)
mapping = {}
for k,v in attrs.items():
if isinstance(v,Field):
print(‘Found mapping:%s ==> %s’ %(k,v))
mapping[k] = v
for k in mapping.keys():
attrs.pop(k)
attrs[‘mappings’] = mapping
attrs[‘table’] = name
return type.new(cls,name,bases,attrs)

class Model(dict,metaclass=ModelMetaclass):
def init(self,**kw):
super(Model,self).init(**kw)

def __getattr__(self, item):
    try:
        return self[item]
    except KeyError:
        raise AttributeError('Model object ha no attribute: %s' % item)

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(self[k])
        #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))

class User(Model):
id = IntField(‘id’)
name = StringField(‘username’)
email = StringField(‘email’)
password = StringField(‘pwd’)

链接:https://www.jianshu.com/p/06c960020322
来源:简书

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值