“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乘法函数, ab是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中,它是这样的:

  1. 创build一个函数(在@调用下面)
  2. 调用另一个函数来操作你创build的函数。 这将返回一个新的函数。 你调用的函数是@的参数。
  3. replace返回的新函数定义的函数。

这可以用于各种有用的东西,因为function是对象,只是必要的指令。