25.Python编程:@property详解

作者: TensorFlow开发者 | 来源:发表于2018-05-30 20:51 被阅读19次

    在前面学习访问权限一文中,我们设计了一个SmartPhone类,

    # 定义一个SmartPhone类
    class SmartPhone(object):
        __os = ""  # 私有属性:系统
        __type = ""  # 私有属性:品牌
        __memory = "4GB"  # 私有属性:内存大小 默认单位GB
    
        # 构造方法
        def __init__(self, os, type, memory):
            self.__os = os
            self.__type = type
            self.__memory = memory
    
        def print_phone_info(self):
            print('os:', self.__os, '\n品牌:', self.__type, '\n内存大小:', self.__memory)
    
        #  对外界提供获取__os的值的方法
        def get_os(self):
            return self.__os
    
        #  对外界提供设置__os的值的方法
        def set_os(self, os):
            self.__os = os
    
        #  对外界提供获取__type的值的方法
        def get_type(self):
            return self.__type
    
        #  对外界提供设置__type的值的方法
        def set_type(self, types):
            self.__type = types
    
        #  对外界提供获取__memory的值的方法
        def get_memory(self):
            return self.__memory
    
        #  对外界提供设置__memory的值的方法
        def set_memory(self, memory):
            self.__memory = memory
    

    如果你观察的足够仔细,你会发现,例子中我们属性只有3个,增加了3对get\set方法,也就是6个方法。我们已经知道,当把属性设置为私有属性时,通过添加对应的get方法获取其值,通过添加对应的set方法设置值,还可以通过set方法做数据的有效性校验、过滤等操作。

    那么,如果属性非常多时,我们上面的做法又会显得非常麻烦,这有没有好的解决方案呢?答案是有的。python中给我们提供了一些关键词@property,专门帮我们解决上面的问题,我们今天就详细学习这些知识。

    @property

    @property是Python内置的一种装饰器。(什么是装饰器,暂时可以理解为给函数动态加上功能的一种语法)。@property的内部实现是比较复杂的。现在我们先学会如何使用,等以后有了一定的分析源码的能力,再回过头分析其内部实现。

    从今天以后,在Python编程中,你一看到@property,第一反应就是:@property专门负责把一个方法变成同名属性的。

    # 定义一个Car类
    class Car(object):
    
        @property
        def price(self):
            print("调用了:@property修饰的price方法")
            return self.__price
    
        @price.setter
        def price(self, price):
            if price < 0:
                price = 0
            print("调用了: @price.setter修饰的price方法")
            self.__price = price
    

    解释:上面我们用@property修饰了方法price(self):,此时@property会把方法price直接变成同名属性。当我们获取price属性的值时,实际上就是调用的此方法。

    此时,@property本身又自动创建了另一个装饰器@price.setter,负责把一个方法变成属性赋值,即:price的setter方法。于是,@price.setter修饰的price其实是set方法,当我们给price赋值时,实际上就是调用的此方法。

       @price.setter
       def price(self, price):
            if price < 0:
                price = 0
            print("调用了: @price.setter修饰的price方法")
            self.__price = price
    

    接下来验证上面的解析:

    # 创建一个Car类型的对象
    c = Car()
    c.price = -100000 # 故意设置为负值,
    print("小汽车的价格:price = ", c.price)
    

    运行结果:

    调用了: @price.setter修饰的price方法
    调用了:@property修饰的price方法
    小汽车的价格:price =  0
    

    可见,我们给price设置非法的数值时,会被@price.setter修饰的price方法,即:set方法过滤处理。我们设置一个合法的价格,重新运行:

    调用了: @price.setter修饰的price方法
    调用了:@property修饰的price方法
    小汽车的价格:price =  100000
    

    @property补充

    1.我们还可以定义只读属性,即只定义getter方法,不定义setter方法就是一个只读属性。
    例如:我们给上面的Car类,新增一个轮胎个数的只读属性:

    # 定义一个Car类
    class Car(object):
    
        @property
        def price(self):
            print("调用了:@property修饰的price方法")
            return self.__price
    
        @price.setter
        def price(self, price):
            if price < 0:
                price = 0
            print("调用了: @price.setter修饰的price方法")
            self.__price = price
    
        @property
        def tire_count(self):
            return 4
    

    读取该轮胎个数属性,用下面代码进行验证:

    # 创建一个Car类型的对象c2
    c2 = Car()
    print("轮胎个数:", c2.tire_count)
    

    运行结果:

    轮胎个数: 4
    

    读取成功。我们尝试设置轮胎个数为5,代码如下:

    # 创建一个Car类型的对象c2
    c2 = Car()
    print("轮胎个数:", c2.tire_count)
    
    c2.tire_count = 5
    print("更改后,轮胎个数:", c2.tire_count)
    

    运行结果如下:

    轮胎个数: 4
    Traceback (most recent call last):
      File "F:/python_projects/oop/23SmartPhone.py", line 78, in <module>
        c2.tire_count = 5
    AttributeError: can't set attribute
    

    会报错:AttributeError:can't set attribute,

    只读属性示例
    如果你也在用PyChar编辑器,细心的你可以发现:当我们给一个只读属性赋值时,编辑器会提示:属性tire_count不能被赋值。

    2.@property修饰的方法名可以和@property自动生成的装饰器修饰的方法名必须相同。
    上面例子中,我们采用了相同的方法名price。下面我们尝试修改@price.setter修饰的方法名为:price_test

    # 定义一个Car类
    class Car(object):
    
        @property
        def price(self):
            print("调用了:@property修饰的price方法")
            return self.__price
    
        @price.setter
        def price_test(self, price):
            if price < 0:
                price = 0
            print("调用了: @price.setter修饰的price方法")
            self.__price = price
    
    # 创建一个Car类型的对象
    c = Car()
    c.price = 100000
    print("小汽车的价格:price = ", c.price)
    

    运行结果:

    Traceback (most recent call last):
      File "F:/python_projects/oop/23SmartPhone.py", line 71, in <module>
        c.price = 100000
    AttributeError: can't set attribute
    

    这样尝试修饰的方法一个为:price,一个为price_test让方法名不同后,再给price赋值时,就会报错AttributeError: can't set attribute。并且编译器会提示:

    修饰的方法名不相同时的提示语

    小结

    @property广泛应用在Python类的定义中非常常见。这即可以让调用者写出简短的代码,同时又起到了对参数进行必要的检查,这样程序运行时就减少了出错的可能性,这一节知识务必熟练掌握。


    更多了解,可关注公众号:人人懂编程


    微信公众号:人人懂编程

    相关文章

      网友评论

        本文标题:25.Python编程:@property详解

        本文链接:https://www.haomeiwen.com/subject/kwhslftx.html