web-dev-qa-db-ja.com

Pythonのアットマーク(@)は何をするのですか?

私は@記号を使用したPythonコードを見ていますが、それが何をするのかわかりません。また、Pythonドキュメントを検索するときに何を検索するのかわからない、または@記号が含まれているとGoogleが適切な結果を返さない。

420
AJ00200

行頭の@記号は、クラス、関数、メソッドに使用されます デコレータ

もっと読む

PEP 318:デコレータ

Pythonデコレータ

あなたが遭遇する最も一般的なPythonのデコレータは以下のとおりです。

@property

@classmethod

@staticmethod

行の途中に@が表示されている場合、それは別のもの、行列の乗算です。下にスクロールして、@の使用に対処する他の回答を確認します。

215
FogleBird

前文

私はこの概念を完全に理解するのに数分以上かかることを認めているので、私は他の人たちが問題を解決するために学んだことを共有します。

デコレータ - 関数定義の前に@構文を使用して定義したもの - おそらくここでの主な原因でした。

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

これを実現することで、ついにフラスコとの平和を感じることができました。

282
Morgan Wilde

このコードスニペット:

def decorator(func):
   return func

@decorator
def some_func():
    pass

このコードと同等です:

def decorator(func):
    return func

def some_func():
    pass

some_func = decorator(some_func)

デコレータの定義では、通常は関数から返されないような変更されたものをいくつか追加できます。

150
Matheus Araujo

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]]
96
jinhwanlazy

Pythonのアットマーク(@)は何をするのですか?

つまり、デコレータの構文や行列の乗算に使用されます。

デコレータのコンテキストでは、この構文は次のとおりです。

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

これと同等です:

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

decorated_function = decorator(decorated_function)

行列乗算のコンテキストでは、a @ ba.__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

@が3つのコンテキストで使用されていることがわかります。

  • デコレータ
  • 因子間の演算子
  • 拡張代入演算子

デコレータの構文:

"decorator python docs"をグーグル検索すると、トップ結果の1つとして、 "Python言語リファレンス"の "複合ステートメント"セクションが得られます。 関数定義のセクション までスクロールしてみましょう。これはWordの "decorator"を検索することで見つけることができます。読むべきことがたくさんあります。しかし、Word、 "decorator"は用語集へのリンクです 、これは次のことを意味します。

デコレータ

別の関数を返す関数。通常は@wrapper構文を使用した関数変換として適用されます。デコレータの一般的な例はclassmethod()staticmethod()です。

デコレータの構文は単なる構文上の糖であり、次の2つの関数定義は意味的に同等です。

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

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

同じ概念がクラスにもありますが、それほど一般的ではありません。デコレータの詳細については、関数定義とクラス定義についてのドキュメントを参照してください。

だから、私たちはそれを見ます

@foo
def bar():
    pass

意味的には以下と同じです。

def bar():
    pass

bar = foo(bar)

Pythonは、デコレータ(@)構文を使ってbarの前のfoo式(ドットルックアップや関数呼び出し)を評価しますが、他の式ではfoo式 after barを評価するため、まったく同じではありません。場合。

(この違いによってコードの意味が変わる場合は、自分の人生で何をしているのかを再検討する必要があります。これは病理学的な問題となるためです。)

積み上げデコレータ

関数定義構文のドキュメントに戻ると、次のようになります。

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

とほぼ同等です

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

これは、スタックデコレータと同様に、デコレータである関数を最初に呼び出すことができるというデモンストレーションです。 Pythonでは、関数はファーストクラスオブジェクトです。つまり、関数を引数として別の関数に渡し、関数を返すことができます。デコレータはこれら両方を行います。

デコレータをスタックすると、定義されているように、関数は最初にそのすぐ上のデコレータに渡され、次に次のように渡されます。

これはデコレータのコンテキストで@の使用法をまとめたものです。

演算子@

言語リファレンスの字句解析セクションには、 演算子に関するセクション があります。これには@が含まれ、これも演算子になります。

次のトークンは演算子です。

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

そして次のページのデータモデルには、{ section、数値型のエミュレート 、があります。

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 @ 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]])
61
Aaron Hall

Pythonのアットマーク(@)は何をするのですか?

@記号はdecoratorを利用するためにpythonが提供する構文上の糖です。
質問を言い換えると、それはまさにデコレータが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_bookread_a_book = add_a_book(read_a_book)を言うための空想的で便利な方法です、それは統語論的な砂糖です、それについてそれ以上の空想的なものは何もありません。

22
JawSaw

Numpy libraryを使用しているPythonノートブックのコードを参照している場合、@ operator Matrix Multiplication を意味します。例えば:

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
12
f__society

Python 3.5からは、 '@'がMATRIX MULTIPLICATIONの専用の中置記号として使用されています(PEP 0465 - https://www.python.org/dev/peps/pep-0465/ を参照)。

8
dpodbori

@シンボルは、データ/パンダデータフレームクエリーpandas.DataFrame.query内の変数にアクセスするためにも使用されます。例:

df = pandas.DataFrame({'foo': [1,2,15,17]})
y = 10
df >> query('foo > @y') # plydata
df.query('foo > @y') # pandas
2
Aswin

関数とメソッドのラッピング(関数を受け取り、拡張された関数を返す関数)を読みやすく、理解しやすくするために、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式は許可されていません)で、呼び出されたときに1つの引数を受け取り(装飾された関数になります)別の呼び出し可能オブジェクト。ここでは、「関数」の代わりに計画的に「呼び出し可能」が使用されます。デコレータはメソッドと関数の範囲でよく議論されますが、それらに限定されません。実際、呼び出し可能なものはすべて(_call__メソッドを実装するオブジェクトは呼び出し可能と見なされます)、デコレーターとして使用でき、それらによって返されるオブジェクトは単純な関数ではなく、独自の__call_メソッドを実装するより複雑なクラスのインスタンスです。

デコレータの構文は、単にa構文糖のみです。次のデコレータの使用を検討してください。

@some_decorator
def decorated_function():
    pass

これは、常に明示的なデコレータ呼び出しと関数の再割り当てに置き換えることができます。

def decorated_function():
    pass
decorated_function = some_decorator(decorated_function)

ただし、後者は可読性が低く、1つの関数で複数のデコレータが使用されている場合は理解するのが非常に困難です。以下に示すように、デコレータは複数の異なる方法で使用できます。

関数として

カスタムデコレータを記述する方法は多数ありますが、最も簡単な方法は、元の関数呼び出しをラップするサブ関数を返す関数を記述することです。

一般的なパターンは次のとおりです。

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

デコレータのパラメータ化

実際のコードでは、パラメーター化できるデコレーターを使用する必要がしばしばあります。関数をデコレータとして使用する場合、解決策は簡単です。第2レベルのラッピングを使用する必要があります。以下は、呼び出されるたびに指定された回数だけ装飾された関数の実行を繰り返すデコレータの簡単な例です。

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の4つのオプション引数を取ります。最後のものは、属性であるかのようにリンクされているdocstringを定義するために提供できます。 2つのコーナーポイントを格納する属性に直接アクセスするか、widthプロパティとheightプロパティを使用して制御できるRectangleクラスの例を次に示します。

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
2
iun1x

他の人が別の方法で持っているものを言うために:はい、それはデコレータです。

Pythonでは、次のようになります。

  1. 関数を作成する(@呼び出しの下に続きます)
  2. 作成した関数を操作するために別の関数を呼び出す。これは新しい関数を返します。あなたが呼び出す関数は@の引数です。
  3. 定義された関数を新しい関数で置き換えます。

関数はオブジェクトであり、必要なのは単に命令であるため、これはあらゆる種類の便利なことに使用できます。

1
Mayur Patel

それはあなたがデコレータを使っていることを示しています。これが Bruce Eckelの例 2008年の/です。

1
Peter Rowell