python中各种@property、@xxx.setter、@classmethod、@staticmethod 都是些啥啊?
类似这样:
这是你最常见的几个玩意了吧,它们都是啥意思,以及怎么去定义使用呢?
那么,接下来我就尽量通熟易懂的跟你聊聊这些玩意。
在此之前,我们先看下 Python 中的函数,它的定义和调用可以如此简单:
其实,在 Python 里,一个函数可以是一个对象,一个函数也可以被作为一个「参数」进行传递,像这样:
我们这里定义的函数 「func_1」,直接返回的是「传入进来的函数执行了一波」。
这样显然没有什么意义,更多时候,我们是希望传入的函数在执行的前后可以做一些相关的额外的操作,像这样:
但这里的 「func_1」并没有 return,这就会导致一个这样的 Error:
我们本想拿到函数的引用,然后去执行,可是 func_1 并没有返回任何东西,所以我们第七行得到的 my_func 实际上是 None。
想要解决这样的尴尬,我们可以定义一个内部方法,然后返回这个引用,像这样:
简单说一下这里的执行流程,当你执行第十行 「my_func = func1(say)」 的时候,这时候 say 方法会作为参数传递给 func_1 函数,而这个函数直接返回了 「inner_func」,那么这时候 my_func 指向的就是 inner_func:
所以我们这时候执行 「my_func()」,就可以执行到内部方法所定义的东西。
看到这里,你会发现,我们所定义的 「func_1」实际上就是为了改变(优化)传入进来的函数的执行结果,比如我们刚定义的 say 函数。
这样的函数操作,在实际应用场景中常常会用到,举个例子,用户登录校验:
很显然,这里我们希望用户在执行 「login_user」前先检查一下用户名密码对不对。
同样的,我们可以这样来拿到内部方法的引用:
那么通过这个 login ,我们就可以得到用户的校验了,当密码错误时:
当权限不足时:
只有用户名密码正确,才会执行 login_user 方法:
也许这时候你会发现,这种方式的使用,每次都需要像这样才能拿到引用去执行:
这..一点都不 Pythonic 呀!
那么,@ 就派上用场了!!
可以直接这样使用:在 @ 后面添加一个你要进行额外操作的方法名称。
通过这样的定义,就等于 「login_new_user」拿到了 「user_check」的内部引用,可以直接执行:
你可以看到它们两的区别:
通过一个简单的 @ ,就可以让这个函数的拥有额外的功能,或者说改变了这个函数的执行结果。
我们刚刚所说的「在 @ 后面添加一个你要进行额外操作的方法名称」,这个方法在 Python 中就叫 decorator——装饰器。
而这种 @ 语法,我们叫它「语法糖」。
语法糖(英语:Syntactic sugar)是由英国计算机科学家彼得·兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。
——来自维基百科
在装饰器中还有一种常用的方式,就是定义装饰器的同时,可以给它传递参数。
就拿刚刚的例子,假设我们除了用户名密码,还想校验密码的长度,但每个注册装饰器的方法,想要的长度不相同,那么可以这样:
在这个方法中,我们希望密码最小长度为 6 ,装饰器就可以这样写:
这和我们一开始写的装饰器是差不多的,只不过为了接收变量参数,我们再定义了一个外层方法。
另外,这里只是为了演示如何给装饰器传递参数,重点看 length 判断就行。
这样执行 user_login ,密码长度不对就会得到这样的结果:
好了,相信现在的你已经知道了什么是装饰器。
那么现在,回到一开始的问题。
这些玩意,是不是一下子就有亲切感了?
它们就是 Python 已经写好了的装饰器,你的方法定义了什么装饰器,那它们就拥有了什么额外的功能。
来给你简单介绍一下它们的功能。
通常,@property 和 @.setter 会搭配使用,比如上面的 name,通过 @name.setter 装饰,那么这个属性 name 的值就可以被改变,并且可以在方法里做一些简单的校验,比如上面的 @name.setter 下设置 name 的长度要大于 5。
这时候 name 属性就得到了约束:
可以看到,通过 @property 装饰,这个方法行为可以直接被当作属性使用。
所以有些方法可以直接使用 @property 来单纯返回一些数据,比如获取数据库中用户的记录有多少,就可以这样:
这时候只需要通过实例 user.user_count 就可以直接获取了。
而通过 @classmethod 装饰,你就可以把这个方法当作「工厂方法」,可以通过这个方法来创建实例:
通过 @staticmethod 装饰,这个方法就成为了「静态方法」,那么你可以直接通过类去访问它也可以通过实例去访问它:
这几个只是常见的装饰器,在一些项目中我们也常常会使用到装饰器,比如用 Python 写 web 项目,就有很多插件都是可以通过装饰器来简化代码,操作起来方便且可读性杠杠滴。