“at”(@)符号在Python中做什么?
我正在看一些使用@
符号的Python代码,但我不知道它的作用。 我也不知道如何searchPython文档,或者当包含@
符号时Google不返回相关结果。
@
符号用于类,函数和方法装饰器 。
在这里阅读更多:
PEP 318:装饰者
Python装饰器
你会遇到的最常见的Python装饰器是:
@属性
@classmethod
@staticmethod
前言
我承认花了不less时间才完全掌握了这个概念,所以我会分享一下我所学到的拯救别人的麻烦。
名字装饰器 – 我们在函数定义之前使用@
语法定义的东西 – 可能是这里的主要罪魁祸首。
例
class Pizza(object): def __init__(self): self.toppings = [] def __call__(self, topping): # when using '@instance_of_pizza' before a function def # the function gets passed onto 'topping' self.toppings.append(topping()) def __repr__(self): return str(self.toppings) pizza = Pizza() @pizza def cheese(): return 'cheese' @pizza def sauce(): return 'sauce' print pizza # ['cheese', 'sauce']
这显示的是你在装饰器之后定义的function
/ method
/ class
基本上是在@
符号之后立即作为argument
传递给function
/ method
。
初次见面
微框架Flask从一开始就以如下格式引入装饰器 :
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!"
这反过来又转化为:
rule = "/" view_func = hello # they go as arguments here in 'flask/app.py' def add_url_rule(self, rule, endpoint=None, view_func=None, **options): pass
意识到这一点,终于让我感受到了烧瓶的安宁。
此代码片段:
def decorator(func): return func @decorator def some_func(): pass
相当于这个代码:
def decorator(func): return func def some_func(): pass some_func = decorator(some_func)
在装饰器的定义中,你可以添加一些不会被函数正常返回的修改过的东西。
在python3.5中,你可以重载@
作为操作符。 它被命名为__matmul__
因为它被devise来执行matrix乘法,但它可以是任何你想要的。 详情请参阅PEP465 。
这是matrix乘法的一个简单实现。
class Mat(list) : def __matmul__(self, B) : A = self return Mat([[sum(A[i][k]*B[k][j] for k in range(len(B))) for j in range(len(B[0])) ] for i in range(len(A))]) A = Mat([[1,3],[7,5]]) B = Mat([[6,8],[4,2]]) print(A @ B)
这个代码产生
[[18, 14], [62, 66]]
“at”(@)符号在Python中做什么?
简而言之,它用于装饰器语法和matrix乘法。
在装饰器的上下文中,这个语法:
@decorator def decorated_function(): """this function is decorated"""
相当于这个:
def decorated_function(): """this function is decorated""" decorated_function = decorator(decorated_function)
在matrix乘法的情况下, a @ b
调用a.__matmul__(b)
– 做这个语法:
a @ b
相当于
dot(a, b)
和
a @= b
相当于
a = dot(a, b)
例如, dot
是numpymatrix乘法函数, a
和b
是matrix。
你怎么能自己发现这个?
我也不知道如何searchPython文档,或者当包含@符号时Google不返回相关结果。
如果您想对Python语法的特定部分有一个完整的视图,请直接查看语法文件。 对于Python 3分支:
~$ grep -C 1 "@" cpython/Grammar/Grammar decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorators: decorator+ -- testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=') -- arith_expr: term (('+'|'-') term)* term: factor (('*'|'@'|'/'|'%'|'//') factor)* factor: ('+'|'-'|'~') factor | power
我们可以在这里看到@
在三种情况下使用:
- 装饰
- 因素之间的操作员
- 增强的赋值运算符
装饰者语法:
一个谷歌search“装饰python文档”作为最重要的结果之一,“Python语言参考”的“复合语句”部分。 向下滚动到函数定义的部分 ,我们可以通过search单词“装饰器”find这个部分 ,我们可以看到有很多东西需要阅读。 但是, “装饰者”这个词是链接到词汇表 ,这告诉我们:
装饰
返回另一个函数的函数,通常作为函数转换使用
@wrapper
语法应用。 装饰器的常见例子是classmethod()
和staticmethod()
。装饰器语法仅仅是语法糖,下面两个函数定义在语义上是等价的:
def f(...): ... f = staticmethod(f) @staticmethod def f(...): ...
类存在相同的概念,但在那里不太常用。 有关装饰器的更多信息,请参阅函数定义和类定义的文档。
所以,我们看到了
@foo def bar(): pass
在语义上是相同的:
def bar(): pass bar = foo(bar)
它们并不完全一样,因为Python在装饰器( @
)语法之前用bar评估fooexpression式(可能是点状查找和函数调用),而是在其他情况下评估fooexpression式。
(如果这种差异在你的代码的含义上有所不同,你应该重新考虑你在做什么,因为那是病态的。)
堆积的装饰
如果我们回到函数定义语法文档,我们看到:
@f1(arg) @f2 def func(): pass
大致相当于
def func(): pass func = f1(arg)(f2(func))
这是一个演示,我们可以先调用一个装饰器函数,也可以调用堆栈装饰器。 Python中的函数是第一类对象 – 这意味着您可以将函数作为parameter passing给另一个函数,并返回函数。 装饰者都做这些事情。
如果我们堆栈装饰器,那么定义的函数首先被传递给它上面的装饰器,然后是下一个,依此类推。
这在装饰器的上下文中总结了@
的用法。
运营商, @
在语言参考的词法分析部分,我们有一个关于运算符的部分 ,其中包括@
,这使得它也是一个运算符:
以下令牌是运营商:
+ - * ** / // % @ << >> & | ^ ~ < > <= >= == !=
在下一页,数据模型,我们有这个部分,模拟数字types ,
object.__add__(self, other) object.__sub__(self, other) object.__mul__(self, other) object.__matmul__(self, other) object.__truediv__(self, other) object.__floordiv__(self, other)
[…]调用这些方法来实现二进制算术运算(
+
,-
,*
,@
,/
,//
,
我们看到__matmul__
对应于@
。 如果我们search“matmul”的文档,我们可以在标题为“PEP 465 – matrix乘法的专用中缀运算符”的标题下,获得Python 3.5中的新增function与“matmul”的链接。
它可以通过定义
__matmul__()
,__rmatmul__()
和__imatmul__()
来实现规则,reflection和原地matrix乘法。
(所以现在我们知道@=
是就地版本)。 它进一步解释说:
matrix乘法在math,科学,工程等许多领域中是一个非常常见的操作,并且允许编写更简洁的代码:
S = (H @ beta - r).T @ inv(H @ V @ HT) @ (H @ beta - r)
代替:
S = dot((dot(H, beta) - r).T, dot(inv(dot(dot(H, V), HT)), dot(H, beta) - r))
虽然这个运算符可以被重载来完成几乎任何事情,例如numpy
,我们将使用这个语法来计算数组和matrix的内积和外积:
>>> from numpy import array, matrix >>> array([[1,2,3]]).T @ array([[1,2,3]]) array([[1, 2, 3], [2, 4, 6], [3, 6, 9]]) >>> array([[1,2,3]]) @ array([[1,2,3]]).T array([[14]]) >>> matrix([1,2,3]).T @ matrix([1,2,3]) matrix([[1, 2, 3], [2, 4, 6], [3, 6, 9]]) >>> matrix([1,2,3]) @ matrix([1,2,3]).T matrix([[14]])
matrix乘法: @=
在研究先前的用法的同时,我们知道还有就地matrix乘法。 如果我们尝试使用它,我们可能会发现它尚未实现numpy:
>>> m = matrix([1,2,3]) >>> m @= mT Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: In-place matrix multiplication is not (yet) supported. Use 'a = a @ b' instead of 'a @= b'.
实施时,我希望结果如下所示:
>>> m = matrix([1,2,3]) >>> m @= mT >>> m matrix([[14]])
当我开始回答时,我没有看到第一个答案,就是比你需要的,尊重在Java是一个不同的概念,你可以阅读例如在这里的Java,注释教程
在Java这是一个注释,你可以阅读是使用是完全不同的比在Python惋惜的麻烦。
编辑:原来的职位,并在评论中说我犯了我select的选项的错误。 它是一种装饰器,就像您在Java语言中用于声明和使用抽象方法一样。 与Python不同的是,抽象方法可以有一个实现。
从docs.python.org定义
从Python 3.5开始,“@”被用作MATRIX MULTIPLICATION的专用中缀符号(PEP 0465 – 见https://www.python.org/dev/peps/pep-0465/ )
这表示您正在使用装饰器。 这是布鲁斯·埃克尔 ( Bruce Eckel) 2008年的例子 。
说别人有什么不同的方式:是的,它是一个装饰者。
在Python中,它是这样的:
- 创build一个函数(在@调用下面)
- 调用另一个函数来操作你创build的函数。 这将返回一个新的函数。 你调用的函数是@的参数。
- replace返回的新函数定义的函数。
这可以用于各种有用的东西,因为function是对象,只是必要的指令。