python高级特性之二:描述器初探

44 篇文章 0 订阅
18 篇文章 1 订阅
本文介绍了Python中的描述器(Descriptor)概念,通过实例展示了如何利用描述器实现属性托管、敏感数据保护以及一般属性的自动化管理,实现了面向对象的封装和外包机制。通过托管属性和Trusteeship类,演示了描述器在控制属性查找和数据操作中的重要作用。
摘要由CSDN通过智能技术生成

前置认识

'''
学习用python的高级特性2:描述器descriptor

'''
# 1 example
class Ten:
    def __get__(self, instance, owner):
        return 10

class A:
    x = 5
    y = Ten()

print(A.x, A.y)
#描述器A.y和属性差别就是 直接调用了 __get__; 相当于每次.()引用属性就调用get, call方法?

# 2 listdir, 统计数目的get函数
import os
class DirectorySize:
    def __get__(self, instance, owner):
        return len(os.listdir(instance.dirname))

class Directory:
    size = DirectorySize()

    def __init__(self, dirname):
        self.dirname = dirname

s =  Directory('../')
g = Directory('../DeepPython')
print(s.size, g.size)
#从输出看,这个--get--三个入参含义是self为DirectorySize实例,instance是调用者实例(s,g), owner是类Directory


‘’‘
output:
5 10
13 3
‘’’

  • 利用了类的自动调用get机制,完成某些计算、存储、读写任务在专门类中,实现类似于java那种面向对象的“封装机制”或者说python中更像的“外包机制”;
  • 装饰器是由别人替我完成边边角角工作,而描述器更像替我完成核心、专业化的工作。

描述器举例之一:托管


# 3 描述器目标是提供一个hook钩子,将对象存储在类变量中,控制属性查找时间(. dot引发);
# example:托管属性,descriptor作为托管器,创建私有的属性,功其它类调用;需要get、set属性来自动化读写
import logging
logging.basicConfig(level = logging.INFO)

class Trusteeship:
    def __get__(self, instance, owner):
        value = instance._age
        logging.info('Access %r get %r','age', value) #%r means cannoical string representation of object
        return value

    def __set__(self, instance, value):
        logging.info('Update age as %r', value)
        instance._age = value

class DesEx:

    age = Trusteeship() # call descriptor
    def __init__(self, name, age):
        self.age = age   #写了一次,call get()
        self.name = name

    def incAge(self):
        self.age = self.age + 1 #读写各一次,call get(),set()

alice = DesEx('alice', 23)
alice.incAge()

'''
Output:
5 10
13 3
INFO:root:Update age as 23
>>alice.incAge()
INFO:root:Access 'age' get 23
INFO:root:Update age as 24
'''

  • 显然,敏感的“年龄”数据告诉Trusteesheet管理,person类本身可以不知道,不碰同时完成年龄增加、年龄获取任务。
  • 关键方法是: get(), set()一对,每次读都调用get,每次写都调用set(比如等式左边就是写,右边就是读,自加需读写都要);内部默认参量self,instance和owner分别表示托管描述器本身self(name,age属性,乃至下面的public_name属性都是self这边建立。)instance表示调用托管描述器的实例,owner是实例的类对象

描述器:属性托管的推广到一般属性

# 4 托管任意属性,制定init方法,设置getattr,setattr,

class TrusteesheetA:
    def __set_name__(self, owner, name):
        self.pubblic_name = name  #public_name只是一个对外展示(存储了初始的名字,其实没有真正赋值或者刷新
        self.private_name = '_' + name

    def __get__(self, instance, owner):
        value = getattr(instance, self.private_name)
        logging.info('New Trusteesheet access %r, get %r', self.pubblic_name, value)
        return value

    def __set__(self, instance, value):
        setattr(instance, self.private_name, value)
        logging.info('Updating %r to %r', self.pubblic_name, value)

class Person:
    name = TrusteesheetA() # set_name
    age = TrusteesheetA()

    def __init__(self, name, age):
        self.name = name  #set once
        self.age = age    #set

    def birthday(self):
        self.age = self.age + 1 # get,set

    def changeName(self):
        self.name = self.name + ' Karl'

bob = Person('bob',30)
bob.birthday()
bob.changeName()

'''
output:
INFO:root:Updating 'name' to 'bob'
INFO:root:Updating 'age' to 30
INFO:root:New Trusteesheet access 'age', get 30
INFO:root:Updating 'age' to 31
INFO:root:New Trusteesheet access 'name', get 'bob'
INFO:root:Updating 'name' to 'bob Karl'
'''
  • set_name用于初次调用,保存属性对外名称 self.public_name, 对内名称为self.private_name 分离操作!
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值