Best way to ensure user calls methods in correct order?

Thomas Nyberg tomuxiong at gmx.com
Thu Jun 22 09:53:04 EDT 2017


Hello,

I have a situation in which I want a user to call methods in a certain
order and to force the re-calling of methods "down-stream" if upstream
methods are called again. An example of this sort of thing would be a
pipeline where calling methods again invalidates the results of methods
called afterwards and you'd like to warn the user of that.

Here is a very simplified example:

ordered_consistency.py
-----------------------------------------------
class ConsistencyError(Exception):
    pass

class C:
    def __init__(self):
        self._a_dirty = self._b_dirty = self._c_dirty = True

    def a(self):
        self._a_dirty = self._b_dirty = self._c_dirty = True
        print("Calling a()...")
        self._a_dirty = False

    def b(self):
        if self._a_dirty:
            raise ConsistencyError("Re-run a() before calling b()!")
        self._b_dirty = self._c_dirty = True
        print("Calling b()...")
        self._b_dirty = False

    def c(self):
        if self._b_dirty:
            raise ConsistencyError("Re-run b() before calling c()!")
        self._c_dirty = True
        print("Calling c()...")
        self._c_dirty = False

    def d(self):
        if self._c_dirty:
            raise ConsistencyError("Re-run c() before calling d()!")
        print("Calling d()...")

c = C()
# This is fine:
c.a()
c.b()
c.c()
c.d()
# This is also fine (with same class instantiation!)
c.c()
c.d()
# This throws an error:
c.b()
c.d()
-----------------------------------------------

Here's what you get when calling it:
-----------------------------------------------
$ python3 ordered_methods.py
Calling a()...
Calling b()...
Calling c()...
Calling d()...
Calling c()...
Calling d()...
Calling b()...
Traceback (most recent call last):
  File "ordered_methods.py", line 43, in <module>
    c.d()
  File "ordered_methods.py", line 29, in d
    raise ConsistencyError("Re-run c() before calling d()!")
__main__.ConsistencyError: Re-run c() before calling d()!
-----------------------------------------------

My solution seems to work, but has a large amount of repetition and
errors will certainly be introduced the first time anything is changed.
I have the following questions:

	1) Most importantly, am I being stupid? I.e. is there some obviously
better way to handle this sort of thing?
	2) Is there an out of the box solution somewhere that enforces this
that I've never seen before?
	3) If not, can anyone here see some sort of more obvious way to do this
without all the repetition in dirty bits, error messages, etc.?

I presume a decorator could be used to do some sort of "order
registration", but I figure I might as well ask before I re-invent a
hexagonal wheel. Thanks a lot for any help!

Cheers,
Thomas



More information about the Python-list mailing list