How to avoid explicit 'self' in Python? How to avoid explicit 'self' in Python? python python

How to avoid explicit 'self' in Python?


Python requires specifying self. The result is there's never any confusion over what's a member and what's not, even without the full class definition visible. This leads to useful properties, such as: you can't add members which accidentally shadow non-members and thereby break code.

One extreme example: you can write a class without any knowledge of what base classes it might have, and always know whether you are accessing a member or not:

class A(some_function()):  def f(self):    self.member = 42    self.method()

That's the complete code! (some_function returns the type used as a base.)

Another, where the methods of a class are dynamically composed:

class B(object):  passprint B()# <__main__.B object at 0xb7e4082c>def B_init(self):  self.answer = 42def B_str(self):  return "<The answer is %s.>" % self.answer# notice these functions require no knowledge of the actual class# how hard are they to read and realize that "members" are used?B.__init__ = B_initB.__str__ = B_strprint B()# <The answer is 42.>

Remember, both of these examples are extreme and you won't see them every day, nor am I suggesting you should often write code like this, but they do clearly show aspects of self being explicitly required.


Previous answers are all basically variants of "you can't" or "you shouldn't". While I agree with the latter sentiment, the question is technically still unanswered.

Furthermore, there are legitimate reasons why someone might want to do something along the lines of what the actual question is asking. One thing I run into sometimes is lengthy math equations where using long names makes the equation unrecognizable. Here are a couple ways of how you could do this in a canned example:

import numpy as npclass MyFunkyGaussian() :    def __init__(self, A, x0, w, s, y0) :        self.A = float(A)        self.x0 = x0        self.w = w        self.y0 = y0        self.s = s    # The correct way, but subjectively less readable to some (like me)     def calc1(self, x) :        return (self.A/(self.w*np.sqrt(np.pi))/(1+self.s*self.w**2/2)                * np.exp( -(x-self.x0)**2/self.w**2)                * (1+self.s*(x-self.x0)**2) + self.y0 )    # The correct way if you really don't want to use 'self' in the calculations    def calc2(self, x) :        # Explicity copy variables        A, x0, w, y0, s = self.A, self.x0, self.w, self.y0, self.s        sqrt, exp, pi = np.sqrt, np.exp, np.pi        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)                * exp( -(x-x0)**2/w**2 )                * (1+s*(x-x0)**2) + y0 )    # Probably a bad idea...    def calc3(self, x) :        # Automatically copy every class vairable        for k in self.__dict__ : exec(k+'= self.'+k)        sqrt, exp, pi = np.sqrt, np.exp, np.pi        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)                * exp( -(x-x0)**2/w**2 )                * (1+s*(x-x0)**2) + y0 )g = MyFunkyGaussian(2.0, 1.5, 3.0, 5.0, 0.0)print(g.calc1(0.5))print(g.calc2(0.5))print(g.calc3(0.5))

The third example - i.e. using for k in self.__dict__ : exec(k+'= self.'+k) is basically what the question is actually asking for, but let me be clear that I don't think it is generally a good idea.

For more info, and ways to iterate through class variables, or even functions, see answers and discussion to this question. For a discussion of other ways to dynamically name variables, and why this is usually not a good idea see this blog post.

UPDATE: There appears to be no way to dynamically update or change locals in a function in Python3, so calc3 and similar variants are no longer possible. The only python3 compatible solution I can think of now is to use globals:

def calc4(self, x) :        # Automatically copy every class variable in globals        globals().update(self.__dict__)        sqrt, exp, pi = np.sqrt, np.exp, np.pi        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)                * exp( -(x-x0)**2/w**2 )                * (1+s*(x-x0)**2) + y0 )

Which, again, would be a terrible practice in general.


Actually self is not a keyword, it's just the name conventionally given to the first parameter of instance methods in Python. And that first parameter can't be skipped, as it's the only mechanism a method has of knowing which instance of your class it's being called on.