zoukankan      html  css  js  c++  java
  • 面向对象高级编程——使用@property

    在绑定属性的时候,如过我们直接把属性暴露出去,虽然写起来简单,但是,没办法检查参数,导致可以把成绩随意改:

    s = Student()
    s.score = 9999  #不符合常规依然可以更改

    这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score方法里,就可以检查参数:

    class Student(object):
    
        def get_score(self):
             return self._score
    
        def set_score(self, value):
            if not isinstance(value, int):
                raise ValueError('score must be an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 ~ 100!')
            self._score = value

    现在,对任意的Student实例进行操作,就不能随心所欲地设置score了:

    >>> s = Student()
    >>> s.set_score(60) # ok!
    >>> s.get_score()
    60
    >>> s.set_score(9999)
    Traceback (most recent call last):
      ...
    ValueError: score must between 0 ~ 100!

    但是,上面地调用方法又略显复杂,没有直接用属性这么直接简单。

    有没有既能检查参数,又可以用类似属性这样简单地方式来访问类地变量了?对于追求完美地python程序员来说,这是必须要做到的!

    还记得装饰器可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用,python内置的@propert装饰器就是负责把一个方法变成属性调用:

    class Student(object):
    
        @property
        def score(self):
            return self._score
    
        @score.setter
        def score(self, value):
            if not isinstance(value, int):
                raise ValueError('score must be an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 ~ 100!')
            self._score = value

    @property的实现比较复杂,我们先只关注如何使用。把一个getter方法变成属性,只需要加上@property就可以实现了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是我们就有了一个可控的属性操作:

    >>> s = Student()
    >>> s.score = 60 # OK,实际转化为s.set_score(60)
    >>> s.score # OK,实际转化为s.get_score()
    60
    >>> s.score = 9999
    Traceback (most recent call last):
      ...
    ValueError: score must between 0 ~ 100!

    注意到这个神奇的@property,我们对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法实现的。

    还可以定义制度属性,只定义getter方法,不定义setter方法就是一个只读属性。

    class Student(object):
    
        @property
        def birth(self):
            return self._birth
    
        @birth.setter
        def birth(self, value):
            self._birth = value
    
        @property
        def age(self):
            return 2015 - self._birth

    @property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查。

    class Goods:
        __discount = 0.8
        def __init__(self,name):
            self.name = name
            self.__price = 100
    
        @property    #将一个方法变成属性
        def price(self):
            return self.__price * Goods.__discount
    
        @price.setter
        def price(self,new_price):
            self.__price = new_price
    
        @price.deleter
        def price(self):
            del self.__price
    
    apple = Goods('苹果')
    print(apple.price)   #原本是apple.price()
    apple.price = 200    #有=就可以关联到属性,原本是不能访问的,因为隐藏了
    print(apple.price)
    # del apple._Goods__price  
    del apple.price          #del会关联到deleter
    # print(apple.price)

    如果没有@property就没有下面的setter和delete。

    class Foo:
        @property
        def AAA(self):   #AAA已经变成了属性
            print("get的时候运行我")
    
        @AAA.setter       #现在我想修改或重赋值AAA的属性,就可以关联到这里
        def AAA(self,value):
            print("set的时候运行我")
    
        @AAA.deleter       #我想删除属性的时候,出现删除的命令的时候就会关联到这
        def AAA(self):
            print("delete的时候运行我")
    
    f1 = Foo()
    f1.AAA
    f1.AAA = 'aaa'
    del f1.AAA
    
    结果:
    get的时候运行我
    set的时候运行我
    delete的时候运行我
  • 相关阅读:
    scala之伴生对象的继承
    scala之伴生对象说明
    “Failed to install the following Android SDK packages as some licences have not been accepted” 错误
    PATH 环境变量重复问题解决
    Ubuntu 18.04 配置java环境
    JDBC的基本使用2
    DCL的基本语法(授权)
    ZJNU 1374
    ZJNU 2184
    ZJNU 1334
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/7868106.html
Copyright © 2011-2022 走看看