On Thu, 22 Jun 2017 11:53 pm, Thomas Nyberg wrote: > 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.
Don't do that. It's fragile and an anti-pattern. Your methods have too much coupling. If c() relies on b() being called first, then either b() or c() aren't good methods. They don't do enough: - calling b() alone doesn't do enough, so you have to call c() next to get the job done; - calling c() alone doesn't do enough, because it relies on b() being called first. There are a very few exceptions to this rule of thumb, such as opening connections to databases or files or similar. They are mostly enshrined from long practice, or justified by low-level APIs (that's how file systems and databases work, and it's not practical to change that). But you should try very hard to avoid creating new examples. Of course, I'm talking about your *public* methods. Private methods can be a bit more restrictive, since it's only *you* who suffers if you do it wrong. Ideally, your methods should be written in a functional style with as little shared state as possible. (Shared state introduces coupling between components, and excessive coupling is *the* ultimate evil in programming.) With no shared state, your methods are trivial: def a(self, arg): return something def b(self, arg): # relies on a x = self.a(arg) return process(x) def c(self, arg): # relies on b x = self.b(arg) return process(x) With shared state, it becomes more horrible, but at least your users are shared the pain. (*You* on the other hand, are not -- that's your punishment for writing in a Java-like style with lots of shared state.) def a(self): self.data = something self.step = 1 def b(self): # relies on a assert self.step >= 0 if self.step == 0: self.a() if self.step == 1: self.data = process(self.data) self.step = 2 else: assert self.step > 1 # do nothing? # or raise? def c(self): # relies on b assert self.step >= 0 if self.step < 2: self.b() if self.step == 2: self.data = process(self.data) self.step = 3 else: assert self.step > 1 # do nothing? # or raise? This is messy enough if there is only a single chain of correct calls: # you must call a, b, c, d in that order If you can call the methods in lots of different ways: # you can call a, b, c, d; # or a, b, d; # or a, d, e, f # or g, d, e # ... it becomes horrible. In that case, I'd say just document what the methods do and let the user deal with the mess. > 1) Most importantly, am I being stupid? I.e. is there some obviously > better way to handle this sort of thing? I wouldn't say "stupid" as such, but since you used the word, yes :-) > 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.? If you want the user to call methods a, b, c, d in that order, provide then with a single method "run" that calls a, b, c, d in that order, and tell them to call "run". -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list