Могу ли я быть предупрежден, когда я случайно использовал функцию генератора

StackOverflow https://stackoverflow.com/questions/1087019

Вопрос

Я работал с функциями генератора и частными функциями класса.Мне интересно

  1. Почему при выдаче (что в моем единственном случае было случайно) в __someFunc кажется, что эта функция просто не вызывается изнутри __someGenerator .Кроме того, какую терминологию я хочу использовать при описании этих аспектов языка?
  2. Может ли интерпретатор python предупреждать о таких случаях?

Ниже приведен примерный фрагмент моего сценария.

class someClass():
    def __init__(self):
        pass

    #Copy and paste mistake where yield ended up in a regular function
    def __someFunc(self):
        print "hello"
        #yield True #if yielding in this function it isn't called

    def __someGenerator (self):
        for i in range(0, 10):
            self.__someFunc()
            yield True
        yield False

    def someMethod(self):
        func = self.__someGenerator()
        while func.next():
            print "next"

sc = someClass()
sc.someMethod()

Я обжегся на этом и потратил некоторое время, пытаясь понять, почему функция просто не вызывалась.Наконец-то я обнаружил, что уступаю в выполнении функций, в которых не хотел участвовать.

Это было полезно?

Решение

Я постараюсь ответить на первый из ваших вопросов.

Обычная функция, вызываемая следующим образом:

val = func()

выполняет свои внутренние инструкции до тех пор, пока они не закончатся или return утверждение достигнуто.Затем возвращаемое значение функции присваивается val.

Если компилятор распознает функцию как фактически являющуюся генератором, а не обычной функцией (он делает это, ища yield операторы внутри функции - если есть хотя бы один, это генератор), сценарий при вызове его таким же образом, как описано выше, имеет разные последствия.При вызове func(), никакой код внутри функции не выполняется, и специальный <generator> значение присваивается val.Затем, в первый раз, когда вы звоните val.next(), фактические заявления о func выполняются до тех пор, пока yield или return встречается, при котором выполнение функции останавливается, возвращаемое значение возвращается, и генератор ожидает другого вызова val.next().

Вот почему, в вашем примере, функция __someFunc не напечатал "hello" - его инструкции не были выполнены, потому что вы не вызывали self.__someFunc().next(), но только self.__someFunc().

К сожалению, я почти уверен, что нет встроенного механизма предупреждения об ошибках программирования, подобных вашей.

Другие советы

"Генератор" - это не столько языковая функция, сколько название функций, которые "выдают". Выдача практически всегда законна.На самом деле у Python нет никакого способа узнать, что вы не "хотели" получить результат от какой-либо функции.

Этот БОДРЯЧОК http://www.python.org/dev/peps/pep-0255/ рассказывает о генераторах и, возможно, поможет вам лучше понять предысторию.

Я сочувствую вашему опыту, но компиляторы не могут понять, что вы "хотели, чтобы они сделали", только то, что вы на самом деле сказали им сделать.

Python не знает, хотите ли вы создать объект-генератор для последующей итерации или вызвать функцию.Но python - не ваш единственный инструмент для просмотра того, что происходит с вашим кодом.Если вы используете редактор или IDE, который позволяет настраивать подсветку синтаксиса, вы можете указать ему придать ключевому слову yield другой цвет или даже яркий фон, что, по крайней мере, поможет вам быстрее находить свои ошибки.В vim, например, вы могли бы сделать:

:syntax keyword Yield yield
:highlight yield ctermbg=yellow guibg=yellow ctermfg=blue guifg=blue

Кстати, это ужасные цвета.Я рекомендую выбрать что-нибудь получше.Другой вариант, если ваш редактор или IDE не будут сотрудничать, - настроить пользовательское правило в программе проверки кода, такой как pylint.Пример из архива с исходным кодом pylint:

from pylint.interfaces import IRawChecker
from pylint.checkers import BaseChecker

class MyRawChecker(BaseChecker):
    """check for line continuations with '\' instead of using triple
    quoted string or parenthesis
    """

    __implements__ = IRawChecker

    name = 'custom_raw'
    msgs = {'W9901': ('use \\ for line continuation',
                     ('Used when a \\ is used for a line continuation instead'
                      ' of using triple quoted string or parenthesis.')),
           }
    options = ()

    def process_module(self, stream):
        """process a module

        the module's content is accessible via the stream object
        """
        for (lineno, line) in enumerate(stream):
            if line.rstrip().endswith('\\'):
                self.add_message('W9901', line=lineno)


def register(linter):
    """required method to auto register this checker"""
    linter.register_checker(MyRawChecker(linter))

Руководство по pylint доступно здесь: http://www.logilab.org/card/pylint_manual И документация по синтаксису vim находится здесь: http://www.vim.org/htmldoc/syntax.html

Потому что return ключевое слово применимо как в функциях генератора, так и в обычных функциях, вы ничего не могли бы проверить (как упоминает @Christopher).В return ключевое слово в генераторе указывает, что должно быть вызвано исключение StopIteration.

Если вы попытаетесь return со значением из генератора (что не имеет смысла, поскольку return просто означает "остановить итерацию"), компилятор будет жаловаться во время компиляции - это может привести к некоторым ошибкам копирования и вставки:

>>> def foo():
...     yield 12
...     return 15
... 
  File "<stdin>", line 3
SyntaxError: 'return' with argument inside generator

Лично я просто не советую программировать методом копирования и вставки.:-)

От БОДРОГО духа:

Обратите внимание, что return означает "Я закончил, и у меня нет ничего интересного для return", как для функций генератора, так и для функций, не являющихся функциями генератора.

Мы делаем это.

Генераторы имеют имена с "generate" или "gen" в их названии.У него будет оператор yield в теле.Довольно легко проверить визуально, так как ни один метод не занимает намного больше 20 строк кода.

Другие методы не имеют "gen" в своем названии.

Кроме того, мы не каждый раз используем __ (двойное подчеркивание) имена при любых обстоятельствах.32 000 строк кода.Не __ имена.

"Генератор противфункция метода "без генератора" - это полностью вопрос дизайна.Что программист "намеревался" сделать.Компилятор не может легко проверить ваше намерение, он может проверить только то, что вы на самом деле ввели.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top