Python元类编程

文章目录

    • property动态属性
    • \__getattr\_\_
    • \__getattribute__
    • 属性描述符
    • 属性的查找顺序
    • 自定义元类
    • metaclass
    • 元类实现简单orm

property动态属性

将取函数的模式变成取属性的模式
from datetime import date, datetime

class User:
    def __init__(self, name, birthday):
        self.name = name
        self.birthday = birthday
    def get_age(self):
        return datetime.now().year - self.birthday.year
    @property
    def age(self):	# @property会将方法名转变为 属性描述符
        return datetime.now().year - self.birthday.year
    
if __name__ == '__main__':
    user = User('bob', date(year=1980, month=1, day=1))
    print(user.get_age())
    print(user.age)   # 不用加括号, 效果与方法get_age()一样

也可以动态设置:

class User:
    def __init__(self):
        self._sex = 0

    @property
    def sex(self):
        return self._sex

    @sex.setter
    def sex(self, value):
        self._sex = value

if __name__ == '__main__':
    user = User()
    print(user.sex)		# 0
    user.sex = 1
    print(user.sex) 	# 1

__getattr__

在查找不到属性的时候调用, 并且不会抛出异常
class User:
    def __getattr__(self, item):
        return 'not found',item
    
user = User()
print(user.name)	# not fount name

利用__getattr__完成更复杂的逻辑 :

class User:
    def __init__(self, name, **info):	# 用户的详细信息将传入字典info中
        self.name = name
        self.info = info
    def __getattr__(self, item):	# 当某些属性找不到时
        return self.info[item]		# 直接获取字典中的值
    
if __name__ == '__main__':
    user = user('bob', age=19)
    print(user.age)		# 19

_getattribute_

把持所有属性获取的入口
class User:
    def __init__(self, name):
        self.name = name
    def __getattribute__(self, item):   # 不论获取什么属性都会先通过这个魔法属性
        return 'I love python'		# 全部返回'I love python', 不论是否有这个属性

user = User('Ami')
print(user.name)    # 'I love python'
print(user.age)    # 'I love python'

文章目录

    • property动态属性
    • \__getattr\_\_
    • \__getattribute__
    • 属性描述符
    • 属性的查找顺序
    • 自定义元类
    • metaclass
    • 元类实现简单orm

属性描述符

一个类实现任何一个__get__ , __set__ , __delete__ 魔法方法, 都可以称为属性描述符

class IntField:
    def __get__(self, instance, owner):		# 获取值时调用, 其中的参数instance是 User类的实例
        pass							  # 参数owner是 User类
    def __set__(self, instance, value):		# 设置值时调用
        pass
    def __delete__(self, instance):			# 删除值时调用
        pass
  
class User:
    age = IntField()
    # def __init__(self, age=None):    # 如果放到初始化函数中, 属性描述符并不会被调用
    # 	  self.age = age     

例子: 将类User的age属性强制规定为数字类型(虽然这个要求可以用很简单的代码完成, 但是当大量的属性都要依照这个要求时, 就会产生大量的代码冗余, 通过属性描述符, 我们可以将其都赋为属性描述符的实例即可)

import number

class IntField:
    def __set__(self, instance, value):
        if not isinstance(value, number.Integral):		# 如果不是Integral类型, 抛出异常
            raise ValueError('Integral is needed')
        self.value = value 	# 如果符合要求, 将其储存在属性描述符的实例中 !(而不是存储在instance中)
    def __get__(self, instance, owner):
        return self.value

class User:
    age = IntField()
    
if __name__ == '__main__':
    user = User()
    user.age = 20
    print(user.age)

属性的查找顺序

class User:
    def __init__(self, age):
        self.age = age
    def __getattribute__(self, item):  
        pass		
    def __getattr__(self, item)		
        pass
    
user = User(18)
如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’))
首先调用__getattribute__。如果类定义了__getattr__方法,
那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,
而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。
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__方法, 否则

(3.2)返回 __dict__[‘age’]

(4)如果User有__getattr__方法,调用__getattr__方法,否则

(5)抛出AttributeError

自定义元类

类也是对象, type是创建类的类

type动态创建类语法 :

User = type(object_or_name, base, dict)   # object_or_name: 名称, base: 基类(元组), dict: 属性 

利用这种语法添加方法:

def say(self):	# 一定要有一个参数
    return 'hello'

# 创建User类 
User = type('User', (), {
     'name':'LiLei', 'say':say})  # 其中base基类没有就写一个空元组

疑问: 通过type创建出来的类, {}中的属性是类属性还是实例属性?

u = User()
u.age = 18
print(User.name)
print(u.name)
print(u.__dict__)	# {'age': 18}
print(User.__dict__)	# {'name': 'LiLei', 'say':  ...... }

__dict__ 存储了该对象的一些属性, 由此看来, 利用type创建类是, {}中添加的属性是类属性(因为这本来就是创建一个类…)

如果有基类要继承 :

class BaseClass:
    def run(self):
        print('running...')
        
User = ('User', (BaseClass, ), {
     })  # 注意: 第二个参数一定是一个元组

元类的定义: 元类就是创建类的类

对象 <-- class <-- type

对象是类创建的(在python中类也是对象), 类是type创建的
class A:
    pass
a = A()
print(type(A))  #     一个类的type是 type
print(type(a))  # 	一个对象的type是 类
print(type(type))	# 	

文章目录

    • property动态属性
    • \__getattr\_\_
    • \__getattribute__
    • 属性描述符
    • 属性的查找顺序
    • 自定义元类
    • metaclass
    • 元类实现简单orm

metaclass

控制类的实例化过程
class MetaClass(type):  # 继承了type, 这个类就是元类
    pass

class User(metaclass=MetaClass):  # 注意: 通过mateclass指定参数, 控制User类的实例化过程
    pass

Python类的实例化过程: 会首先去 本类或基类或模块 中寻找 metaclass, 如果都没有找到, 就会去利用type去创建类对象. metaclass的优先级特别高

如果重写metaclass中的__new__, 将它生成对象的过程委托给它的父类(type) :

class MetaClass01(type):
    def __new__(cls, *args, **kwargs):
        print('MetaClass01.__new__')
        m_obj = super().__new__(cls, *args, **kwargs)
        print('m_obj', m_obj)   	# m_obj   产生了一个对象
        print('type(m_obj)', type(m_obj))         # type(m_obj) 
        print('type(type(m_obj))', type(type(m_obj)))   # type(type(m_obj)) 
        return m_obj

class User(metaclass=MetaClass01):
    # def __new__(cls, *args, **kwargs):  这里不要再写__new__, 会报错 
        # return super.__new__(cls)
     pass


u = User()
print('u ', u)

元类实现简单orm

ORM(object relational mapping)对象关系映射, 是通过使用描述对象和数据库之间的映射的 元数据, 将面向对象语言程序中的对象自动持久化到关系数据库中.
本质上就是将数据从一种形式转换到另一种形式. 这同时也暗示着更多的开销; 然而, 如果ORM作为一种 中间件实现, 则会有很多机会做优化, 而这些在手写的 持久层并不存在.

元数据:关于数据的数据, 描述数据属性的信息

中间件:是介于应用软件和系统软件之间的一类软件, 提供资源共享, 功能共享的目的

持久层:负责数据库的访问

实际应用在关系型数据库和业务实体对象之间做一个映射, 这样, 我们在具体的操作业务对象的时候, 就不需要再去和SQL语句打交道, 只要像平时操作对象一样操作它就可以了.

你可能感兴趣的:(python,python)