私は@
記号を使用したPythonコードを見ていますが、それが何をするのかわかりません。また、Pythonドキュメントを検索するときに何を検索するのかわからない、または@
記号が含まれているとGoogleが適切な結果を返さない。
行頭の@
記号は、クラス、関数、メソッドに使用されます デコレータ 。
もっと読む
あなたが遭遇する最も一般的な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
これを実現することで、ついにフラスコとの平和を感じることができました。
このコードスニペット:
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]]
つまり、デコレータの構文や行列の乗算に使用されます。
デコレータのコンテキストでは、この構文は次のとおりです。
@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"をグーグル検索すると、トップ結果の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]])
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_book
はread_a_book = add_a_book(read_a_book)
を言うための空想的で便利な方法です、それは統語論的な砂糖です、それについてそれ以上の空想的なものは何もありません。
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
Python 3.5からは、 '@'がMATRIX MULTIPLICATIONの専用の中置記号として使用されています(PEP 0465 - https://www.python.org/dev/peps/pep-0465/ を参照)。
@シンボルは、データ/パンダデータフレームクエリーpandas.DataFrame.query
内の変数にアクセスするためにも使用されます。例:
df = pandas.DataFrame({'foo': [1,2,15,17]})
y = 10
df >> query('foo > @y') # plydata
df.query('foo > @y') # pandas
関数とメソッドのラッピング(関数を受け取り、拡張された関数を返す関数)を読みやすく、理解しやすくするために、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
他の人が別の方法で持っているものを言うために:はい、それはデコレータです。
Pythonでは、次のようになります。
関数はオブジェクトであり、必要なのは単に命令であるため、これはあらゆる種類の便利なことに使用できます。
それはあなたがデコレータを使っていることを示しています。これが Bruce Eckelの例 2008年の/です。