Python 的描述器Descriptors

Python 的描述器Descriptors

描述器的表现
—————————————————————————
用到3个魔术方法: __get__()\__set__()\__delete__()

方法签名:
object.__get__(self, instance, owner)
object.__set__(self, instance, value)
object.__delete__(self, instance)

self 指当前实例,调用者
instance是owner的实例
owner是属性的所属的类

描述器定义
——————————————————————————
Python中,一个类实现了__get__()\__set__()\__delete__()中的任一种方法,就是描述器。

非数据描述符:仅实现__get__
数据描述符:实现__get__ \ __set__

如果一个类的类属性设置为描述器,它被称为owner属主

属性的访问顺序
——————————————————————————
class A:
def __init__(self):
self.a1 = ‘a1’
print(‘A init’)

def __get__(self, instance, owner):
print(“A.__get__{} {} {}”.format(self, instance, owner))
return self

def __set__(self, instance, value):
print(“A.__set__{} {} {}”.format(self , instance , value))
self.data = value

def __delete__(self, instance):
print(“A.__delete__{} {}”.format(self , instance))
del self

class B:
x = A()
def __init__(self):
print(‘B init’)
self.y = ‘y1’
self.x = ‘b.x’ #增加实例属性

print(‘-‘*20)
print(B.x)
print(B.x.a1)

print(‘=’*20)
b = B()
print(b.x)
print(b.x.data)
print(b.__dict__)

b.x.a1 = 200

print(b.x.__dict__)
print(b.__dict__)

del b.x
print(b.x)
print(b.x.a1)
print(b.__dict__)

print(‘+’*20)

b.x = 300 #调用数据数据描述符的__set__方法,或非数据描述器的实例覆盖
B.x = 600 #赋值即定义,覆盖类属性
print(b.x)
print(b.__dict__)
print(B.__dict__)

属性查找顺序:
实例的__dict__优先于非数据描述符
数据描述符优先于实例的__dict__ (属性查找变成了描述器的__set__)

Python中的描述器应用
————————————————————————————
staticmethod() 和 classmethod()是非数据描述器。实例可以重新定义和覆盖方法。

property()是数据描述符。实例不能覆盖属性的行为。

class staticmethod:
def __init__(self, fn):
self._fn = fn
print(‘1 init’)

def __get__(self, instance, owner):
print(“1.__get__{} {} {}”.format(self, instance, owner))
return self._fn

class classmethod:
def __init__(self , fn):
self._fn = fn
print(‘2 init’)

def __get__(self, instance , owner):
from functools import partial
print(“2.__get__{} {} {}”.format(self , instance , owner))
return partial(self._fn, owner)

class property:
def __init__(self, fn):
self._fn = fn
self.setfn = None
print(‘3 init’)

def __get__(self, instance, owner):
print(“3.__get__{} {} {}”.format(self , instance , owner))
return self._fn(instance)

def __set__(self, instance, value):
print(“3.__set__{} {} {}”.format(self , instance , value))
self.setfn(instance,value)

# def getter(self):
# return self.__get__

def setter(self,fn):
self.setfn = fn
return self

class B:
@staticmethod # add = staticmethod(add) -> add
def add(x, y):
return x + y

@classmethod # add = staticmethod(add) -> add
def add(cls, x, y):
return x + y

@property # x = property(x) -> x
def x(self):
return self._x

@x.setter # x = x.setter(x) -> x
def x(self, value):
self._x = value

def __init__(self):
self._x = 6

b = B()
# print(b.add(3, 5))
# print(b.__dict__)
# print(B.__dict__)

print(b.x)
b.x = 10
print(b.x)

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/99690

(0)
JacoJaco
上一篇 2018-05-28
下一篇 2018-05-29

相关推荐

  • Python内置数据结构——字符串

    知识结构图 学习笔记 字符串 字符组成的有序序列,字符的集合 使用单引号、双引号、三引号引起来的字符序列 不可变对象 Unicode类型 定义 单引号、双引号、三引号 r、R:引号内的字符原样输出 元素访问 索引访问 可迭代 join连接 “string“.join(iteratable) 使用string作为分隔符将可迭代对象连接起…

    2018-03-31
  • Centtos7搭建ftp服务

    Centtos7搭建ftp服务 下载安装软件包 yum -y install vsftpd   开启启用ftp服务 systemctl start vsftpd    #设置立即启用该服务 systemctl status vsftpd   #查看该服务当前运行状态 systemctl enable vsftpd   #设置开机自动启用该服务 systemc…

    Python笔记 2018-07-07
  • 元组与字符串

    元组tuple 一个有序的元素组成的集合,不可变,用()表示,可进行索引,正索引:从左至右,从0开始;负索引:从右至左,从-1开始,正负索引不可超界,否则引发indexerror,tuple[index],index就是索引,使用中括号访问 元组是只读的,所以没有增,改,删的方法 冒泡法:属于交换排序,两两比较大小,交换位置,结果分为升序和降序排列 升序:n…

    Python笔记 2018-04-01
  • Python内置数据结构——字符串

    知识结构图 学习笔记 字符串 字符组成的有序序列,字符的集合 使用单引号、双引号、三引号引起来的字符序列 不可变对象 Unicode类型 定义 单引号、双引号、三引号 r、R:引号内的字符原样输出 元素访问 索引访问 可迭代 join连接 “string“.join(iteratable) 使用string作为分隔符将可迭代对象连接起…

    2018-03-31
  • 函数与生成器

    函数 由若干语句组成的语句块,函数名,参数列表构成,是组织代码的最小单元,完成一定的功能,结构化编程对代码的最基本的封装,封装的目的是为了复用 函数中没有return,隐式会返回一个none值 定义中的参数列表成为形式参数,只是一种形式表达,简称形参 调用时写的参数是实际参数,是实实在在传入的值,简称实参 函数的定义,只是声明了参数,不会执行,可以进行调用,…

    2018-04-16
  • python学习总结

    内建函数、函数、插入排序、树

    2018-04-15