元类编程之前先学习两个魔法函数
# __getattr__ 和__getattribute__魔法函数
# __getattr__ 查找不到属性的时候调用
# __getattribute__
from datetime import date
class User:
def __init__(self, name, birthday,info={}):
self.name = name
self.birthday = birthday
self.info = info
# 在查找不到属性的时候调用
def __getattr__(self, item):
# print('attribute not find')
# print(item)
# return 'attribute not find'
return self.info[item]
# return self.info.get(item)
# __getattribute__在__getattr__之前执行 不轻易去重写
# def __getattribute__(self, item):
# return 'juran'
# 打印没有反回值的函数返回None
# def demo(): pass
# print(demo()) # None
if __name__ == '__main__':
# 1990-1-1
user = User('ellen', date(year=1990, month=1, day=1),info={'age':18})
# print(user.name)
print(user.age) # 18
#print(user.birthday)
属性描述符
class User(object):
def __init__(self, age):
self.age = age
def get_age(self):
return self.age
def set_age(self,age):
if not isinstance(age,int):
raise TypeError('Type Error')
self.age = age
# 以上只是对age一个属性做整数验证,如果还有姓名name属性等,也要做字符串验证,
# 比较麻烦,可以用什么方法解决?就可用属性描述符:
# 属性描述符 __get__ __set__ __delete__
# Django
class IntFild(object):
'''数据描述符 有__get__ 和__set__等方法 只有 __get__是非数据描述符'''
def __get__(self, instance, owner):
print('__get__')
print(owner)
print(instance)
return self.values #
def __set__(self, instance, value):
print('__set__')
print(instance) # 对象
# print(value) # 值 30 对值做验证
if not isinstance(value,int):
raise ValueError('Value Error')
self.values = value
def __delete__(self, instance):
pass
# 非数据属性描述 只有 __get__ 方法
class NoneDataIntFild:
def __get__(self, instance, owner):
return owner
class User:
age = IntFild()
user = User()
user.__dict__['age'] = 18
user.age = 30
print(user.age)
属性查找顺序
user = User 那么user.age 顺序如下
- 如果’age’是出现在User或其基类的__dict__中 且age是data descriptor
那么调用其__get__方法,否则 5-抛出AttributeError
2.如果’age’是出现在User的__dict__中 那么返回obj.dict[‘age’],否则 5
3.如果’age’是出现在User或其基类的__dict__中,两各种情况:
3.1 如果age是non-data descriptor,那么调用其__get__方法 否则5
3.2 返回__dict__[‘age’] - 如果User有__getattr__方法 调用__getatter方法
5.抛出AttributeError
自定义元类
def create_class(name):
if name == 'user':
class User:
def __str__(self):
return 'user'
return User
elif name == 'student':
class Student:
def __str__(self):
return 'Student'
return Student
if __name__ == '__main__':
myclass = create_class('user')
obj = myclass()
print(obj) # user
# print(type(obj))
元类就是创建类的类 就是说的type
动态创建类
使用type创建类
'''
type两个功能:
1.可以用type查看数据类型
2.还可以动态的创建类 type(类名:由父类组成的元组,包含属性的字典)
metacalss 属性
如果一个类中定义了metacalss = xxx.Python就会用元类的方式来创建类
'''
'''
type(name, bases, dict) -> a new type
name - > 类名
bases -> 继承
dict -> 方法
'''
# 使用type创建类和一般正常创建的类一样没有区别
User = type('User',(),{})
obj = User()
print(obj) # 相当于创建了类 <__main__.User object at 0x00000000021A8630>
# 添加属性
User = type('User',(),{'name':'ellen'})
obj = User()
print(obj)
print(obj.name) # ellen
# 添加一个方法
def demo(self):
return self.name
def get_age(self):
self.age = 18
return self.age
# 定义魔法方法 尽量不用魔法方法创建方法
def __init__(self):
self.sex = 1
User = type('User',(),{'name':'ellen','info': demo,'age': get_age,})
obj = User()
print(obj.info())
print(obj.age())
# 类的继承
class BaseClass(object):
def test(self):
return 'base class'
# 可以继承魔法方法
def __str__(self):
return 'this is test'
class BaseClass1(BaseClass):
def test1(self):
return 'base class1'
b = BaseClass()
print(b) # this is test
User = type('User',(BaseClass,BaseClass1),{'name':'ellen'})
user = User()
print(user.test()) # 继承 base class
print(user.test1()) # 可继承多个 base class1
# 正常创建类
class User1(object):
pass
obj1 = User()
print(obj1) # <__main__.User object at 0x00000000021A8748>
metaclass 属性
# metaclass 属性 python2 和 pytho3 有区别
'''
如果一个类中定义了metaclass = xxx.Python就会用元类方式创建类
从而可以控制类的创建行为
'''
'''
def upper_attr(class_name,class_parent,class_attr): # 1.传类名 2.继承父类,3.类的属性
# print(class_name)
# print(class_parent)
# print(class_attr)
newattr = {}
for name,value in class_attr.items():
# print(name)
# print(value)
if not name.startswith('_'):
newattr[name.upper()] = value
return type(class_name,class_parent,newattr)
class Foo(object,metaclass=upper_attr):
name = 'ellen'
f = Foo()
print(hasattr(Foo,'name'))
print(hasattr(Foo,'Name'))
# print(f.NAME)
# print(f.Name)
'''
# 类的实例化中 首先寻找metaclass 如果没有再找其他类
class Demo(object):
def __new__(cls, *args, **kwargs):
pass
class MetaClass(type):
def __new__(cls, *args, **kwargs):
pass
class User(Demo,metaclass= MetaClass):
pass
obj = User()