Pergunta

Eu estava trabalhando com funções de gerador e eventos privados de uma classe. Eu estou querendo saber

  1. Por que ao ceder (que na minha um caso foi por acidente) em __someFunc que esta função só não parece ser chamado de dentro __someGenerator. Também o que é a terminologia que eu quero usar quando se refere a estes aspectos da linguagem?
  2. Pode o interpretador Python alertam para tais casos?

Abaixo está um exemplo de trecho de meu cenário.

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

Eu me queimei sobre isso e passei algum tempo tentando descobrir por que uma função simplesmente não estava sendo chamado. Eu finalmente descobri que eu estava produzindo na função que eu não queria na.

Foi útil?

Solução

Vou tentar responder à primeira de suas perguntas.

A função de regular, quando chamado como este:

val = func()

executa suas instruções dentro até que ela termine ou uma declaração return é atingido. Em seguida, o valor de retorno da função é atribuído a val.

Se um compilador reconhece a função para ser realmente um gerador e não uma função (ele que, ao olhar para as demonstrações yield dentro da função - se há pelo menos um, é um gerador), o cenário quando chamando-o mesma maneira como acima tem consequências diferentes. Após a func() chamando, nenhum código dentro da função é executado , e um valor especial <generator> é atribuído a val. Então, a primeira vez que você chamar val.next(), as demonstrações reais de func estão sendo executadas até que um yield ou return é encontrado, sobre o qual a execução da função pára, valor rendeu é retornado e gerador de espera por outra chamada para val.next().

É por isso que, no seu exemplo, a função __someFunc não imprimir "Olá" -. Suas declarações não foram executados, porque você não ter chamado self.__someFunc().next(), mas apenas self.__someFunc()

Infelizmente, eu tenho certeza que não há nenhum mecanismo interno de alerta para erros de programação como o seu.

Outras dicas

A "gerador" não é tanto um recurso de linguagem, como um nome para funções que "rendimento". Cedendo é praticamente sempre legal. Não há realmente qualquer maneira para Python para saber que você não fez "média" para produzir a partir de alguma função.

Esta PEP http://www.python.org/dev/peps/pep -0255 / fala sobre os geradores, e pode ajudá-lo a entender o contexto melhor.

Eu simpatizo com a sua experiência, mas compiladores não pode descobrir o que você "significava para eles a fazer", apenas o que você realmente lhes disse para fazer.

Python não sabe se você deseja criar um objeto gerador para a iteração mais tarde ou chamar uma função. Mas python não é sua única ferramenta para ver o que está acontecendo com o seu código. Se você estiver usando um editor ou IDE que permite a personalização destaque de sintaxe, você pode dizer que para dar o rendimento palavra-chave de uma cor diferente, ou mesmo um fundo brilhante, que vai ajudá-lo a encontrar os seus erros mais rapidamente, pelo menos. No vim, por exemplo, que você pode fazer:

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

Essas são as cores horrendas, pelo caminho. Eu recomendo pegar algo melhor. Outra opção, se o seu editor ou IDE não vai cooperar, é a criação de uma regra personalizada em um verificador de código como pylint. Um exemplo de tarball fonte de 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))

O manual pylint está disponível aqui: http://www.logilab.org/card/pylint_manual E documentação sintaxe de vim está aqui: http://www.vim.org/htmldoc/syntax.html

Porque a palavra-chave return é aplicável em ambas as funções de gerador e funções regulares, não há nada que você poderia verificar (como @Christopher menciona). A palavra-chave return em um gerador indica que uma exceção StopIteration deve ser levantada.

Se você tentar return com um valor a partir de um gerador (que não faz sentido, uma vez return apenas significa "paragem iteração"), o compilador vai reclamar em tempo de compilação - o que pode pegar alguns de copiar e erros -paste:

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

Eu, pessoalmente, apenas aconselhar contra copiar e colar programação. : -)

A partir do PEP:

Note-se que os meios de retorno "eu sou feito, e não têm nada interessante voltar", para ambas as funções de gerador e funções não-gerador.

Nós fazemos isso.

geradores têm nomes com "gerar" ou "gen" em seu nome. Ela terá uma declaração de rendimento no corpo. Muito fácil de verificar visualmente, uma vez que nenhum método é muito mais de 20 linhas de código.

Outros métodos não têm "gen" em seu nome.

Além disso, nós não cada utilização __ (sublinhado duplo) Nomes sob quaisquer circunstâncias. 32.000 linhas de código. nomes não __.

A função de método "gerador vs. não-gerador" é inteiramente uma questão de design. O que o programador "pretende" acontecer. O compilador não pode facilmente validar a sua intenção, ele só pode validar o que você realmente digitado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top