Python中的“ @”(@)符号有什么作用? |
您所在的位置:网站首页 › default在python语言中 › Python中的“ @”(@)符号有什么作用? |
我正在看一些使用@符号的Python代码,但我不知道它的作用。 我也不知道要搜索什么,因为搜索Python文档时会出现,或者当包含@符号时Google不会返回相关结果。 #1楼此代码段: def decorator(func): return func @decorator def some_func(): pass等效于以下代码: def decorator(func): return func def some_func(): pass some_func = decorator(some_func)在装饰器的定义中,您可以添加一些通常不会由函数返回的修改内容。 #2楼 前言我承认,花了我很多时间才能完全理解这个概念,所以我将分享我所学到的为他人省下麻烦的知识。 名称装饰器 (我们在函数定义之前使用@语法定义的东西)可能是此处的罪魁祸首。 例 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和平相处。 #3楼用不同的方式来说其他人:是的,它是一个装饰器。 在Python中,就像: 创建一个函数(在@调用之后) 调用另一个函数以对您创建的函数进行操作。 这将返回一个新函数。 您调用的函数是@的参数。 用返回的新函数替换定义的函数。这可以用于各种有用的东西,因为功能是对象,而只是指令而已,因此成为可能。 #4楼在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]] #5楼从Python 3.5开始,“ @”用作MATRIX MULTIPLICATION(PEP 0465-参见https://www.python.org/dev/peps/pep-0465/ )的专用中缀符号。 #6楼 Python中的“ @”(@)符号有什么作用?简而言之,它用于装饰器语法和矩阵乘法。 在装饰器的上下文中,此语法为: @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”一词找到该部分 ,我们发现……有很多东西可供阅读。 但是“ decorator”这个词是词汇表的链接 ,它告诉我们: 装饰工返回另一个函数的函数,通常使用@wrapper语法作为函数转换应用。 装饰器的常见示例是classmethod()和staticmethod() 。 装饰器语法只是语法糖,以下两个函数定义在语义上是等效的: def f(...): ... f = staticmethod(f) @staticmethod def f(...): ...类存在相同的概念,但在该类中较少使用。 有关装饰器的更多信息,请参见函数定义和类定义的文档。 所以,我们看到 @foo def bar(): pass在语义上与: def bar(): pass bar = foo(bar)它们并不完全相同,因为Python使用装饰器( @ )语法在bar之前评估foo表达式(可能是点分查找和函数调用),但在另一种情况下,则在 bar 之后评估foo表达式。 (如果这种差异使代码的含义有所不同,则应重新考虑自己的生活,因为那会是病态的。) 堆叠式装饰器如果回到函数定义语法文档,则会看到: @f1(arg) @f2 def func(): pass大致相当于 def func(): pass func = f1(arg)(f2(func))这是一个演示,我们可以调用首先是装饰器的函数以及堆栈装饰器。 在Python中,函数是一流的对象-这意味着您可以将一个函数作为参数传递给另一个函数,然后返回函数。 装饰者可以做这两种事情。 如果我们堆叠装饰器,则已定义的函数会首先传递到紧接其上的装饰器,然后传递给下一个,依此类推。 关于装饰器上下文中@的用法的总结。 运营商, @在语言参考的词法分析部分,我们有一个关于运算符的部分 ,其中包括@ ,这使其同时也是一个运算符: 以下标记是运算符: + - * ** / // % @ > & | ^ ~ < > = == !=在下一页的数据模型中,我们有模拟数字类型一节, 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-矩阵乘法的专用中缀运算符”下获得指向“ matmul”的Python 3.5新增功能的链接。 可以通过定义__matmul__() , __rmatmul__()和__imatmul__()来实现常规,反射和就地矩阵乘法。 (所以现在我们知道@=是就地版本)。 它进一步说明: 在数学,科学,工程学的许多领域中,矩阵乘法是一种常见的操作,并且@的加法允许编写更简洁的代码: 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 ,我们将使用以下语法来计算数组和矩阵的内乘和外乘: >>> 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 "", line 1, in 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]]) #7楼@符号还用于访问plydata / pandas数据pandas.DataFrame.query查询pandas.DataFrame.query 。 例: df = pandas.DataFrame({'foo': [1,2,15,17]}) y = 10 df >> query('foo > @y') # plydata df.query('foo > @y') # pandas #8楼Python中的“ @”(@)符号有什么作用? @符号是python提供的使用decorator的语法糖, 解释这个问题,这恰恰是关于装饰器在Python中的作用? 把它简单的decorator让你修改一个给定函数的定义,但不接触它的最内层(它的闭包)。 从第三方导入精美的包时,最常见的情况是。 您可以可视化它,可以使用它,但不能触摸它的最内层和内心。 这是一个简单的例子, 假设我在read_a_book上定义了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'Tada,您知道,我修改了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) ,它是一种语法糖,对此没有什么幻想。 #9楼如果您在使用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 #10楼在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_方法。 装饰器语法只是一个语法糖 。 考虑以下装饰器用法: @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最后,让我们看看带有Properties的装饰器。 性质 这些属性提供了内置的描述符类型,该描述符类型知道如何将属性链接到一组方法。 一个属性带有四个可选参数: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 #11楼它表明您正在使用装饰器。 这是Bruce Eckel在2008年的例子 。 #12楼行开头的@符号用于类,函数和方法修饰符 。 在这里阅读更多: PEP 318:装饰器 Python装饰器 您会遇到的最常见的Python装饰器是: @属性 @classmethod @staticmethod 如果您在一行的中间看到一个@ ,那就是矩阵乘法。 向下滚动以查看其他使用@答案。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |