2009-07-06 5 views
2

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

  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() 

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

+1

Предложение Orthogonal Python: лидирующие двойные подчеркивания не нужны, просто используйте один ведущий символ подчеркивания, а кодировщики Python признают, что он не является частью интерфейса по конфиденциальности джентльмена. – cdleary

+1

Как вы НЕ знали, что у вас есть заявление о доходности? Кто-то еще отредактировал ваш код, и вы сделали SVN и были удивлены обновлением? Какой сценарий привел к тому, что функция была генератором вместо обычного метода. –

+0

@ S.Lott: Скопировать/вставить, как упоминает его комментарий. Я всегда находил копии/пасты кода, чтобы вызвать больше головных болей, чем они решают, но я знаю, что многие люди считают их полезными. –

ответ

2

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

Регулярная функция, когда называется так:

val = func() 

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

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

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

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

6

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

Этот PEP http://www.python.org/dev/peps/pep-0255/ рассказывает о генераторах и может помочь вам лучше понять фон.

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

+0

Я, наконец, натолкнулся на pep 255. Он идет в детали. раздел «Спецификация: возврат» описывает некоторые из этих результатов. Кроме того, другие части pep упоминают или обсуждают проблемы с try/catch и использованием урожая. Я по-прежнему надеялся, что интерпретатор python может выдавать предупреждения (возможно, с соответствующими флагами); даже gcc предупредит вас о вещах, которые вы сказали, но, возможно, не имел в виду. – 2009-07-06 15:41:50

+0

Верно, что некоторые нативные компиляторы могут проверять проблемы с здравым смыслом, а иногда и для «вы сделали X, но вы, вероятно, имели в виду Y», но есть очень мало случаев, когда это правда, и они, как правило, весьма специфичны (например, порядок операции в выражении или if-test.) Но более высокий уровень: «Я еще не хотел возвращаться из этой функции, или я не хотел возвращаться таким образом» все еще выходит за рамки каких-либо компиляторов, я осознавая. Из любопытства, какой намек вы думаете, что компилятор мог иметь, что вы делаете не то? – Christopher

1

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

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

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

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

Из PEP:

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

2

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

0

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

Генераторы имеют имена с именем «generate» или «gen» в их имени. Он будет иметь выписку в теле. Довольно легко проверить визуально, поскольку ни один метод не содержит более 20 строк кода.

Другие методы не имеют «gen» в их имени.

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

Функция метода «генератор против негенератора» является полностью вопросом дизайна. Что должен был сделать программист? Компилятор не может легко подтвердить ваши намерения, он может только подтвердить то, что вы на самом деле набрали.