Co robi symbol " at " ( @ ) w Pythonie?

Patrzę na jakiś kod Pythona, który używał symbolu @, ale nie mam pojęcia, co on robi. Nie wiem również, co szukać, ponieważ wyszukiwanie Python docs lub Google nie zwraca odpowiednich wyników, gdy symbol @ jest dołączony.

Author: Vadim Kotov, 2011-06-18

10 answers

Symbol @ jest używany dla klas, funkcji i metod dekoratorów .

Czytaj więcej tutaj:

PEP 318: dekoratorzy

Python Decorators

Najczęściej spotykanymi dekoratorami Pythona są:

@property

@classmethod

@staticmethod

 180
Author: FogleBird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-17 23:23:44

Preambuła

Przyznaję, że zajęło mi więcej niż kilka chwil, aby w pełni zrozumieć tę koncepcję, więc podzielę się tym, czego się nauczyłem, aby zaoszczędzić innym kłopotów.

Nazwa dekorator - rzecz, którą definiujemy za pomocą składni @ przed definicją funkcji-była tu prawdopodobnie głównym winowajcą.

Przykład

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

To pokazuje, że function/method/class definiujesz po dekorator jest w zasadzie przekazywany jako argument do function/method bezpośrednio po znaku @.

Pierwsza obserwacja

Mikroframework Kolba wprowadza dekoratory od samego początku w następującym formacie:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

To z kolei tłumaczy się na:

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

Uświadomienie sobie tego w końcu pozwoliło mi poczuć spokój z Flask.

 247
Author: Morgan Wilde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-20 13:42:23

Ten fragment kodu:

def decorator(func):
   return func

@decorator
def some_func():
    pass

Jest odpowiednikiem tego kodu:

def decorator(func):
    return func

def some_func():
    pass

some_func = decorator(some_func)

W definicji dekoratora można dodać kilka zmodyfikowanych rzeczy, które normalnie nie byłyby zwracane przez funkcję.

 134
Author: Matheus Araujo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-20 13:40:12

W Pythonie 3.5 możesz przeciążać @ jako operator. Jest on nazwany __matmul__, ponieważ jest przeznaczony do mnożenia macierzy, ale może to być wszystko, co chcesz. Zobacz PEP465 Po szczegóły.

Jest to prosta implementacja mnożenia macierzy.

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)

Ten kod daje:

[[18, 14], [62, 66]]
 77
Author: jinhwanlazy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-20 13:44:17

Co robi symbol "at" ( @ ) w Pythonie?

W skrócie, jest używany w składni dekoratora i do mnożenia macierzy.

W kontekście dekoratorów składnia ta:

@decorator
def decorated_function():
    """this function is decorated"""

Jest równoważne temu:

def decorated_function():
    """this function is decorated"""

decorated_function = decorator(decorated_function)

W kontekście mnożenia macierzy, a @ b wywołuje a.__matmul__(b) - tworząc tę składnię:

a @ b

Odpowiednik

dot(a, b)

I

a @= b

Odpowiednik

a = dot(a, b)

Gdzie dot jest, na przykład, numpy funkcja mnożenia macierzy oraz a i b są macierzami.

Jak mogłeś to odkryć na własną rękę?

Nie wiem również, co szukać, ponieważ wyszukiwanie Python docs lub Google nie zwraca odpowiednich wyników, gdy symbol @ jest dołączony.

Jeśli chcesz mieć dość kompletny widok tego, co robi dany fragment składni Pythona, spójrz bezpośrednio na plik gramatyki. Dla gałęzi 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

Widzimy tutaj, że @ jest używany w trzech kontekstach:

  • dekoratorzy
  • operator między czynnikami
  • Operator rozszerzonego przydziału

Składnia Dekoratora:

Wyszukiwarka google dla "decorator python docs" daje jako jeden z najlepszych wyników sekcję "Compound Statements" w "Python Language Reference"."Przewijając w dół do sekcji dotyczącej definicji funkcji , którą możemy znaleźć szukając słowa "dekorator", widzimy to... jest dużo do przeczytania. Jednak słowo, "dekorator" jest odnośnikiem do słownika , który mówi nam:

Dekorator

Funkcja zwracająca inną funkcję, zwykle stosowana jako transformacja funkcji przy użyciu składni @wrapper. Często przykłady dekoratorów to classmethod() i staticmethod().

Składnia dekoratora jest jedynie cukrem składniowym, następujące dwa definicje funkcji są semantycznie równoważne:

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

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

To samo pojęcie istnieje dla klas, ale jest tam rzadziej używany. Definicje funkcji i klas można znaleźć w dokumentacji więcej o dekoratorach.

Widzimy więc, że

@foo
def bar():
    pass

Jest semantycznie takie samo jak:

def bar():
    pass

bar = foo(bar)

Nie są dokładnie takie same, ponieważ Python ocenia wyrażenie foo (które może być przeszukiwaniem kropkami i wywołaniem funkcji) przed składnią paska z dekoratorem (@), ale oblicza wyrażenie foo po pasku w drugim case.

(jeśli ta różnica ma znaczenie w Twoim kodzie, powinieneś przemyśleć to, co robisz ze swoim życiem, ponieważ byłoby to patologiczne.)

Ułożone Dekoratory

Jeśli wrócimy do dokumentacji składni definicji funkcji, zobaczymy:

@f1(arg)
@f2
def func(): pass

Jest mniej więcej równoważne

def func(): pass
func = f1(arg)(f2(func))

Jest to demonstracja, że możemy najpierw wywołać funkcję, która jest dekoratorem, a także stos dekoratorów. Funkcje, w Pythonie, są obiektami pierwszej klasy - co oznacza, że można przekazać funkcję jako argument do innej funkcji i zwracać funkcje. Dekoratorzy robią obie te rzeczy.

Jeśli stosujemy dekoratory, funkcja, jak zdefiniowano, jest przekazywana najpierw dekoratorowi bezpośrednio nad nim, a następnie następnej, i tak dalej.

Że o podsumowuje użycie dla @ W kontekście dekoratorów.

Operator, @

W sekcji Analiza leksykalna w tym przypadku, jeśli nie jest to możliwe, nie jest to konieczne, ponieważ nie jest to konieczne do osiągnięcia zamierzonego celu.]}

Następujące tokeny są operatorami:

+       -       *       **      /       //      %      @
<<      >>      &       |       ^       ~
<       >       <=      >=      ==      !=

I na następnej stronie, model danych, mamy sekcję , emulującą typy numeryczne ,

object.__add__(self, other)
object.__sub__(self, other) 
object.__mul__(self, other) 
object.__matmul__(self, other) 
object.__truediv__(self, other) 
object.__floordiv__(self, other)

[...] Metody te są wywoływane do implementacji binarnych operacji arytmetycznych(+, -, *, @, /, //, [...]

I widzimy, że __matmul__ odpowiada @. Jeśli przeszukamy dokumentację pod kątem "matmul", otrzymamy link do Co nowego w Pythonie 3.5 z "matmul" pod nagłówkiem "PEP 465-dedykowany operator infiksu do mnożenia macierzy".

Można go zaimplementować definiując __matmul__(), __rmatmul__(), oraz __imatmul__() dla mnożenia macierzy regularnej, odbitej i w miejscu.

(więc teraz dowiadujemy się, że @= jest wersją in-place). To dalej wyjaśnia:

Mnożenie macierzy jest szczególnie powszechną operacją w wielu dziedzinach matematyka, nauki ścisłe, Inżynieria, a dodanie @ pozwala pisanie kodu:

S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)

Zamiast:

S = dot((dot(H, beta) - r).T,
        dot(inv(dot(dot(H, V), H.T)), dot(H, beta) - r))

Chociaż operator ten może być przeciążony, aby zrobić prawie wszystko, na przykład w numpy, użyjemy tej składni do obliczenia wewnętrznego i zewnętrznego iloczynu tablic i macierzy:

>>> 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]])

Mnożenie macierzy Inplace: @=

Badając wcześniejsze użycie, dowiadujemy się, że istnieje również mnożenie macierzy inplace. Jeśli spróbujemy go użyć, może się okazać, że nie jest jeszcze zaimplementowany dla 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'.

Kiedy zostanie zaimplementowany, spodziewam się, że wynik będzie wyglądał tak:

>>> m = matrix([1,2,3])
>>> m @= m.T
>>> m
matrix([[14]])
 43
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-05 17:19:02

Począwszy od Pythona 3.5, ' @ ' jest używany jako dedykowany symbol infiksu do mnożenia macierzy (PEP 0465 -- zobacz https://www.python.org/dev/peps/pep-0465/)

 6
Author: dpodbori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-07 23:18:41

Co robi symbol " at " ( @ ) w Pythonie?

@ symbol jest składniowym cukrem, który python dostarcza do wykorzystania decorator,
parafrazując pytanie, chodzi dokładnie o to, co dekorator robi w Pythonie?

Proste decorator pozwalają zmodyfikować definicję danej funkcji bez dotykania jej najgłębszej (jest zamknięciem).
Jest to najbardziej przypadek, gdy importujesz wspaniały pakiet od strony trzeciej. Można go wizualizować, można go używać, ale nie można go dotknąć najskrytsze i jego serce.

Oto szybki przykład,
Załóżmy, że definiuję read_a_book funkcję na Ipythonie

In [9]: def read_a_book():
   ...:     return "I am reading the book: "
   ...: 
In [10]: read_a_book()
Out[10]: 'I am reading the book: '

Widzisz, zapomniałem dodać nazwę do niego.
Jak rozwiązać taki problem? Oczywiście, mógłbym ponownie zdefiniować funkcję jako:

def read_a_book():
    return "I am reading the book: 'Python Cookbook'"

Niemniej jednak, co jeśli nie wolno mi manipulować oryginalną funkcją, lub jeśli są tysiące takich funkcji do obsługi.

Rozwiąż problem myśląc inaczej i zdefiniuj new_function

def add_a_book(func):
    def wrapper():
        return func() + "Python Cookbook"
    return wrapper

Więc go wykorzystaj.

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, widzisz, zmieniłem read_a_book nie dotykając tego wewnętrznego zamknięcia. Nic mnie nie powstrzyma.

O co chodzi @

@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 jest fantazyjnym i poręcznym sposobem na powiedzenie read_a_book = add_a_book(read_a_book), to cukier składniowy, nie ma w nim nic bardziej fantazyjnego.

 5
Author: JawSaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-26 02:21:07

@ symbol jest również używany do uzyskiwania dostępu do zmiennych wewnątrz zapytania plydata / pandas dataframe, pandas.DataFrame.query. Przykład:

df = pandas.DataFrame({'foo': [1,2,15,17]})
y = 10
df >> query('foo > @y') # plydata
df.query('foo > @y') # pandas
 2
Author: Aswin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-15 21:08:51

Wskazuje, że używasz dekoratora. Oto Przykład Bruce ' a Eckela z 2008 roku.

 1
Author: Peter Rowell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-17 23:22:51

Powiedzieć to, co inni mają w inny sposób: tak, to dekorator.

W Pythonie to tak:

  1. Tworzenie funkcji (następuje pod wywołaniem@)
  2. wywołanie innej funkcji do działania na utworzonej funkcji. To zwraca nową funkcję. Wywołana funkcja jest argumentem @.
  3. zastąpienie funkcji zdefiniowanej nową funkcją zwróconą.

To może być używane do wszelkiego rodzaju przydatnych rzeczy, możliwe, ponieważ funkcje są obiektami i tylko niezbędne tylko instrukcje.

 1
Author: Mayur Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-07 20:20:26