python 元类的使用


class Animal(object):
"""a class representing an animal"""
def __init__(self,name):
self.name = name

def eat(self):
pass

def go_to_vet(self):
pass

animal = Animal('cat')
print(type(Animal))
print(animal)

#用type方式创建类******************************************************************
def init(self,name):
self.name = name

def eat(self):
pass

def go_to_vet(self):
pass

Animal = type('Animal',(object,),
{'__doc__':"a class representing an animal",'__init__':init,
'eat':eat,'go_to_vet':go_to_vet})

animal = Animal('dog')
print(animal)

#创建子类
def meow(self):
return None

def purr(self):
return None



Cat = type('Cat',(Animal,),{
'meow':meow,
'purr':purr
})

cat = Cat(name='xiaohuang')
print(cat)

print(type(Cat))

#元类示例******************************************************************
class Meta(type):
"""a metaclass that adds no actual functionality"""
def _(cls,name,bases,attrs):
"""

:param name: 类型:字符串 类名
:param bases: 类型:元组,继承的基类
:param attrs: 类型:字典 属性
:return: 类
"""
return super(Meta, cls).__new__(cls,name,bases,attrs)


#何时使用元类******************************************************************
# 1.说明性类声明,现有示例django模型声明

# 2.类验证 (foo 和 bar属性两个只能包含一个)
class FooOrbar(type):

def __new__(cls, name,bases,attrs):
if 'foo' in attrs and 'bar' in attrs:
raise TypeError('Class %s cannot contain both foo and bar'%name)
if 'foo' not in attrs and 'bar' not in attrs:
raise TypeError('Class %s must provide either foo or bar'%name)
return super(FooOrbar,cls).__new__(cls,name,bases,attrs)


class Valid(metaclass=FooOrbar):
foo = 42

v = Valid()

class Invalid(metaclass=FooOrbar):
foo =41


# 以上实现存在一个问题,他的子类并不会继承该功能,原因是元类直接检查attrs属性,但这只包含所声明的类属性集,
# 他并不知道继承自基类的属性

# class AlsoValid(Valid):
# pass


# 改进如下
class FooOrBarUpdate(type):
def __new__(cls, name,bases,attrs):
"""实例化,从基类中获取了所有的属性"""
answer = super(FooOrBarUpdate, cls).__new__(cls,name,bases,attrs)

if hasattr(answer,'foo') and hasattr(answer,'bar'):
raise TypeError('Class %s cannot contain both foo and bar'%name)

if not hasattr(answer,'foo') and not hasattr(answer,'bar'):
raise TypeError('Class %s must provide either foo or bar' % name)

return answer

# 3.非继承性

class Meta1(type):
def __new__(cls, name,bases,attrs):
if attrs.get('abstract',False):
return super(Meta1,cls).__new__(cls,name,bases,attrs)

class SubClass(metaclass=Meta1):
abstract = False

# 以上元类定义存在一个问题,任何子类都需要显示的声明自己并不是抽象类
# 改进如下 :
class MetaUpdate1(type):

def __new__(cls, name,bases,attrs):
if attrs.pop('abstract',False):
return super(MetaUpdate1, cls).__new__(cls,name,bases,attrs)

#meta-coding***************************************************************

class Logged(type):

""""a meta class that cause classes that it creates to log their function calls"""
def __new__(cls, name,bases,attrs):
for k,v in attrs.items():
if callable(v):
attrs[k] = cls.log_call(v)

return super(Logged, cls).__new__(cls,name,bases,attrs)

@staticmethod
def log_call(v):

def inner(*args,**kwargs):

try:
response = v(*args,**kwargs)
print('%s函数被调用,参数为%s,字典关键字为:%s.'%(v.__name__,args,kwargs))
return response
except Exception as e:
print('%s函数被调用,抛出异常:%s'%(v.__name__,e))
raise e

return inner

class MyClass(metaclass=Logged):

def foo(self):
pass

def bar(self):
raise TypeError('oh,noes')

obj = MyClass()
obj.foo()
obj.bar()

posted @ 2020-07-31 16:57  ~相忘于江湖  阅读(163)  评论(0)    收藏  举报