Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

DecoratorとDecomakerを一つの関数で定義する方法

More than 3 years have passed since last update.

Pytestでfixtureを定義するとき、デコレータfixtureは括弧と引数無しでも、(scope="session")といった括弧と引数がある使い方でもどちらでもサポートしています。次のコードはPytestのドキュメントにある両方の使い方の例です。

引用元: Pytestのドキュメント

括弧と引数無しの使い方

@pytest.fixture
def smtp():
    return smtplib.SMTP("smtp.gmail.com")

括弧と引数有りの使い方

@pytest.fixture(scope="module")
def smtp():
    return smtplib.SMTP("smtp.gmail.com")

どうやってこのようなデコレータを記述しているのか、調べてみました。

正確に記すと、前者の括弧と引数無しの用法でのfixtureはデコレータと呼び、後者の括弧と引数有りの用法ではfixtureはデコレータを作成するデコメーカー(decomaker)というものです。(PEP 318 -- Decorators for Functions and Methods)

Pytestのfixtureのソースでは、fixtureは次のように実装されていました。

def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
    """ (return a) decorator to mark a fixture factory function.

    This decorator ....(略)    
    """
    if callable(scope) and params is None and autouse == False:
        # direct decoration
        return FixtureFunctionMarker(
                "function", params, autouse, name=name)(scope)
    if params is not None and not isinstance(params, (list, tuple)):
        params = list(params)
    return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)

括弧と引数無しのデコレータとしてfixtureが用いられた場合、fixtureの引数scopeには、デコレータに続く関数定義で定義された関数オブジェクト(上記の例ではsmtp)が渡されます。

if callable(...の行で、scopecallableであるかどうか(と同時に後に続く引数がデフォルト値であるか)を調べ、そうであった場合、デコメーカーFixtureFunctionMakerのインスタンスを作成し、さらにその()scopeを渡しています。

一方、括弧と引数有りでfixtureが使用された場合、デコレータ(デコメーカーのインスタンス)自体を返しています。Pythonは、返されたデコレータにsmtpを渡して返り値を名前smtpにアサインします。

最初引数scopeを全く別の目的に使用している点が気持ち悪いですが、一つの関数に集約できてユーザーにとっては使いやすいデコレータのインターフェースができます。

fumitoh
Pythonの言語仕様や実装に関する備忘録が中心です。たまに便利なTipsなども投稿します。
https://github.com/fumitoh
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away