Python 中的“at”(@)符号起什么作用?

2024-12-03 08:44:00
admin
原创
202
摘要:问题描述:该@符号在 Python 中起什么作用?解决方案 1:行首@的符号用于类和函数装饰器:PEP 318:装饰器Python 装饰器- Python 维基最常见的 Python 装饰器是:+ `@property` + `@classmethod` + `@staticmethod` 一行@中间的可能是...

问题描述:

@符号在 Python 中起什么作用?


解决方案 1:

行首@的符号用于类和函数装饰器

  • PEP 318:装饰器

  • Python 装饰器- Python 维基

  • 最常见的 Python 装饰器是:

+ `@property`
+ `@classmethod`
+ `@staticmethod`

一行@中间可能是矩阵乘法:

  • @作为二元运算符。

解决方案 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`argumentfunctionmethod`@

首次目击

微框架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 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:

此代码片段:

def decorator(func):
   return func

@decorator
def some_func():
    pass

相当于此代码:

def decorator(func):
    return func

def some_func():
    pass

some_func = decorator(some_func)

在装饰器的定义中,你可以添加一些通常不会由函数返回的修改内容。

解决方案 5:

Python 中的“at”(@)符号起什么作用?

简而言之,它用于装饰器语法和矩阵乘法。

在装饰器的上下文中,此语法:

@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 矩阵乘法函数,而ab是矩阵。

您自己怎么能发现这一点呢?

我不知道要搜索什么,因为当包含 @ 符号时,搜索 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

我们可以从这里看到它@在三种情况下使用:

  • 装饰器

  • 因素之间的运算符

  • 增强赋值运算符

装饰器语法:

在谷歌上搜索“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”,我们会得到一个链接,指向Python 3.5 中的新增功能,其中包含“matmul”,标题为“PEP 465 - 用于矩阵乘法的专用中缀运算符”。

它可以通过定义__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]])

解决方案 6:

Python 中的“at”(@)符号起什么作用?

@ 符号是python提供的一个语法糖decorator

用来解释这个问题,它到底在Python中起什么作用?

简单来说,decorator允许你修改给定函数的定义而不触及它的最内层(它的闭包)。

当你从第三方导入精彩的包时,这种情况最多。你可以将其可视化,你可以使用它,但你无法触及它的最内层和它的核心。

这是一个简单的例子,

假设我read_a_book在 Ipython 上定义了一个函数

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'"

然而,如果我不被允许操作原始函数,或者有数千个这样的函数需要处理,该怎么办呢?

用不同的思维方式解决问题并定义一个新的函数

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),它是一种语法糖,没有什么比它更花哨的了。

解决方案 7:

如果你引用的是使用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

解决方案 8:

在 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

最后让我们看看具有属性的装饰器。

特性

属性提供了一种内置的描述符类型,它知道如何将属性链接到一组方法。属性有四个可选参数: 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

解决方案 9:

从 Python 3.5 开始,'@' 被用作矩阵乘法的专用中缀符号(PEP 0465 - 请参阅https://www.python.org/dev/peps/pep-0465/

解决方案 10:

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

解决方案 11:

@可以是数学运算符或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/

解决方案 12:

它表明您正在使用装饰器。这是Bruce Eckel 2008 年的示例。

解决方案 13:

@ 符号也用于访问 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

解决方案 14:

换个角度来说别人有的:是的,它是一个装饰器。

在 Python 中,它就像:

  1. 创建一个函数(按照@调用)

  2. 调用另一个函数来操作您创建的函数。这将返回一个新函数。您调用的函数是 @ 的参数。

  3. 用返回的新函数替换定义的函数。

这可以用于各种有用的事物,因为函数是对象并且仅仅是必要的指令。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用