How can I split a long function into separate steps while maintaining the connection between the specified steps?

I have a very long function functhat takes a browser handle and executes a bunch of requests and reads a bunch of responses in a specific order:

def func(browser):
    # make sure we are logged in otherwise log in
    # make request to /search and check that the page has loaded
    # fill form in /search and submit it
    # read table of response and return the result as list of objects

Each operation requires a lot of code due to the complexity of the DOM, and they tend to grow very fast.

What would be the best way to reorganize this function into smaller components so that the following properties are still preserved:

  • the flow of operations and / or their preconditions is guaranteed in the same way as in the current version
  • Prerequisites are not checked with statements regarding the condition, as this is a very expensive operation.
  • func can be called several times in the browser

?

+4
5

, .

class Helper(object):

    def __init__(self):
        self.a = True
        self.b = False
        self.c = False

    def funcA(self):
        if not self.A:
            raise Error("Cannot run funcA now")
        # do stuff here
        self.a = False
        self.b = True
        return whatever

    def funcB(self):
        if not self.B:
            raise Error("Cannot run funcB now")
        # do stuff here
        self.b = False
        self.c = True
        return whatever

    def funcC(self):
        if not self.C:
            raise Error("Cannot run funcC now")
        # do stuff here
        self.c = False
        self.a = True
        return whatever

def func(...):
    h = Helper()
    h.funcA()
    h.funcB()
    h.funcC()

# etc

- , . h.a et al. , , .

, , .

class Helper(object):
    def __init__(self):
        self.allowed = self.funcA
    def funcA(self):
        if self.allowed is not self.funcA:
            raise Error("Cannot run funcA now")
        # do stuff
        self.allowed = self.funcB
        return whatever
    # etc
+4

, . ( , ), .

def call_only_once(func):  
  def new_func(*args, **kwargs):  
    if not new_func._called:  
      try:  
        return func(*args, **kwargs)  
      finally:  
        new_func._called = True  
    else:
      raise Exception("Already called this once.")
  new_func._called = False  
  return new_func  

@call_only_once  
def stateA(): 
   print 'Calling stateA only this time' 

@call_only_once  
def stateB(): 
   print 'Calling stateB only this time'    

@call_only_once  
def stateC(): 
   print 'Calling stateC only this time' 

def state():
  stateA()
  stateB()
  stateC()

if __name__ == "__main__":
  state()

, - , Exception, , .

, - state(), . , , , , - Python.

else , None.

+2

,

class StateMachine(object):
    def __init__(self):
        self.handlers = {}
        self.start_state = None
        self.end_states = []

    def add_state(self, name, handler, end_state=0):
        name = name.upper()
        self.handlers[name] = handler
        if end_state:
            self.end_states.append(name)

    def set_start(self, name):
        # startup state
        self.start_state = name

    def run(self, **kw):
        """
        Run
        :param kw:
        :return:
        """
        # the first .run call call the first handler with kw keywords
        # each registered handler should returns the following handler and the needed kw 
        try:
            handler = self.handlers[self.start_state]
        except:
            raise InitializationError("must call .set_start() before .run()")
        while True:
            (new_state, kw) = handler(**kw)
            if isinstance(new_state, str):
                if new_state in self.end_states:
                    print("reached ", new_state)
                    break
                else:
                    handler = self.handlers[new_state]
            elif hasattr(new_state, "__call__"):
                handler = new_state
            else:
                return

class MyParser(StateMachine):
    def __init__(self):
        super().__init__()
        # define handlers
        # we can define many handler as we want
        self.handlers["begin_parse"] = self.begin_parse
        # define the startup handler
        self.set_start("begin_parse")

    def end(self, **kw):
        logging.info("End of parsing ")
        # no callable handler => end 
        return None, None

    def second(self, **kw):
        logging.info("second  ")
        # do something
        # if condition is reach the call `self.end` handler
        if ...:
            return self.end, {}

    def begin_parse(self, **kw):
        logging.info("start  of parsing ")
        # long process until the condition is reach then call the `self.second` handler with kw new keywords
        while True:
            kw = {}
            if ...:
                return self.second, kw
            # elif other cond:
                # return self.other_handler, kw
            # elif other cond 2:
                # return self.other_handler 2, kw
             else:
                return self.end, kw
# start the state machine
MyParser().run()

   INFO:root:start  of parsing 
   INFO:root:second  
   INFO:root:End of parsing
+1

func. , , Python , .

, 3 ( ) . test, test , :

def func(test=None):
    glob = []
    def partA():
        glob.append('A')
    def partB():
        glob.append('B')
    def partC():
        glob.append('C')
    if (test == 'TEST'):
        global testA, testB, testC, testCR
        testA, testB, testC, testCR = partA, partB, partC, glob
        return None
    partA()
    partB()
    partC()
    return glob

func, . func('TEST'), glob testCR, 3 - testA, testB testC. , - 3 .

0

, @user3159253 :

- , func "private" > "" (.. _func1 __func1) > , , .

- , . :

(teste.py):

class Test:
    def __init__(self):
        self.__environment = {}             # Protected information to be shared
        self.public_stuff = 'public info'   # Accessible to outside callers

    def func(self):
        print "Main function"
        self.__func_a()
        self.__func_b()
        self.__func_c()
        print self.__environment

    def __func_a(self):
        self.__environment['function a says'] = 'hi'

    def __func_b(self):
        self.__environment['function b says'] = 'hello'

    def __func_c(self):
        self.__environment['function c says'] = 'hey'

:

from teste import Test

t = Test()
t.func()

:

Main function says hey guys
{'function a says': 'hi', 'function b says': 'hello', 'function c says': 'hey'}

, :

Traceback (most recent call last):
  File "C:/Users/Lucas/PycharmProjects/testes/other.py", line 6, in <module>
    t.__func_a()
AttributeError: Test instance has no attribute '__func_a'

, :

Traceback (most recent call last):
  File "C:/Users/Lucas/PycharmProjects/testes/other.py", line 5, in <module>
    print t.__environment
AttributeError: Test instance has no attribute '__environment'

, , , , :)

0
source

All Articles