第十七章 元类编程

getattrgetattribute魔法函数

from datetime import date,datetime

class User:
    def __init__(self,name,birthday):
        self.name = name

        self.birthday = birthday
    
    def __getattr__(self,item):
        print("not find attr")

    def __getattribute__(self,item):
        return "juran"

if __name__ == "__main__":
    user = User("juran",date(year=1990,month=1,day=1))
    print(user.age)    

属性描述符

class User:
    def __init__(self,age):
        self.age = age
    
    def get_age(self):
        return (str(self.age) + '岁')
    
    def set_age(self,age):
        if not isinstance(age,int):
            raise TypeError('Type Error')
        self.age = age

如果User类中有多个属性都需要判断,那么就需要写多个方法,这些方法怎么复用呢?这个时候就要用到属性描述符

属性描述符,只要实现了get,set,delete任何一个方法,就被称为属性描述符

属性查找顺序

user = User(), 那么user.age 顺序如下:
1 如果"age"是出现在User或其基类的dict中, 且age是data descriptor,那么调用其get方法, 否则
2 如果"age"出现在user的dict中, 那么直接返回 obj.dict['age'],否则
3 如果"age"出现在User或其基类的dict
3.1 如果age是non-data descriptor,那么调用其get方法, 否则
返回 dict['age']
4 如果User有getattr方法,调用getattr方法,否则
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)     
    print(type(obj))    

使用type创建类

type还可以动态的创建类,type(类名,由父类组成的元组,包含属性的字典)

  • 第一个参数:name表示类名称,字符串类型
  • 第二个参数:bases表示继承对象(父类),元组类型,单元素使用逗号
  • 第三个参数:dict表示属性,这里可以填写类属性、类方式、静态方法,采用字典格式,key为属性名,value为属性值
  • 建议魔法方法不用type()里面的dict来创建
'''
type(name, bases, dict) -> a new type
'''
def demo(self):
    return self.name

def get_age(self):
    self.age = 18
    return self.age

User = type("User", (), {'name': '张老三', "info": demo, "age": get_age})
# dict 中name是对User类中添加属性
# dict 中info是对User类中添加demo方法
# dict 中age是对User类中添加get_age方法
obj = User()
print(obj.name)  >>>张老三
print(obj.info())  >>> 张老三
print(obj.age()) >>> 18

# 多重继承
class BaseClass(object):
    def test(self):
        return "base class"

    def __str__(self):
        return "this is test"


class BaseClass1(object):
    def test1(self):
        return "base class1"

User = type("User", (BaseClass, BaseClass1), {'name': 'juran'})
user = User()
print(user)
>>> this is test
print(user.test1())
>>> base class1

总结:
元类:创建类的类
元类:type(name, bases, dict)
解释:type(类名,由父类组成的元组,包含属性的字典)

  • 第一个参数:name表示类名称,字符串类型
  • 第二个参数:bases表示继承对象(父类),元组类型,单元素使用逗号
  • 第三个参数:dict表示属性,这里可以填写类属性、类方式、静态方法,采用字典格式,key为属性名,value为属性值

metaclass属性

如果一个类中定义了metalass = xxx,Python就会用元类的方式来创建类,metalass的优先级大于继承的父类,可参考实例,如下:

def upper_attr(class_name, class_parents, class_attr):
  
    newattr = {}
    for name, value in class_attr.items():
        
        if not name.startswith("_"):
            newattr[name.upper()] = value

    return type(class_name, class_parents, newattr)


class Foo(object, metaclass=upper_attr):
    # __metaclass__ = upper_attr
    name = 'juran'


f = Foo()
# print(hasattr(Foo, 'name'))
# print(hasattr(Foo, 'NAME'))

print(f.NAME)
>>>juran
print(f.name)
>>> AttributeError: 'Foo' object has no attribute 'name'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容