回答:
@
行頭のシンボルは、クラス、関数、メソッドのデコレータに使用されます。
詳細はこちら:
実行する最も一般的なPythonデコレータは次のとおりです。
@
線の真ん中にが表示されている場合、それは別のこと、行列の乗算です。下にスクロールして、の使用に対処する他の回答を確認します@
。
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
これを実現したことで、ようやく私はフラスコとの平和を感じることができました。
app.route("/")
:この関数は関数を返します。この関数はhello()
、引数として呼び出します
app.route("/", hello)
を定義した直後にhello
、あるいは定義hello
に引数にラムダとしてapp.route
?(後者の例では、Node.jsのと共通であり、http.Server
そしてエクスプレスルート)
このコードスニペット:
def decorator(func):
return func
@decorator
def some_func():
pass
このコードと同等です:
def decorator(func):
return func
def some_func():
pass
some_func = decorator(some_func)
デコレータの定義では、通常は関数から返されない変更されたものを追加できます。
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]]
@=
いる(インプレース)演算子を__imatmul__
。
__add__
おり、__sub__
それぞれに関連付けられていますが、その@
兆候を聞いたことはありません。他に潜んでいる人はいますか?
つまり、デコレータの構文や行列の乗算に使用されます。
デコレータのコンテキストでは、この構文は次のとおりです。
@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
ここで@
は、3つのコンテキストで使用されていることがわかります。
「decorator python docs」をGoogle検索すると、「Python言語リファレンス」の「複合ステートメント」セクションが上位の結果の1つとして表示されます。「デコレータ」という単語を検索して見つけることができる関数定義のセクションまで下にスクロールすると、次のことがわかります...読むべきことがたくさんあります。ただし、「デコレータ」という用語は用語集へのリンクであり、次のように説明しています。
デコレータ
通常は
@wrapper
構文を使用して関数変換として適用される、別の関数を返す関数。デコレータのための一般的な例ですclassmethod()
とstaticmethod()
。デコレータの構文は単なる構文上の砂糖であり、次の2つの関数定義は意味的に同等です。
def f(...): ... f = staticmethod(f) @staticmethod def f(...): ...
クラスにも同じ概念が存在しますが、そこではあまり使用されません。デコレータの詳細については、関数定義とクラス定義のドキュメントを参照してください。
だから、私たちはそれを見る
@foo
def bar():
pass
意味的には次と同じです:
def bar():
pass
bar = foo(bar)
Pythonは、decorator(@
)構文を使用して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 @ 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]])
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'"
それでも、元の関数を操作することが許可されていない場合、またはそのような関数が何千も処理されている場合はどうでしょうか。
別の考え方で問題を解決し、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_book
は空想的で便利な言い方ですread_a_book = add_a_book(read_a_book)
、それは構文上の砂糖であり、それ以上に凝ったものはありません。
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
関数とメソッドのラッピング(関数を受け取って拡張された関数を返す関数)を読みやすく、理解しやすくするために、デコレーターが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")
一般的な構文と可能な実装
デコレータは通常、名前付きオブジェクトであり(ラムダ式は許可されていません)、呼び出されたときに1つの引数を受け入れ(デコレートされた関数になります)、別の呼び出し可能なオブジェクトを返します。ここでは、「関数」の代わりに「呼び出し可能」を使用します。デコレータはメソッドと関数の範囲で議論されることが多いですが、それらに限定されません。実際、呼び出し可能なものはすべて(_call__メソッドを実装するオブジェクトは呼び出し可能と見なされます)、デコレータとして使用でき、それらによって返されるオブジェクトは単純な関数ではなく、独自の__call_メソッドを実装するより複雑なクラスのインスタンスが多くなります。
デコレータの構文は、単なる構文上の糖衣です。次のデコレータの使用法を検討してください。
@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
最後に、Propertiesでデコレータを確認します。
プロパティ
プロパティは、属性をメソッドのセットにリンクする方法を知っている組み込み記述子タイプを提供します。プロパティは4つのオプションの引数を取ります:fget、fset、fdel、およびdoc。最後のものは、あたかもそれがメソッドであるかのように、属性にリンクされている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
デコレータを使用していることを示しています。ここにあるブルース・Eckel氏の例 2008年からは。