Python语法糖之@property

引子

        今天阅读OpenAI Gym的robotics/robot_env.py时,遇到了@property这个语法糖,因此记录一下,以备下次使用。

简介

        我们知道,在Python中,用语法糖(或者叫装饰器)可以给函数动态加上功能,究竟什么是语法糖?参考百度百科进行介绍:
        语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的术语,指向计算机语言中添加某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常而言,使用语法糖能够增加程序的可读性,从而减少代码出错的机会。
        举个例子,在C语言里面我们经常用a[i][j]表示((a+i)+j),a[i][j]这种写法简洁明了,更容易被人理解。

Pythonic

        在Python中,常常有一些让人感觉很舒服的用法。

例1

        举个例子,我们想要将list1=[[1, 2], [3, 4, 5], [6, 7]]变为list2=[1, 2, 3, 4, 5, 6, 7],常规做法:

list1 = [[1, 2], [3, 4, 5], [6, 7]]
list2 = []
for i in list1:
    list2 += i

        更加Pythonic的做法:

list1 = [[1, 2], [3, 4, 5], [6, 7]]
list2 = [i for sublist in list1 for i in sublist]

例2

        一个更加著名的例子是lambda表达式。

        它的用法是:

lambda 参数列表 : 返回值

        比如:

f = lambda x,y : x if x>y else y

        举这些例子主要是为了让大家了解到Python的独特魅力。下面我们将回到正题。

@property

        在定义类的时候,我们会一直与成员变量以及成员函数打交道。
        直接定义一个成员变量(属性)并直接暴露给用户,虽然这样用起来很简单,可以直接对属性进行读写,但是却不能检查我们的参数。比如说,我们定义某一天的温度:

t = Temperature()
t.celcius = 100

        100摄氏度,显然这是不合情理的,所以我们通常会这么写:

class Temperature()
    def __init__(self):
        self._celcius = None
    def get_celcius(self):
        return self._celcius
    def set_celcius(self, value):
        if not isinstance(value, int):
            raise ValueError("Celcius must be an integer!")
        if value < -40 or value > 50:
            raise ValueError("Celcius must between -40 ~ 50!")
        self._celcius = value

        这样就可以有效地防止用户随心所欲地更改温度了,毕竟谁也不想很冷或很热吧。不过这样做又引发了另一个问题,就是调用起来比较麻烦,没有直接用属性这么简单。
        有没有一种方式能够让我们既能执行参数检查,又可以用类似于属性这种简单的方式访问类的变量呢?Pyhton内置的@property就是负责将一个方法变成属性调用的。比如说:

class Temperature()
    def __init__(self):
        self._celcius = None
    @property
    def celcius(self):
        return self._celcius
    @celcius.setter
    def celcius(self, value):
        if not isinstance(value, int):
            raise ValueError("Celcius must be an integer!")
        if value < -40 or value > 50:
            raise ValueError("Celcius must between -40 ~ 50!")
        self._celcius = value

        对此我们可以执行如下调用:

t = Temperature()
t.celcius = 25    # 变为t.set_celcius(25)
t.celcius    # 比哪位t.get_celcius()

        当然,我们可以通过不定义setter方法,删去上面的@celcius.setter即可。

总结

        @property被广泛地用于类定义中,通过使用这个语法糖,我们可以让调用者用得更加愉快,同时保证对参数进行必要的检查,这样就减少了程序运行时出错的可能性。





猜你喜欢

转载自blog.csdn.net/u013745804/article/details/80089901