-1

I'm using python to do some research tasks. I have a class hierarchy for "tools", where each object is an instance of a particular tool. They all share some functionality and have many similarities in their states.

Some of these tools can use one of several methods based on the tool object's current state. The specific tool I'm going to ask about actually calls functions from external modules instead of methods written in the class directly. The underlying reason for this is to break up the code into multiple files, i.e. not have any huge monster file that has all the various methods and helper functions those methods use, when all it needs at any given time is a particular very-targeted subset. I.e. when the mode of the tool is "clean_house", I would only functions like "wash_windows", "vacuum_carpet", and "ask_girlfriend_for_help", while when the mode is "do_work", I use functions like "write_code", "debug_code", and "ask_SO_question". The subsets don't intersect in any way, i.e. "write_code" would never call "ask_girlfriend_for_help", etc.

Instead of calling these functions from module scope within the class methods, it seems to me that it's a better idea to monkeypatch them to the tool's class, since there are instance methods they need to call that go further up the class hierarchy and modify some (protected) part object's state that is used later in the destructor.

I know monkeypatching is often considered poor design or last-resort practice when hot-fixes are in order (Programmer's SE post here), but is it justified in this case? Any alternative code design suggestions?

Greg Kramida
  • 282
  • 2
  • 12
  • 1
    Monkeypatching is the act of using Python's dynamic nature to change third-party code. What you are doing is using that same dynamic nature to build your class. That is not the same thing, per se. – Martijn Pieters Aug 09 '13 at 12:58
  • That makes sense. But is writing an "extension method" like this in a different module (for lack of a better way to describe it) a good idea at all? – Greg Kramida Aug 09 '13 at 13:06

1 Answers1

1

You are not really monkey patching. Monkey patching is the act of using Python's dynamic nature to change third-party code. What you are doing is using that same dynamic nature to build your class. That is not the same thing, per se.

It sounds like you are delegating functionality to other modules. That sounds like a perfectly fine practice. But I don't quite see why you'd need to alter your tool to do so; your tool can pass on method calls to an underlying object that is responsible for the actual implementation, based on the current state.

Those responsible objects can still modify the state of the tool, as nothing in Python is private, really.

Martijn Pieters
  • 14,499
  • 10
  • 57
  • 58
  • I understand the idea, I think it's good in many ways. However, I don't think you are entirely correct when you say "nothing in Python is private." Python does make provisions for encapsulation: "private" and "protected" are there (The destructor being the former). Besides, if I have code written in class A that holds class B as a field and uses it, instance of B would need a reference to its encapsulating instance of A, and even then it would be only able to call its public methods and access its public variables. – Greg Kramida Aug 09 '13 at 13:18
  • `__del__` is not a destructor, nor is it private. The `__` convention only applies to names that *start* with the double underscore, and that mechanism is intended to provide instance attributes with a namespace (subclasses using the same `__name` attributes or methods do not override the parent), not privacy. You can still access those attributes. Using `_` for 'private' attributes is merely a convention. – Martijn Pieters Aug 09 '13 at 13:20
  • You are right that `B` would need a reference to `A`, but it can reach in and access anything `A` can, short of local variables in functions. – Martijn Pieters Aug 09 '13 at 13:21
  • What you're saying is certainly correct where it's dealing with fact. I think the misunderstanding hinges on the word "private" here, and it all depends on how you define it. The python documentation uses the word "private" to describe the things python achieves with name-mangling. Even if it doesn't fully prevent accessing those methods, it is clear they are not intended to be accessed from outside. Storing something in A_instance._A__private_state I think is a little more hacky and counter-intuitive then the "extension methods." – Greg Kramida Aug 09 '13 at 13:30
  • Then don't use double-underscore names for such state, or provide methods for `B` to access and influence the state of `A`. It is still *your* choice as to what the internal interactions are. – Martijn Pieters Aug 09 '13 at 13:31
  • I am aware the documentation is using the term 'private' there; however, it has not the same meaning as 'private' in the context of Java or C++. – Martijn Pieters Aug 09 '13 at 13:33
  • This is true, it is context-specific. An aside: `__del__`, to quote the python documentation, "is also called a destructor". Different languages use same terms for similar, yet different things. – Greg Kramida Aug 09 '13 at 13:35
  • Yeah, I am perhaps being a bit too pedantic on that particular issue; it is a clean-up hook, and one that is not usually needed, really. – Martijn Pieters Aug 09 '13 at 13:37
  • After some tinkering with the code, I ended up using the design you suggested. It turns out that every set of operations can also benefit from sharing some state, i.e. instance of CleaningLady is bound to need a private variable called "vacuum," so ,naturally, using objects is a better solution. – Greg Kramida Aug 09 '13 at 18:16