第八章 元类编程复习

本文详细介绍了Python中的@property装饰器、属性描述符的工作原理,包括getter和setter的使用,以及动态属性的创建。同时,探讨了__new__和__init__的区别,强调__new__在对象创建阶段的作用,而__init__则负责初始化。最后,讨论了元类的概念,解释了如何自定义元类,并说明元类在Python对象创建过程中的角色。
摘要由CSDN通过智能技术生成

 

 

 

 

 

 

proterty动态属性 

property 作用和应用场景:

  • @property 优化了属性读取和设置的可读性
  • 需要限制属性的特征;
  • 只读属性。如果属性只可以读,不可以写,用起来很方便。
  • 这个属性根据一个变化的环境动态改变。
  • 举例https://www.cnblogs.com/wagyuze/p/10622561.html
from datetime import datetime, date


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

    # def get_age(self):
    #     return datetime.now().year - self.birthday.year

    @property
    def age(self):
        return datetime.now().year - self.birthday.year

    @age.setter
    def age(self, value):
        self._age = value


if __name__ == "__main__":
    user = User("tom", date(year=1987, month=11, day=9))
    user.age = 32  # 可以通过这种方式来读写类中的私有属性
    print(user._age)
动态属性 @property
from datetime import date, datetime
class User:
    def __init__(self, name, birthday):
        self.name = name
        self.birthday = birthday
        self._age = 0 # _代表这个属性不想暴露,代码上的规范。双下滑线隐藏。
        
    @property # 将age方法变为属性 、这个可以理解为get属性
    def age(self):
        # 获取他的年龄 当年年份-生日
        return datetime.now().year - self.birthday.year

    @age.setter # user.age=30 会运行这段代码
    def age(self, value):
        self._age = value

if __name__ == "__main__":
    user = User("bobby", date(year=1987, month=1, day=1))
    user.age = 30
    print (user._age)
    print(user.age)
属性描述符和属性的查找过程
"""
IntField 是专门判断是否为整数的类

实现get set delte任何一个魔法函数,IntField 就变为属性描述符
"""
import numbers

class IntField:
    """数据描述符"""
    def __get__(self,instance,owner):
        return self.value
    def __set__(self,instance,value):
        # 判断是否为Int类型
        if not isinstance(value,numbers.Integral):
            raise ValueError("int value need ")
        if value<0:
            raise ValueError("positive value need ")
        self.value = value
        pass
    def __delete__(self,instance):
        pass
     
class NoneDataIntField:
    """非数据属性描述符"""
    def __get__(self,instance,owner):
        return self.value 
    
class User:
    age = IntField()
    
    
if __name__ == "__main__":
    user = User()
    user.age=30 # 赋值的时候,其实会调用User的set方法。
    print(user.age)
"""
属性描述符查找的完整过程
如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’)) getattr全局
首先调用__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

"""

__new__ 和 __init__ 的区别

这两个方法的主要区别在于:__new__ 负责对象的创建而 __init__ 负责对象的初始化。在对象的实例化过程中,这两个方法会有些细微的差别,表现于:如何工作,何时定义

1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。

2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

但是说了这么多,__new__最通常的用法是什么呢,我们什么时候需要__new__?

自定义元类

元类
# python中一切皆为对象。
# 所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化)
# 基于python中一切皆为对象的概念分析出:我们用class关键字定义的类本身也是一个对象,
# 负责产生该对象的类称之为元类(元类可以简称为类的类),内置的元类为type
# class关键字在帮我们创建类时,必然帮我们调用了元类OldboyTeacher=type(...),那调用type时传入的参数是什么呢?必然是类的关键组成部分,一个类有三大组成部分,分别是
# 1、类名class_name='OldboyTeacher'
# 2、基类们class_bases=(object,)
# 3、类的名称空间class_dic,类的名称空间是执行类体代码而得到的
# 调用type时会依次传入以上三个参数
#一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,
# 我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类

参考文章:

原文链接:https://blog.csdn.net/sunt2018/article/details/88696305

原文链接:https://blog.csdn.net/sunt2018/article/details/88696305

https://www.cnblogs.com/xiaoyaotx/p/12548892.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落雪snowflake

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值