驚くべき機能


私は最近、Jjangoのソースコードを読んでいました.そして、私は@ wrapsデコレータに遭遇しました.その発見はこの記事の作成につながった.
このチュートリアルでは、あなたの人生をより簡単にするためにいくつかの素晴らしいFunctoolメソッドを使用する方法をお教えします.

関数とは


FunctionToolsはPythonの組み込みモジュールで、他の関数と対話できる高次の関数を含んでいます.完全なfunctoolsドキュメントがここで見つかります.
いくつかのデコレーターを見てみましょう.

Lruchenキャッシュ


同じ引数を持つ関数を呼び出すときに、FunFoolモジュール内のこのデコレータはキャッシュのn個の関数呼び出しを保存します.
デモンストレーションのために、実行するのに長い時間がかかる非常に大きな機能があると仮定してください.この関数で実行するには3秒かかります.
import time

start = time.time()
def a_heavy_operation():
    time.sleep(3)
    return 11 + 22


print(a_heavy_operation())
print(a_heavy_operation())

print(time.time() - start)

# Output
# 33
# 33
# 6.024240255355835
上記のコードを実行するには約6秒かかります.上記の関数には、LRUキャッシュを追加します.
import time
from functools import lru_cache

start = time.time()


@lru_cache()
def a_heavy_operation():
    time.sleep(3)
    return 11 + 22


print(a_heavy_operation())
print(a_heavy_operation())

print(time.time() - start)

# Output
# 33
# 33
# 3.0158064365386963

LRUキャッシュを使用してコードを高速化する方法を見てみましょう.Pythonは関数のキャッシュを保存し、キャッシュされた値を取得し、実行時間を短縮します.

ラップする


ラップは、関数の詳細を保つために、Functionツールで使用されます.関数を装飾するとき、関数の情報はなくなります.我々は、これを防ぐために@ wrapsのデコレータをデコレータラッパー関数に利用します.
私が意味するものを見るためにこのコードを見てください.
from functools import lru_cache


def my_decorator(func):
    def log(*args, **kwargs):
        print("Running ")
        return func(*args, *kwargs)

    return log


@my_decorator
def add(a, b):
    """my beautiful doc"""
    return a + b

上記のコードをI - modeで実行します.パイ
我々が持っているものを見ましょう
>>> add(1,2)
Running 
3
>>> add(3,4)
Running 
7
>>> add.__name__
log
>>> add.__doc__
>>>
私たちのデコレータは、それぞれのランで一貫して“実行”されているので、前の例で適切に動作していることがわかります.しかし、私たちの関数の情報は失われました、そして、それは名前またはdocstringを返すことができません.
我々は@この問題を私たちを助けるためにラップしている.以下のコードを変更します.
from functools import wraps

def my_decorator(func):
    @wraps(func)
    def log(*args, **kwargs):
        print("Running ")
        return func(*args, *kwargs)

    return log


@my_decorator
def add(a, b):
    """my beautiful doc"""
    return a + b

次に、python -i file.pyを使用してコードを実行します
>>> add(1,2) 
Running 
3       
>>> add.__name__
'add'
>>> add.__doc__
'my beautiful doc'
>>>
Voila!関数の情報は、我々の機能に保存されます.

シングルディスパッチ


汎用関数を作成するには、singledispatchを利用します.ジェネリック関数は、さまざまなデータ型で同じ操作を実行する関数です.
いくつかのデータ型のiterableから最初の値を返す関数を作成したいと仮定します.

def return_first_element(data):
    if isinstance(data, list):
        print(data[0])
    elif isinstance(data, str):
        print(data.split()[0])
    elif isinstance(data, dict):
        print(list(data.values())[0] )
    else:
        print(print(data))

これでPython - Iファイルを実行します.Pyは対話モードでコードを実行します.
>>> return_first_element({"Age":20, "Height": 180})
20
>>> return_first_element("Hello Mr Python")
Hello
>>> return_first_element([12,432,563])      
12
>>>
我々の機能は効果的ですが、それはきれいではありません.ジェネリック関数を作成するためにif/elif/elseステートメントを使用すると、Pythonでは推奨されません.では、解決策は?SingleDispatchももちろんです.
コードにいくつかの変更を加えましょう.
from functools import singledispatch

@singledispatch
def return_first_el(data):
    return data


@return_first_el.register(list)
def _(data):
    return data[0]


@return_first_el.register(dict)
def _(data):
    return list(data.values())[0]


@return_first_el.register(str)
def _(data):
    return data.split()[0]

結果を確認するには、Python - Iファイルを使用して再度対話モードでコードを実行します.Py
>>> return_first_el({"Age":20, "Height": 180}) 
20
>>> return_first_el("Hello Mr Python")             
'Hello'
>>> return_first_el([124, 765, 897])   
124
>>> return_first_el({12,31,1})       
{1, 12, 31}
どのようにデータ型が' Set 'にマッチしていないとき、我々のReturnNorst Rel機能がフォールバック機能としてどのように機能したかについて見てください.
どのようにクリーンなコードは、現在見ているSingleDispatchは、より多くのデータ型を追加することが容易になりました.また、各データ型では、データのさらなる操作を行うことができる独自の場所を取得します.

TOTALRAI注文


TotalRank Orderデコレータは、オブジェクト指向のプログラムで時間のトンを保存します.
この例を考えて、以下のクラスは、名前とageのプロパティを持つクラスのmanと、__eq__と(2424)7142のメソッドを宣言します.
class Man:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, o):
        return self.age == o.age

    def __lt__(self, o):
        return self.age < o.age

コードを実行してみましょう.
>>> obj = Man("Vivek", 20)
>>> obj2 = Man("Alex", 24) 
>>> obj = obj
>>> obj == obj2
False
>>> obj < obj2
True
>>> obj >= obj2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>=' not supported between instances of 'Man' and 'Man'
私たちのコードは(==)と(<)で働いていましたが、クラスで定義されていない演算子を使用したときには動きませんでした.少なくとも1つの演算子DunderメソッドとEQメソッドを作成すると、@ TotalRank Orderによって生成されます.
クラスのすぐ上にデコレーターを加えましょう.
from functools import total_ordering

@total_ordering
class Man:
.....
.....
次に、対話モードでのコードを実行し、結果を確認します
>>> o = Man("Vivek", 20) 
>>> b = Man("Alex", 24) 
>>> o == b
False
>>> o >= b  
False
>>> o <= b
True
合計順序がクラスの比較演算子を生成する方法を見てみましょう.

結論


このポストが役に立つことを願っています私は、これらのより高いレベル機能の内部の力学を完全に理解するために、あなたにドキュメンテーションを研究するよう強く強く勧めます.あなたがこれを楽しんだならば、私が私について、私がPython、ウェブ開発とオープンソースソフトウェアに関連したものを共有することについて考えてください.そこにお会いしましょう.