Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Un yield pour couper sa fonction en deux ?

+1 vote

Je travaille avec WAMP, Crossbar.io et Autobahn et j'ai besoin de faire ça. J'en déduis le code suivant (la limite de caractères m'empêche de le poster ici) :

data.py

locator.py

Seulement, c'est pas optimal : j'ai deux fonctions (is_ et set_) et des if de partout dans mon locator. Et encore, je n'ai pas beaucoup de trucs à faire.

Du coup, je voulais fusionner les is_ et les set_. Sauf qu'avec mon histoire de transaction, il faut que je teste si tous les arguments de chaque fonction sont corrects avant d'exécuter ces dernières (faire tous les is_ puis tous les set_). Du coup, je me suis dis que j'allais passer par un générateur, pour modéliser cette coupure entre vérification et affectation :

data.py v2

Et utiliser cette affaire comme ça :

locator.py v2

tools.py

Sauf que pickle ne veut pas me sérialiser mon générateur. D'où mes questions :

  • S'agit-il de la bonne manière de faire ?
  • Puis-je sérialiser un générateur ?
demandé 16-Fev-2015 par Vayel (1,050 points)

1 Réponse

+4 votes
 
Meilleure réponse

Avec des if, trop sale et pas assez Pythonique. Avec des yield, beaucoup trop compliqué. Il vaut mieux utiliser les exceptions (version 3) :

data.py :

from twisted.internet.defer import inlineCallbacks

from autobahn import wamp
from autobahn.twisted.wamp import ApplicationSession
from autobahn.twisted.wamp import ApplicationRunner



class PositionError(ValueError):
    pass


class Data(ApplicationSession):

    DIRECTIONS = (-1, 1)

    def __init__(self, config):
        ApplicationSession.__init__(self, config)

        self.positions = ['', '', '', '', '', '']
        self.markables = [True, True, False, True, False, False]
        self.position = 0
        self.direction = 1

    @inlineCallbacks
    def onJoin(self, details):
        yield self.register(self)

    @wamp.register(u'data.get_direction')    
    def get_direction(self):
        return self.direction

    @wamp.register(u'data.get_position')    
    def get_position(self):
        return self.position

    @wamp.register(u'data.check_markable')    
    def check_markable(self, pos):
        self.check_position(pos)

        try:
            assert self.markables[pos]
        except AssertionError:
            raise PositionError('The position {} is not markable.'.format(pos))

    @wamp.register(u'data.check_position')    
    def check_position(self, pos):
        try:
            self.positions[pos]
        except IndexError:
            raise PositionError('The position {} does not exist.'.format(pos))

    @wamp.register(u'data.check_sth')
    def check_sth(self):
        pass 

    @wamp.register(u'data.mark_position')    
    def mark_position(self, pos):
        """``pos`` is a markable position."""

        self.positions[pos] = 'marked'

        print('Positions: {}'.format(self.positions))

    @wamp.register(u'data.set_position')    
    def set_pos(self, pos):
        """``pos`` is an existing position."""

        self.position = pos

        print('Position: {}'.format(self.position))

    @wamp.register(u'data.do_sth')
    def do_sth(self):
        print('Something done.')


if __name__ == "__main__":
    print('Starting Data component...')

    ApplicationRunner(url='ws://localhost:8080/ws', realm='realm1').run(Data)

locator.py :

from twisted.internet.defer import inlineCallbacks

from autobahn import wamp
from autobahn.twisted.wamp import ApplicationSession
from autobahn.wamp.exception import ApplicationError
from autobahn.twisted.wamp import ApplicationRunner



class Locator(ApplicationSession):

    @inlineCallbacks
    def onJoin(self, details):
        yield self.register(self)

    @wamp.register(u'locator.move')
    @inlineCallbacks
    def move(self):
        """Try to mark the current position and to go to the next one. Fail if 
        the current position is not markable or if the next position does not 
        exist.
        """

        print('Move!')

        pos = yield self.call('data.get_position')
        direction = yield self.call('data.get_direction')
        next_pos = pos + direction

        try:
            yield self.call('data.check_markable', pos)
            yield self.call('data.check_position', next_pos)
        except ApplicationError as e:
            raise e
        else:
            self.call('data.mark_position', pos)
            self.call('data.set_position', next_pos)
        finally:
            try:
                yield self.call('data.check_sth')
            except ApplicationError as e:
                raise e
            else:
                self.call('data.do_sth')


if __name__ == "__main__":
    print('Starting Locator component...')

    ApplicationRunner(url='ws://localhost:8080/ws', realm='realm1').run(Locator)

Il faudrait juste offrir une jolie interface pour éviter ce code spaghetti, mais ce sera l'affaire d'un autre sujet.

répondu 17-Fev-2015 par Vayel (1,050 points)
...