I'm trying to rewrite some code using classes. At some point what I want is assign a member function a particular definition using a parameter value for each instance of an object.
Coming from other languages (JavaScript, C++, Haskell, Fortran, ...) I am struggling to understand a few things on Python. One thing is the following distinction of self in class methods.
For instance, the following code obviously won't work:
class fdf:
def f(x):
return 666
class gdg(fdf):
def sq():
return 7*7
hg = gdg()
hf = fdf()
print(hf.f(),hg.f(),hg.sq())
which gives the error that "sq() takes 0 positional arguments but 1 was given".
The reason, as I understand it, is that at execution time the function is passed a reference to the calling object (the instance calling sq) as first argument before any other parameter/argument we may have defined/called sq with. So the solution is simple: change the code of sq to def sq(self):
. Indeed, the Python tutorial 1 seems to suggest that object methods should always be defined with self
as first parameter. Doing so we get as expected 666 666 49
. So far so good.
However, when I try to implement my class like this:
class Activation:
def nonLinearBipolarStep(self,x,string=None):
if not string: return (-1 if x<0 else 1 )
else: return ('-' if x<0 else '1')
default='bipolar'
activationFunctions = {
'bipolar': nonLinearBipolarStep ,
}
def _getActivation(self,func=default):
return self.activationFunctions.get(func,self.activationFunctions.get(self.default))
def __init__(self,func=None):
if func == None: func=self.default
self.run = self._getActivation(func)
ag = Activation()
print(ag.run(4))
I get the error
nonLinearBipolarStep() missing 1 required positional argument: 'x'
Yet, a workaround ( solution??) is defining the the step function without the parameter self
(!) as
def nonLinearBipolarStep(x,string=None):
Then I get the expected behavior (at least for this trivial test) of 1
. So, not only is self
not needed here, but it even is incorrect an use here!
But according to the tutorial mentioned above, or to the answers in threads like this 2 or this 3, it seems to me this code shouldn't work...or should have some unexpected consequences at some point(?). Indeed, if I remove all references to self
in the definition of _getActivation
I get the error message _getActivation() takes from 0 to 1 positional arguments but 2 were given
which I can understand according to that rule.
The thread "Why is self not used in this method" 4 does not provide a clear answer to me: What syntax detail of the code above tells me that self
is not needed? For instance, how is that code different from this tutorial example
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
? Instantiating this class works as expected, but it complains about missing parameter (I know it could be any label) if defined with none.
This makes me question whether my code is not hiding a time bomb somehow: is self
passed as the value for x
? It works as expected so I'd say no, but then I'm facing this conundrum.
I guess I'm missing some key ideas of the language. I admit I also struggle with the question the OP of reference 3 is asking^.
[^]: In JS one just uses this
in the function body, and the function itself is defined either as member of the object's prototype or as an instance member which then gets assigned correctly using...this
.
EDIT:
The thread is long. For those browsing for some help, if you are new to Python, then you may want to check the selected solution and its comments. However, if you already know about bound/unbound methods in Python, you just want to check directly the use of descriptor as described in Blckknght's answer. I finally opted for this way in my code using __get__
in the assignment to run.