Overriding internal method function in python
This is kind of a best practice question.
I have a class structure with certain methods. In some cases, I want to override a specific part of the method. At first I thought it was splitting my method into more atomic elements and redefining related parts like below.
class myTest(object):
def __init__(self):
pass
def myfunc(self):
self._do_atomic_job()
...
...
def _do_atomic_job(self):
print "Hello"
This is a practical way to solve the problem. But since I have too many parameters to pass and return from _do_atomic_job()
, I don't want to pass and retrieve many parameters. Another parameter sets these parameters as class variables with self.param_var
etc., but these parameters are used in a small piece of code and using is self
not my preferred way of solving this question.
The last option I thought uses internal functions. (I know I'm going to have problems with variable scopes, but as I said, this is best practice and they just ignore them and think that scope and all things about internal functions work as expected).
class MyTest2(object):
mytext = ""
def myfunc(self):
def _do_atomic_job():
mytext = "Hello"
_do_atomic_job()
print mytext
Let's assume it works as expected. What I want to do is override the inner function_do_atomic_job()
class MyTest3(MyTest2):
def __init__(self):
super(MyTest3, self).__init__()
self.myfunc._do_atomic_job = self._alt_do_atomic_job # Of course this do not work!
def _alt_do_atomic_job(self):
mytext = "Hollla!"
Doing what I want to achieve is to override the internal function of the inherited class method _do_atomic_job
Is it possible?
source to share
Either factoring it _do_atomic_job()
into the correct method, or perhaps factoring it into your class seems to be the best approach. Overriding an internal function cannot work because you will not have access to the local variable containing the method.
You say you _do_atomic_job()
take many parameters, return many values. Perhaps you are grouping some of these parameters into sane objects:
_do_atomic_job(start_x, start_y, end_x, end_y) # Separate coordinates
_do_atomic_job(start, end) # Better: start/end points
_do_atomic_job(rect) # Even better: rectangle
If you cannot do this and _do_atomic_job()
is self-contained enough, you can create helper classes AtomicJobParams
and AtomicJobResult
. Example using namedtuples
instead of classes:
AtomicJobParams = namedtuple('AtomicJobParams', ['a', 'b', 'c', 'd'])
jobparams = AtomicJobParams(a, b, c, d)
_do_atomic_job(jobparams) # Returns AtomicJobResult
Finally, if the atomic assignment is self-contained, you might even put your own class at risk AtomicJob
.
class AtomicJob:
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
self._do_atomic_job()
def _do_atomic_job(self):
...
self.result_1 = 42
self.result_2 = 23
self.result_3 = 443
Overall, it looks more like a code factorization problem. Aim for classes that delegate work to helpers where needed. Follow the principle of single responsibility . If the values ββbelong together, combine them into a value class.
As David Miller (a renowned Linux kernel developer) recently said :
If you write interfaces with more than 4 or 5 function arguments, it is possible that you and I may not be friends.
source to share
Internal variables are related to where they are defined, not where they run. This prints "hello".
class MyTest2(object):
def __init__(self):
localvariable = "hello"
def do_atomic_job():
print localvariable
self.do_atomic_job = do_atomic_job
def myfunc(self):
localvariable = "hollla!"
self.do_atomic_job()
MyTest2().myfunc()
So I see no way to use local variables without passing them in, which is probably the best way to do it.
Note. Passing locals()
will bring you a variable of variables, however this is considered pretty bad.
source to share