Что делает символ "at" (@) в Python?

Я смотрю на некоторый код Python, который использовал символ @, но я понятия не имею, что он делает. Я также не знаю, что искать в качестве поисковых документов Python или Google не возвращает релевантные результаты при включении символа @.

Ответ 1

Символ @ в начале строки используется для декораторов классов, функций и методов.

Узнайте больше здесь:

ОПТОСОЗ 318: Декораторы

Python Decorators

Наиболее распространенные декораторы Python, с которыми вы столкнетесь:

@имущество

@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 которые вы определяете после декоратора, просто передается в качестве argument function/method сразу после знака @.

Первое наблюдение

Микрофракционная фляжка вводит декораторы с самого начала в следующем формате:

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

Понимая это, я, наконец, позволил почувствовать мир с Фляксом.

Ответ 3

Этот фрагмент кода:

def decorator(func):
   return func

@decorator
def some_func():
    pass

Это эквивалентно этому коду:

def decorator(func):
    return func

def some_func():
    pass

some_func = decorator(some_func)

В определении декоратора вы можете добавить некоторые измененные вещи, которые обычно не возвращались функцией.

Ответ 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

Что символ "at" (@) делает в 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 - это, например, функция умножения матриц, а 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 по запросу "документация по python для декораторов" дает в качестве одного из лучших результатов раздел "Сложные заявления" в "Справочнике по языкам Python". Прокрутив вниз до раздела, посвященного определениям функций, который мы можем найти, выполнив поиск по слову "decorator", мы увидим, что... там много чего можно прочитать. Но слово "декоратор" - это ссылка на глоссарий, который говорит нам:

декоратор

Функция, возвращающая другую функцию, обычно применяется как преобразование функции с использованием синтаксиса @wrapper. Типичными примерами для декораторов являются classmethod() и staticmethod().

Синтаксис декоратора - это просто синтаксический сахар, семантически эквивалентны следующие два определения функций:

def f(...):
    ...
f = staticmethod(f)

@staticmethod
def f(...):
    ...

Та же концепция существует для классов, но там используется реже. См. Документацию для определений функций и определений классов для получения дополнительной информации о декораторах.

Итак, мы видим, что

@foo
def bar():
    pass

семантически совпадает с:

def bar():
    pass

bar = foo(bar)

Они не совсем одинаковы, потому что Python оценивает выражение foo (которое может быть точечным поиском и вызовом функции) перед bar с синтаксисом decorator (@), но оценивает выражение foo после bar в другом случае.

(Если это различие имеет значение в значении вашего кода, вам следует пересмотреть то, что вы делаете со своей жизнью, потому что это будет патологически.)

С накоплением декораторов

Если мы вернемся к документации по синтаксису определения функции, мы увидим:

@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__() для регулярного, отраженного и __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

Что делает символ "at" (@) в Python?

@symbol - синтаксический сахарный питон, который позволяет использовать 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'

Тада, видишь ли, я исправил 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

Если вы имеете в виду некоторый код в записной книжке Python, который использует библиотеку Numpy, то @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 3.5, "@" используется как выделенный символ infix для MATRIX MULTIPLICATION (PEP 0465 - см. Https://www.python.org/dev/peps/pep-0465/)

Ответ 9

Когда я начал отвечать, я не видел первого ответа, это именно то, что вам нужно, уважительно в java - это другое понятие, и, например, вы можете читать здесь java, учебник аннотации

В java это аннотация, и, как вы можете прочитать, используется совершенно иначе, чем в python, извините за неприятности.

Изменить: оригинальное сообщение, и, как сказано в комментариях, я допустил ошибку при выборе варианта. Это декоратор, как на языке Java, с которым вы его используете, для декларации и использования абстрактных методов. Разница в том, что в Python абстрактный метод может иметь реализацию.

Определение с docs.python.org

Ответ 10

Символ

@также используется для доступа к переменным внутри запроса dataframe 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

Ответ 12

Говорить, что другие имеют по-другому: да, это декоратор.

В Python это похоже:

  • Создание функции (следует по вызову @)
  • Вызов другой функции для работы с созданной функцией. Это возвращает новую функцию. Функция, которую вы вызываете, является аргументом @.
  • Замена функции, определяемой возвращенной новой функцией.

Это может использоваться для всех видов полезных вещей, что стало возможным благодаря тому, что функции являются объектами и просто необходимыми только инструкциями.

Ответ 13

В 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")

Общий синтаксис и возможные реализации

Декоратор обычно является именованным объектом (лямбда-выражения не допускаются), который принимает один аргумент при вызове (это будет декорированная функция) и возвращает другой вызываемый объект. "Callable" используется здесь вместо "function" с преднамеренностью. Хотя декораторы часто обсуждаются в области методов и функций, они не ограничиваются ими. Фактически, все, что можно вызвать (любой объект, который реализует метод _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