[PYTHON] Überprüfen Sie den Rückgabewert mit PEP 380

Verwenden Sie dieses Mal PEP 380, um "Ausbeute Keine" gleich "Rückgabe" zu machen, und der Rückgabewert sollte ein Nicht-Keine-Wert sein. Wir stellen den Dekorateur vor, um ihn zu überprüfen.

PEP 380 ist eine neue Spezifikation hinzugefügt in Python 3.3, die eine [Ausbeute von] für mehrstufige Generatoren darstellt. Der Hauptzweck ist das Hinzufügen von Syntax, diesmal jedoch, wie viele zusätzlich zum Ertrag aus der Syntax hinzugefügt wurden. Ich habe einen Dekorateur geschrieben, der mit dieser Funktion "Ausbeute keine" gleich "Rückgabe" macht.

Die meisten Leute

Wie ist die Beziehung zwischen dem Äquivalent von "Yield None" zu "Return" und der Überprüfung, ob der Rückgabewert ein Nicht-None-Wert ist?

Ich denke, Sie haben die Frage, also lassen Sie mich Ihnen eine einfache Funktion als Beispiel geben.

python


    def get_version(self, config_path=None):
        if config_path is None:
            config_path = self.get_default_config_path()
        config = self.parse_config(config_path)
        program_name = config.get("program_name")
        match = RE_VERSION.match(program_name)
        return match.group("version")

Es ist schwer zu verstehen, da es nur ein Teil ist, aber dieses get_version () ruft den Pfad der Einstellungsdatei ab, analysiert die Datei und extrahiert den Versionsteil als regulären Ausdruck aus dem Element"Programmname". Die zurückzugebende Funktion.

Ich bin an reguläre Ausdrücke gewöhnt, daher zögere ich nicht, sie zu verwenden. Wenn ich jedoch reguläre Ausdrücke für diese Art der Verarbeitung verwende,

Ein solcher Code ist nicht Pythonic!

Bitte beachten Sie, dass Pythonista-Leute möglicherweise wütend werden.

Nun, dieser Code überprüft den Rückgabewert überhaupt nicht, wie Sie auf einen Blick sehen können.

Das ist also ein Problem

Der folgende Code wird geändert, um den Rückgabewert zu überprüfen, falls dies in der Regel erforderlich ist.

python


    def get_version(self, config_path=None):
            if config_path is None:
                config_path = self.get_default_config_path()
            if config_path is None:
                return None
            config = self.parse_config(config_path)
            if config is None:
                return None
            program_name = config.get("program_name", None)
            if program_name is None:
                return None
            match = RE_PROGRAM_VERSION.match(program_name)
            if match is None:
                return None
            return match.group("version")

Infolgedessen ist der Code voll mit "Wenn xxx Keine ist: Keine zurückgeben", und die Funktion, die 7 Zeilen umfasste, umfasst jetzt 15 Zeilen.

Ich wollte schon immer etwas dagegen tun, deshalb habe ich einen Dekorateur namens "Yield_none_becomes_return ()" geschrieben, der die in PEP 380 hinzugefügten Funktionen verwendet, wie bereits erwähnt.

Unten ist der Code mit "ield_none_becomes_return () ", der auf die erste Version angewendet wird.

python


    @yield_none_becomes_return
    def get_version(self, config_path=None):
        if config_path is None
            config_path = yield self.get_default_config_path()
        config = yield self.parse_config(config_path)
        program_name = yield config.get("program_name")
        match = yield RE_VERSION.match(program_name)
        return match.group("version")

Der Code, der in der vorherigen Version 15 Zeilen umfasste, besteht jetzt aus 8 Zeilen.

Der einzige Unterschied zur ersten Version besteht in der Hinzufügung von Dekorateuren und "Ertrag", und nichts anderes hat sich geändert.

Der Prozess von "ield_none_becomes_return () "ist einfach. Zum Beispiel

python


        config_path = yield self.get_default_config_path()

Wenn der Rückgabewert von "self.get_default_config_path ()" "None" ist, wird "yield None" festgelegt, und sofort "return", wenn es nicht "None" ist, den Wert an "config_path" zurückgeben. Ersetzen Sie die Verarbeitung und setzen Sie sie fort.

Wenn der Dekorateur kein Argument enthält, entspricht dies "return", sodass "None" zurückgegeben wird.

python


    @yield_none_becomes_return("")

Durch Angabe eines Arguments wie ist es auch möglich, einen beliebigen Wert zurückzugeben, wenn "Ausbeute keine" erfüllt ist.

Wenn Sie jedoch ein Objekt zurückgeben möchten, das mit callable () ausgewertet wird und true ist,

python


    @yield_none_becomes_return(value=function)

Bitte beschreiben Sie als. Dies ist aus verschiedenen Gründen eine Einschränkung.

Die einzige andere Sache, die zu beachten ist, ist, dass StopIteration () nicht an den Aufrufer der dekorierten Funktion weitergegeben wird.

Die Quelle von "yield_none_becomes_return ()" ist unten angegeben. Bitte teilen Sie uns mit, wenn Sie weitere Probleme finden.

ynbr.py


#!/usr/bin/env python3
# vim:fileencoding=utf-8

# Copyright (c) 2014 Masami HIRATA <[email protected]>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     1. Redistributions of source code must retain the above copyright notice,
#        this list of conditions and the following disclaimer.
#
#     2. Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import sys

if sys.version_info < (3, 3):  # pragma: no cover
    raise ImportError("Python >= 3.3 is required")

from functools import partial, wraps
from inspect import isgeneratorfunction

DEFAULT = object()

__all__ = ['yield_none_becomes_return']


def yield_none_becomes_return(function=DEFAULT, *, value=DEFAULT):
    """This decorator changes the yield statement to None checker for
       avoiding "if xxx is None: return" statements

    For example:
    # without this decorator:
    def get_version(self, config_path=None):
        if config_path is None:
            config_path = self.get_default_config_path()
        if config_path is None:
            return ""
        config = self.parse_config(config_path)
        if config is None:
            return ""
        program_name = config.get("program_name")
        if program_name is None:
            return ""
        match = RE_PROGRAM_VERSION.match(program_name)
        if match is None:
            return ""
        return match.group("version")

    # with this decorator:
    @yield_none_becomes_return("")
    def get_version(self, config_path=None):
        if config_path is None:
            config_path = yield self.get_default_config_path()
        config = yield self.parse_config(config_path)
        program_name = yield config.get("program_name")
        match = yield RE_VERSION.match(program_name)
        return match.group("version")
    """

    if not isgeneratorfunction(function):
        if function is DEFAULT:
            if value is DEFAULT:
                # @yield_none_becomes_return()  # CORRECT
                value = None
        else:
            if callable(function):
                raise TypeError("@yield_none_becomes_return is used only " +
                                "for generator functions")

            if value is not DEFAULT:
                # @yield_none_becomes_return("B", value="C")  # WRONG
                raise TypeError("yield_none_becomes_return() takes " +
                                "1 argument but 2 were given.")

            # @yield_none_becomes_return("A")  # CORRECT
            value = function
        return partial(yield_none_becomes_return, value=value)
    else:
        if value is DEFAULT:
            value = None

    @wraps(function)
    def _yield_none_becomes_return(*args, **kwargs):
        generator = function(*args, **kwargs)
        try:
            return_value = next(generator)
            while True:
                if return_value is not None:
                    return_value = generator.send(return_value)
                else:
                    return value
        except StopIteration as exception:
            return exception.value

    return _yield_none_becomes_return

Recommended Posts

Überprüfen Sie den Rückgabewert mit PEP 380
Über den Rückgabewert von pthread_mutex_init ()
Über den Rückgabewert des Histogramms.
Überprüfen Sie den Python-Codestil mit pep8
Achten Sie auf den Rückgabewert von __len__
Generieren Sie Hash-Werte mit der HMAC-Methode.
Überprüfen Sie den Status der Daten mit pandas_profiling
Setzen Sie die Anzahl der Hot-codierten Features auf den ursprünglichen Kategoriewert zurück
Die Geschichte, dass der Rückgabewert von tape.gradient () None war
Versuchen Sie es mit der Twitter-API
Klonen Sie mit dem Befehl dd
Versuchen Sie es mit der Twitter-API
Versuchen Sie es mit der PeeringDB 2.0-API
Überprüfen Sie den Code mit flake8
Umrisse das Gesicht mit Dlib (1)
[Python] Überprüfen Sie die installierten Bibliotheken
Rufen Sie den Wert des Dropdown-Menüs mit Python und Selen ab und legen Sie ihn fest
Überprüfen Sie das Zeichnungsergebnis mit Plotly, indem Sie CodePen in Qiita einbetten
Finden Sie den optimalen Wert der Funktion mit einem genetischen Algorithmus (Teil 1)