零基础入门python3.7 ——基础知识总结(二十) 描述符和property()

一。描述符

描述符简单的来说就是一个类。只不过他定义了另一个类中属性的访问方式。也就是说一个类可以将属性管理权委托给描述符类。

二。描述符协议

  • __set__(self,obj,type=None) 设置属性时调用这个方法
  • __get__(self,obj,value) 读取属性时调用这个方法
  • __delete__(self,obj)对属性调用del时调用这个方法

在每次查找属性时。描述符协议中的方法都由类对象的特殊方法__getattribute__()调用。也就是说每一次使用类对象.属性的调用方式时,都会隐式的调用__getattribute__(),他分如下顺序查找属性。

  • 验证该属性是否为类实例对象的数据描述符
  • 如果不是 就查看该属性是否能在类实例对象的__dict__中找到
  • 最后。查看该属性是否为类实例对象的非数据描述符
class Person:
  def __init__(self, name=None, age=23):
    self.name = name
    self.age = age

  def __get__(self, instance, owner):
    return self.name

  def __set__(self, instance, value):
    self.age = value


class Person1:
  a = Person('小王', 30)
  b = 100

d = Person1
print("这里执行__get__方法:", d.a)
d.a = 1000000
print("这里执行赋值操作:", d.a)

这里执行__get__方法: 小王
这里执行赋值操作: 1000000

不难看出如果一个类的属性具有数据描述符,在每次查询这个属性时都会调用描述符的__get__()方法返回他的值。 每次对这个属性赋值时也会调用__set__()方法 

三  property()函数

通过类对象.属性访问定义在类中的属性。其实这种做法是欠妥的。他破坏了类的封装原则。正常情况下类包含的属性应该是隐藏的。只允许通过类提供的方法来间接的实现对类属性的访问和 操作。所以在不破坏类封装原则的基础上为了能够有效操作类中的属性。类中应包含多个读或写的getter或setter方法,这样就可以通过类对象.方法(参数)的方式操作属性。

class Person:
  def __init__(self, name):
    self.name = name

  def getName(self):
        return self.name

  def setName(self, name):
        self.name = name


a = Person("小王")
print(a.getName())
a.setName("小张")
print(a.getName())


小王
小张

由于这种方式过于繁琐。所以python提供了property()函数。可以实现不破坏类封装的前提条件下,可以让开发者依旧使用类对象.属性的方式操作类中的属性。

class Person:
  def __init__(self, name):
    self.__name = name

  def getName(self):
        return self.__name

  def setName(self, name):
        self.__name = name

  def deleteName(self):
        self.__name = '---'

  name = property(getName, setName, deleteName, '这个函数的作用时操作name属性')

help(Person.name)
a = Person("四川")
#  访问getName
print(a.name)
# 访问setName
a.name = "甘肃"
print(a.name)
#  访问deleteName
del a.name
print(a.name)



Help on property:

    这个函数的作用时操作name属性

四川
甘肃
---

第一个参数表示读取该属性值的方法。第二个参数表示设置该属性的方法。第三个参数表示删除该属性的方法。第四个参数表示函数的描述。而且这四个参数可以指定1个或者2个或者3个或者全部。 即参数的指定不是随意的。

需要说明的是。由于getName()要返回name的属性。如果使用self.name的话。其实本身有在调用getName()。这就出出现无限循环。 为了避免这种情况 。name属性必须设置为私有属性(后续详解)。即使用__name(两个下划线)。

你可能感兴趣的:(python)