25.Python编程:@property详解

在前面学习访问权限一文中,我们设计了一个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 
    c2.tire_count = 5
AttributeError: can't set attribute

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

25.Python编程:@property详解_第1张图片
只读属性示例

如果你也在用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 
    c.price = 100000
AttributeError: can't set attribute

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

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

小结

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


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


微信公众号:人人懂编程

你可能感兴趣的:(25.Python编程:@property详解)