Domanda

Stavo lavorando con funzioni di generatore e funzioni private di una classe.mi chiedo

  1. Perché quando si cede (che nel mio caso è stato per sbaglio) in __someFunc questa funzione sembra non essere chiamata dall'interno di __someGenerator.Inoltre, qual è la terminologia che voglio usare quando mi riferisco a questi aspetti della lingua?
  2. L'interprete Python può avvisare di tali casi?

Di seguito è riportato un frammento di esempio del mio scenario.

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

Mi sono scottato su questo e ho passato un po' di tempo cercando di capire perché una funzione non veniva chiamata.Alla fine ho scoperto che stavo cedendo in una funzione che non volevo svolgere.

È stato utile?

Soluzione

Provo a rispondere alla prima delle tue domande.

Una funzione regolare, quando chiamata in questo modo:

val = func()

esegue le sue istruzioni interne finché non termina o a return viene raggiunta la dichiarazione.Quindi viene assegnato il valore restituito della funzione val.

Se un compilatore riconosce che la funzione è effettivamente un generatore e non una funzione regolare (lo fa cercando yield istruzioni all'interno della funzione -- se ce n'è almeno una, è un generatore), lo scenario quando lo si chiama nello stesso modo di sopra ha conseguenze diverse.Alla chiamata func(), nessun codice all'interno della funzione viene eseguito, e uno speciale <generator> viene assegnato il valore val.Poi, la prima volta che chiami val.next(), le dichiarazioni effettive di func vengono eseguiti fino a quando a yield O return viene incontrato, dopodiché l'esecuzione della funzione si interrompe, viene restituito il valore restituito e il generatore attende un'altra chiamata a val.next().

Ecco perché, nel tuo esempio, function __someFunc non ha scritto "ciao" -- le sue istruzioni non sono state eseguite perché non hai chiamato self.__someFunc().next(), ma solo self.__someFunc().

Sfortunatamente, sono abbastanza sicuro che non esista un meccanismo di avviso integrato per errori di programmazione come il tuo.

Altri suggerimenti

A "generatore" non è tanto una caratteristica del linguaggio, come un nome per le funzioni che "resa". Cedendo è praticamente sempre legale. Non c'è davvero nessun modo per Python per sapere che non hai "significa" a cedere da qualche funzione.

Questa PEP http://www.python.org/dev/peps/pep -0255 / parla di generatori, e possono aiutare a capire meglio lo sfondo.

Sono solidale con la vostra esperienza, ma i compilatori non riesco a capire quello che "significava per loro di fare", solo ciò che in realtà ha detto loro di fare.

Python non sa se si desidera creare un oggetto generatore per la successiva iterazione o chiamare una funzione. Ma python non è il vostro unico strumento per vedere cosa sta succedendo con il codice. Se stai usando un editor o IDE che permette la sintassi personalizzato evidenziazione, si può dire che per dare la parola resa di un colore diverso, o anche uno sfondo luminoso, che vi aiuterà a trovare i vostri errori più rapidamente, almeno. In vim, ad esempio, si potrebbe fare:

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

Questi sono i colori orrendi, tra l'altro. Mi consiglia di scegliere qualcosa di meglio. Un'altra opzione, se il vostro editor o IDE non collaboreranno, è quello di creare una regola personalizzata in un correttore codice come pylint. Un esempio dal tarball fonte di 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))

Il manuale pylint è disponibile qui: http://www.logilab.org/card/pylint_manual E la documentazione della sintassi di vim è qui: http://www.vim.org/htmldoc/syntax.html

Perché la parola return è applicabile in entrambe le funzioni del generatore e delle funzioni regolari, non c'è niente che si possa controllare (come cita @Christopher). La parola chiave return in un generatore indica che un'eccezione StopIteration dovrebbe essere aumentata.

Se si tenta di return con un valore all'interno di un generatore (che non ha senso, dal momento che return significa solo "stop iterazione"), il compilatore si lamenterà a tempo di compilazione - questo può prendere un po 'di copia e errori -paste:

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

Io personalmente sconsiglio solo copia e incolla di programmazione. : -)

Dal PEP:

  

Si noti che il ritorno significa "ho finito, e non hanno nulla interessante   ritorno", sia per le funzioni del generatore e funzioni non-generatore.

Lo facciamo.

I generatori hanno nomi con "generare" o "gen" nel loro nome. Avrà una dichiarazione resa nel corpo. Abbastanza facile da controllare visivamente, dal momento che nessun metodo è molto più di 20 righe di codice.

Altri metodi non hanno "gen" nel loro nome.

Inoltre, non lo facciamo ogni uso __ (doppia sottolineatura) nomi in nessun caso. 32.000 righe di codice. nomi non __.

La funzione metodo "generatore vs non-generatore" è interamente una questione di progettazione. Che cosa ha fatto il programmatore "intendere" accada. Il compilatore non può facilmente convalidare il vostro intento, si può convalidare solo quello che effettivamente digitato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top