我正在查看一些使用@
符号的Python代码,但我不知道它的作用。我也不知道在搜索Python文档时要搜索什么,或者当包含@
符号时Google不会返回相关结果。
答案 0 :(得分:285)
我承认我花了不少时间才能完全掌握这个概念,所以我会分享我学到的东西来拯救别人的麻烦。
名称装饰器 - 我们在函数定义之前使用@
语法定义的东西 - 可能是这里的主要罪魁祸首。
class Pizza(object):
def __init__(self):
self.toppings = []
def __call__(self, topping):
# When using '@instance_of_pizza' before a function definition
# 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
最终实现这一点让我对Flask感到安宁。
答案 1 :(得分:217)
一行开头的@
符号用于类,函数和方法装饰器。
在这里阅读更多内容:
您将遇到的最常见的Python装饰器是:
如果你在一条线的中间看到一个@
,那就是矩阵乘法。向下滚动以查看解决@
使用的其他答案。
答案 2 :(得分:155)
此代码段:
def decorator(func):
return func
@decorator
def some_func():
pass
等同于此代码:
def decorator(func):
return func
def some_func():
pass
some_func = decorator(some_func)
在装饰器的定义中,您可以添加一些通常不会被函数返回的修改过的东西。
答案 3 :(得分:97)
在Python 3.5中,您可以将@
重载为运算符。它被命名为__matmul__
,因为它被设计用于矩阵乘法,但它可以是你想要的任何东西。有关详细信息,请参阅PEP465。
这是矩阵乘法的简单实现。
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]]
答案 4 :(得分:63)
简而言之,它用于装饰器语法和矩阵乘法。
在装饰器的上下文中,这个语法:
@decorator
def decorated_function():
"""this function is decorated"""
相当于:
def decorated_function():
"""this function is decorated"""
decorated_function = decorator(decorated_function)
在矩阵乘法的上下文中,a @ b
调用a.__matmul__(b)
- 使用以下语法:
a @ b
相当于
dot(a, b)
和
a @= b
相当于
a = dot(a, b)
例如,dot
是numpy矩阵乘法函数,a
和b
是矩阵。
我也不知道搜索Python文档会搜索什么,或者当包含@符号时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
我们在这里可以看到@
在三种情况下使用:
google搜索“decorator python docs”作为最佳结果之一,即“Python语言参考”的“复合语句”部分。向下滚动到我们可以通过搜索单词“decorator”找到的section on function definitions,我们看到......有很多东西需要阅读。但是,"decorator" is a link to the glossary这个词告诉我们:
装饰
返回另一个函数的函数,通常使用
@wrapper
语法作为函数转换应用。共同 装饰器的示例包括classmethod()
和staticmethod()
。装饰器语法只是语法糖,以下两种 函数定义在语义上是等价的:
def f(...): ... f = staticmethod(f) @staticmethod def f(...): ...
类存在相同的概念,但在那里不太常用。 有关函数定义和类定义,请参阅文档 有关装饰器的更多信息。
所以,我们看到了
@foo
def bar():
pass
在语义上与:
相同def bar():
pass
bar = foo(bar)
它们并不完全相同,因为Python在使用装饰器(@
)语法的bar之前评估foo表达式(可能是虚线查找和函数调用),但是在之后评估foo表达式 在另一种情况下吧。
(如果这种差异对你的代码的含义产生影响,你应该重新考虑你在生活中做了什么,因为那将是病态的。)
如果我们回到函数定义语法文档,我们会看到:
@f1(arg) @f2 def func(): pass
大致相当于
def func(): pass func = f1(arg)(f2(func))
这是一个演示,我们可以先调用一个装饰器的函数,以及堆栈装饰器。 Python中的函数是第一类对象 - 这意味着您可以将函数作为参数传递给另一个函数,并返回函数。装饰者会做这两件事。
如果我们堆叠装饰器,那么定义的函数首先会被传递到它上面的装饰器,然后是下一个,依此类推。
关于在装饰器的上下文中总结@
的用法。
@
在语言参考的词汇分析部分,我们有section on operators,其中包含@
,这也使其成为运算符:
以下令牌是运营商:
+ - * ** / // % @ << >> & | ^ ~ < > <= >= == !=
在下一页的数据模型中,我们有section, emulating numeric 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__
对应@
。如果我们在文档中搜索“matmul”,我们会在标题“PEP 465 - 矩阵乘法的专用中缀运算符”下找到What's new in Python 3.5和“matmul”的链接。
可以通过定义
__matmul__()
,__rmatmul__()
和来实现__imatmul__()
用于常规,反射和就地矩阵乘法。
(现在我们了解到@=
是就地版本)。它进一步解释说:
矩阵乘法在许多领域都是一个非常常见的操作 数学,科学,工程和@允许的添加 写清洁代码:
S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)
而不是:
S = dot((dot(H, beta) - r).T, dot(inv(dot(dot(H, V), H.T)), dot(H, beta) - r))
虽然可以重载此运算符来执行几乎任何操作,例如,在numpy
中,我们将使用此语法来计算数组和矩阵的内部和外部乘积:
>>> 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]])
@=
在研究先前的用法时,我们了解到还有就地矩阵乘法。如果我们尝试使用它,我们可能会发现它尚未实现numpy:
>>> m = matrix([1,2,3])
>>> m @= m.T
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 @= m.T
>>> m
matrix([[14]])
答案 5 :(得分:26)
“at”(@)符号在Python中有什么作用?
@符号是一个语法糖python,提供利用decorator
,
解释这个问题,它究竟是关于装饰器在Python中做了什么?
简单decorator
允许您修改给定函数的定义而不触及其最内层(它的闭包)。
当您从第三方导入精彩包时,情况最多。你可以想象它,你可以使用它,但你无法触及它的内心和它的心脏。
这是一个简单的例子,
假设我在Ipython上定义了一个read_a_book
函数
In [9]: def read_a_book():
...: return "I am reading the book: "
...:
In [10]: read_a_book()
Out[10]: 'I am reading the book: '
你知道,我忘了为它添加一个名字 如何解决这样的问题?当然,我可以将函数重新定义为:
def read_a_book():
return "I am reading the book: 'Python Cookbook'"
然而,如果我不允许操纵原始功能,或者有数千个这样的功能需要处理,那该怎么办呢。
通过思考不同来解决问题,并定义一个new_function
def add_a_book(func):
def wrapper():
return func() + "Python Cookbook"
return wrapper
然后使用它。
In [14]: read_a_book = add_a_book(read_a_book)
In [15]: read_a_book()
Out[15]: 'I am reading the book: Python Cookbook'
田田,你知道,我修改了read_a_book
而没有触及内部封闭。没有什么能阻止我配备decorator
。
关于@
@add_a_book
def read_a_book():
return "I am reading the book: "
In [17]: read_a_book()
Out[17]: 'I am reading the book: Python Cookbook'
@add_a_book
是一种花哨而方便的方式来说read_a_book = add_a_book(read_a_book)
,它是一种语法糖,没有什么比这更好的了。
答案 6 :(得分:14)
如果您在使用 Numpy 库的python笔记本中引用某些代码,则@ operator
表示矩阵乘法。例如:
import numpy as np
def forward(xi, W1, b1, W2, b2):
z1 = W1 @ xi + b1
a1 = sigma(z1)
z2 = W2 @ a1 + b2
return z2, a1
答案 7 :(得分:8)
从Python 3.5开始,&#39; @&#39;用作MATRIX MULTIPLICATION的专用中缀符号(PEP 0465 - 见https://www.python.org/dev/peps/pep-0465/)
答案 8 :(得分:3)
Python 装饰器就像一个函数或类的包装器。还是太概念化了。
def function_decorator(func):
def wrapped_func():
# Do something before the function is executed
func()
# Do something after the function has been executed
return wrapped_func
上面的代码是装饰一个函数的装饰器的定义。 function_decorator 是装饰器的名称。
wrapped_func 是内部函数的名称,实际上只在这个装饰器定义中使用。 func 是被修饰的函数。 在内部函数wrapped_func中,我们可以在调用func之前和之后做任何事情。装饰器定义好后,我们简单的使用如下。
@function_decorator
def func():
pass
然后,每当我们调用函数 func 时,我们在装饰器中定义的行为也将被执行。
示例:
from functools import wraps
def mydecorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
print "Before decorated function"
r = f(*args, **kwargs)
print "After decorated function"
return r
return wrapped
@mydecorator
def myfunc(myarg):
print "my function", myarg
return "return value"
r = myfunc('asdf')
print r
输出:
Before decorated function
my function asdf
After decorated function
return value
答案 9 :(得分:2)
@ symbol还用于访问plydata / pandas数据帧查询pandas.DataFrame.query
中的变量。
例如:
df = pandas.DataFrame({'foo': [1,2,15,17]})
y = 10
df >> query('foo > @y') # plydata
df.query('foo > @y') # pandas
答案 10 :(得分:1)
表示您正在使用装饰器。以下是2008年的Bruce Eckel's example。
答案 11 :(得分:1)
用不同的方式说出其他人有什么:是的,它是装饰者。
在Python中,它就像:
这可以用于各种有用的东西,因为函数是对象,只是必要的指令。
答案 12 :(得分:1)
在Python中添加了装饰器,以使函数和方法包装(接收函数并返回增强函数的函数)更易于阅读和理解。最初的用例是能够在定义的顶部将方法定义为类方法或静态方法。没有装饰器语法,将需要一个相当稀疏且重复的定义:
class WithoutDecorators:
def some_static_method():
print("this is static method")
some_static_method = staticmethod(some_static_method)
def some_class_method(cls):
print("this is class method")
some_class_method = classmethod(some_class_method)
如果将装饰器语法用于相同目的,则代码将更短且更易于理解:
class WithDecorators:
@staticmethod
def some_static_method():
print("this is static method")
@classmethod
def some_class_method(cls):
print("this is class method")
常规语法和可能的实现方式
装饰器通常是一个命名对象(不允许使用 lambda表达式 ),该对象在被调用时将接受单个参数(它将成为装饰后的函数)并返回另一个可调用的宾语。此处使用“可调用”代替带有预想的“功能”。尽管装饰器通常在方法和功能的范围内进行讨论,但它们不限于此。实际上,任何可调用的对象(实现_call__方法的任何对象都被视为可调用的对象)可以用作装饰器,并且它们返回的对象通常不是简单的函数,而是更多复杂类的实例,这些实例实现了自己的__call_方法。 / p>
装饰器语法只是 语法糖 。考虑以下装饰器用法:
@some_decorator
def decorated_function():
pass
这总是可以由显式的装饰器调用和函数重新分配来代替:
def decorated_function():
pass
decorated_function = some_decorator(decorated_function)
但是,如果单个功能上使用多个装饰器,则后者的可读性较低,并且也很难理解。 装饰器可以以多种不同方式使用,如下所示:
作为功能
有许多方法可以编写自定义装饰器,但是最简单的方法是编写一个函数,该函数返回包装原始函数调用的子函数。
通用模式如下:
def mydecorator(function):
def wrapped(*args, **kwargs):
# do some stuff before the original
# function gets called
result = function(*args, **kwargs)
# do some stuff after function call and
# return the result
return result
# return wrapper as a decorated function
return wrapped
作为班级
虽然装饰器几乎总是可以使用函数来实现,但在某些情况下,使用用户定义的类是更好的选择。当装饰器需要复杂的参数化或取决于特定状态时,通常会发生这种情况。
非参数化装饰器作为类的通用模式如下:
class DecoratorAsClass:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
# do some stuff before the original
# function gets called
result = self.function(*args, **kwargs)
# do some stuff after function call and
# return the result
return result
参数化装饰器
在实际代码中,经常需要使用可以参数化的装饰器。当将该函数用作装饰器时,解决方案很简单-必须使用第二层包装。这是装饰器的一个简单示例,该装饰器每次被调用都会重复执行指定次数的装饰函数:
def repeat(number=3):
"""Cause decorated function to be repeated a number of times.
Last value of original function call is returned as a result
:param number: number of repetitions, 3 if not specified
"""
def actual_decorator(function):
def wrapper(*args, **kwargs):
result = None
for _ in range(number):
result = function(*args, **kwargs)
return result
return wrapper
return actual_decorator
以这种方式定义的装饰器可以接受参数:
>>> @repeat(2)
... def foo():
... print("foo")
...
>>> foo()
foo
foo
请注意,即使参数化修饰符的参数具有默认值,也必须在其名称后加上括号。正确使用带有默认参数的前面装饰器的正确方法如下:
>>> @repeat()
... def bar():
... print("bar")
...
>>> bar()
bar
bar
bar
最后,让我们看到带有属性的装饰器。
属性
属性提供内置的descriptor类型,该类型知道如何将属性链接到一组方法。一个属性带有四个可选参数:fget,fset,fdel和doc。可以提供最后一个来定义链接到属性的文档字符串,就好像它是方法一样。这是一个Rectangle类的示例,可以通过直接访问存储两个角点的属性或使用width和height属性来控制它:
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
def _width_get(self):
return self.x2 - self.x1
def _width_set(self, value):
self.x2 = self.x1 + value
def _height_get(self):
return self.y2 - self.y1
def _height_set(self, value):
self.y2 = self.y1 + value
width = property(
_width_get, _width_set,
doc="rectangle width measured from left"
)
height = property(
_height_get, _height_set,
doc="rectangle height measured from top"
)
def __repr__(self):
return "{}({}, {}, {}, {})".format(
self.__class__.__name__,
self.x1, self.y1, self.x2, self.y2
)
创建属性的最佳语法是使用属性作为装饰器。这将减少类内部的方法签名数量 并使代码更可读性和可维护性。使用装饰器,以上类变为:
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
@property
def width(self):
"""rectangle height measured from top"""
return self.x2 - self.x1
@width.setter
def width(self, value):
self.x2 = self.x1 + value
@property
def height(self):
"""rectangle height measured from top"""
return self.y2 - self.y1
@height.setter
def height(self, value):
self.y2 = self.y1 + value
答案 13 :(得分:1)
@ 可以是数学运算符或 DECORATOR 但你的意思是装饰器
看下面的代码
def func(f):
return f
func(lambda :"HelloWorld")()
如果使用装饰器可以写
def func(f):
return f
@func
def name():
return "Hello World"
name()
装饰器可以有参数
GeeksforGeeks 写这篇文章https://www.geeksforgeeks.org/decorators-in-python/