How to avoid explicit 'self' in Python?
Asked Answered
C

11

161

I have been learning Python by following some pygame tutorials.

Therein I found extensive use of the keyword self, and coming from a primarily Java background, I find that I keep forgetting to type self. For example, instead of self.rect.centerx I would type rect.centerx, because, to me, rect is already a member variable of the class.

The Java parallel I can think of for this situation is having to prefix all references to member variables with this.

Am I stuck prefixing all member variables with self, or is there a way to declare them that would allow me to avoid having to do so?

Even if what I am suggesting isn't pythonic, I'd still like to know if it is possible.

I have taken a look at these related SO questions, but they don't quite answer what I am after:

Counterpressure answered 31/12, 2009 at 5:50 Comment(10)
I come from a Java background and find it natural, but I explicitly add "this" to every call to make it clearer that I am referring to an instance variable.Myrnamyrobalan
Are you familiar with the convention of an m_ prefix for all member names observed by some C++/Java programmers? The use of self. helps readability in a similar way. Also, you should read dirtsimple.org/2004/12/python-is-not-java.html.Acciaccatura
Though usually m_ is used for non-public non-static data members only (at least in C++).Ninon
@Beni great linked article, and yes indeed, I actually do follow the convention of using mVariableName, for member variables, when coding in Java. I think @Anurag's comment sums it up pretty well, for what a java dev should do when learning python.Counterpressure
You might want to take a look at #910520Revell
So, how come everyone is telling OP why using self is good/necessary/etc. but nobody says whether or not it can be avoided somehow? Even if by some kind of dirty trick?Erect
Also, @Anurag: How can this ever be self-accepted? :-\Erect
@Myrnamyrobalan but as programmers, aren't we expected to be unreasonably lazy? My text editor can add all that self.x text laaaaaaater :PChan
FWIW, you can use Decorators. #1389680Tarver
Perl is the same way -- we pass explicit "self" around, which is why in a Perl class method you might see something like "my $self = shift" or "my ($self, $another_arg, $some_other_arg) = @_"Weakfish
N
116

In Java terms: Python doesn't have member functions, all class functions are static, and are called with a reference to the actual class instance as first argument when invoked as member function.

This means that when your code has a class MyClass and you build an instance m = MyClass(), calling m.do_something() will be executed as MyClass.do_something(m).

Also note that this first argument can technically be called anything you want, but the convention is to use self, and you should stick to that convention if you want others (including your future self) to be able to easily read your code.

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):
  pass

print B()
# <__main__.B object at 0xb7e4082c>

def B_init(self):
  self.answer = 42
def 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_init
B.__str__ = B_str

print 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.

Ninon answered 31/12, 2009 at 5:57 Comment(9)
Thank you. This answer hits the spot cos it also explains the benefits of using self.Counterpressure
@Roger Pate: Please stop editing my question to remove python from it. I think that it belongs there. (and thanks for the answer!)Counterpressure
@bguiz: It's SO convention to not duplicate the tags in the title. However, when I edited 2 days ago, I did not see you reverted the title 7 months ago.Ninon
It would be nice if self could be reduced to a single character.Tekla
That's actually a rather silly-sounding reason. Python could fail to accept shadowing, and require you to declare it specifically, i.e. 'bless' your shadowing field with some kind of __shadow__ myFieldName. That would prevent accidental shadowing as well, wouldn't it?Erect
@Tekla Ok, I am years late to the party, but I have just started learning Python (my background is C++), and I hate typing 'self'. However I do like explicitly distinguishing locals from instance data. Would a Syntax extension making '.' == 'self.' be feasible to allow code like:Equiponderate
class Vec2d: def __init__(x,y): .x = x .y = y .lenSq = .lengthSqSq(x,y) def lengthSq(x,y): return xx + yyEquiponderate
This does not answer the question "How to avoid explicit 'self' in Python?"Tarver
It's still possible to let the interpreter figure out the context of these functions. If an instance of an object has been defined a function member, then bind that instance to that function. And make self a keyword. I think the only reason to force people to explicitly differentiate a method from a function.Acrobatic
V
75

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 np
class 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.

Virtues answered 15/3, 2018 at 18:55 Comment(7)
Brilliant! This is the most (only?) correct answer. +1 You also uniquely give a practical reason for doing it. +1iLivvy
After creating a class and moving the code inside of it : now all of the methods and variables are no longer recognized (no self. ..) I am reminded of yet another reason python and I do not get along. Thanks for this as an idea. It does not fix the problem /headache / unreadability overall but provides a modest workaround.Talon
Why not just update locals instead of using exec?Loser
I tried locals().update(self.__dict__) in python 2 and 3, but it didn't work. In python3 even the 'exec' trick isn't an option anymore. On the other hand, globals().update(self.__dict__) does work, but would be a terrible practice in general.Virtues
@Talon I couldn't agree more. I believe in the principles outlined in "Clean Code" by Uncle Bob. And having "self." EVERYWHERE in my code DOES NOT make it any more readable or simple.Coping
@Virtues You're being civil / polite to this python[3] language in your answer. Actually python really screwed this all up. Thanks for the various workaroundsTalon
Well replacing 'self' with just 's' is best way for me now. When I look at the code with 'self' in it, I only see the word 'self' xDStellular
P
37

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.

Polad answered 31/12, 2009 at 5:56 Comment(1)
This answer, especially the 2nd sentence, is far much more useful than the accepted answer for me because I can know 'explicit self' is just one of the limitations in Python and not avoidableInterdict
A
24

You can use whatever name you want, for example

class test(object):
    def function(this, variable):
        this.variable = variable

or even

class test(object):
    def function(s, variable):
        s.variable = variable

but you are stuck with using a name for the scope.

I do not recommend you use something different to self unless you have a convincing reason, as it would make it alien for experienced pythonistas.

Agonizing answered 31/12, 2009 at 6:18 Comment(6)
You can do this, but don't! There is no reason to make your code weirder than it needs to be. Yes you can call it anything, but the convention is to call it self, and you should follow the convention. It will make your code easier to understand for any experienced Python programmer who looks at it. (This includes you, six months from now, trying to figure out what your old program does!)Ofori
Even more alien: def function(_, variable): _.variable = variableHellhole
@BobStein-VisiBone even more alien: def funcion(*args): args[0].variable = args[1]Celtic
@Ofori he is not recommending it, this information is very helpfull for people like me who did not know you can use different keywords than self and wonder why an object of the own class is passed.Narton
> "weirder". Python is weird - especially its classes structures and this use of self is a canary for supporting anti readability. I know will get many defenders coming after this but that does not change the veracity.Talon
I started using just letter 's', code looks a bit cleaner.Stellular
Q
9

yes, you must always specify self, because explicit is better than implicit, according to python philosophy.

You will also find out that the way you program in python is very different from the way you program in java, hence the use of self tends to decrease because you don't project everything inside the object. Rather, you make larger use of module-level function, which can be better tested.

by the way. I hated it at first, now I hate the opposite. same for indented-driven flow control.

Quita answered 31/12, 2009 at 5:54 Comment(5)
"You make larger use of module-level function, which can be better tested" is dubious, and I'd have to strongly disagree. It is true you're not forced to make everything a method (static or not) of some class, regardless of whether it's "logically module-level", but that has nothing to do with self and doesn't have any significant impact on testing one way or the other (for me).Ninon
It arises from my experience. I don't follow it as a mantra every time, but it makes things easier to test if you put anything that does not require member variable access as a separate, independent method. yes, you separate logic from data, which yes, is against OOP, but they are together, just at the module level. I don't give one or the other the "best" mark, it's just a matter of taste. Sometimes I find myself specifying class methods that have nothing to do with the class itself, as they don't touch self in any way. So what's the point in having them on the class ?Quita
I disagree with both parts of it (it seems I use "non-methods" no more often than in other languages), but "which can be better tested" does imply that one way is superior to the other (is that just how I read it? doesn't seem likely), while I don't find support for that in my experience. Note that I'm not saying you should always use one or the other, I'm only saying methods and non-methods are equally able to be tested.Ninon
yes, of course you can, but the approach is different. An object has a state, a module level method has not. If you find out a test fails while testing a class-level method, two things could have been wrong: 1) the object state at the time of the call 2) the method itself. If you have a stateless module-level method, only case 2 can happen. You moved the setup from the object (where it is black box as the test is concerned, since it's governed by the eventually complex logic inside the object) to the testsuite. You are reducing complexity and keeping tighter control of setup.Quita
"If you have a stateless module-level method", what about a stateful module-level method? All you're telling me is that stateless functions are easier to test than stateful ones, and I'll agree with that, but it has nothing to do with methods vs non-methods. View the self parameter as exactly that: just another parameter to the function.Ninon
F
4

The "self" is the conventional placeholder of the current object instance of a class. Its used when you want to refer to the object's property or field or method inside a class as if you're referring to "itself". But to make it shorter someone in the Python programming realm started to use "self" , other realms use "this" but they make it as a keyword which cannot be replaced. I rather used "its" to increase the code readability. Its one of the good things in Python - you have a freedom to choose your own placeholder for the object's instance other than "self". Example for self:

class UserAccount():    
    def __init__(self, user_type, username, password):
        self.user_type = user_type
        self.username = username            
        self.password = encrypt(password)        

    def get_password(self):
        return decrypt(self.password)

    def set_password(self, password):
        self.password = encrypt(password)

Now we replace 'self' with 'its':

class UserAccount():    
    def __init__(its, user_type, username, password):
        its.user_type = user_type
        its.username = username            
        its.password = encrypt(password)        

    def get_password(its):
        return decrypt(its.password)

    def set_password(its, password):
        its.password = encrypt(password)

which is more readable now?

Fortuitous answered 18/12, 2012 at 19:47 Comment(4)
why not just s (or some other single letter) instead of itsTalon
' its' has a meaning and 's' does not.Fortuitous
s has the same meaning: an alias to the class instance. i'd have to look up what its means in the context just the sameTalon
Both are not readable to me. It is still illogical to get "yourself" as an external parameter, it doesn't make any sense.Akerley
C
4

From: Self Hell - More stateful functions.

...a hybrid approach works best. All of your class methods that actually do computation should be moved into closures, and extensions to clean up syntax should be kept in classes. Stuff the closures into classes, treating the class much like a namespace. The closures are essentially static functions, and so do not require selfs*, even in the class...

Collaborative answered 12/11, 2015 at 11:22 Comment(2)
Closures are fine for small use cases, but extended use of them will increase the memory overhead of a program quite heavily (as you're using prototype-based OO rather than class-based OO -- so each object requires its own set of functions rather keeping a common set of functions in a class). Further, it will stop you being able to magic/dunder methods (eg __str__ and the like) since these are invoked in a different way to normal methods.Hanse
This answers the question well.Tarver
D
1

self is part of the python syntax to access members of objects, so I'm afraid you're stuck with it

Diplosis answered 31/12, 2009 at 5:53 Comment(2)
self is a way to tell the access modifier without really using one. +1Underquote
This is for whoever reads this. self is not part of the python syntax. It's just a variable name. You can use any name you want. Also, python methods when called, are always implicitly passed with at least one argument in the first spot. That argument is the instance. That's why it gives you an error if you forget to define a parameter.Acrobatic
U
1

Actually you can use recipe "Implicit self" from Armin Ronacher presentation "5 years of bad ideas" ( google it).

It's a very clever recipe, as almost everything from Armin Ronacher, but I don't think this idea is very appealing. I think I'd prefer explicit this in C#/Java.

Update. Link to "bad idea recipe": https://speakerdeck.com/mitsuhiko/5-years-of-bad-ideas?slide=58

Uneducated answered 29/11, 2015 at 22:16 Comment(3)
Is this the link you are referring to what you were referring to? If so pls include in your answerMartian
No, Armin "bad idea" looks more funny for my taste. I included link.Uneducated
Before you click the recipe link, note that this makes it implicit in the def method(<del>self</del>) parameter list, but self.variable is still required with this clever hack.Livvy
D
1

Here I follow the idea from the answer by @argentum2f to copy the attributes. This can be automated by a decorator and it works with Python 3. Of course copying the attributes means that they cannot be changed, hence the name @const_self for the decorator.

With @const_self you define a method with first arguments that have the same names as the attributes you want to use — and no self.

from cmath import sqrt

def const_self(fun):
    fun_args = fun.__code__.co_varnames[:fun.__code__.co_argcount]

    def fun_with_self(*args, **kwargs):
        self = args[0]
        other_args = list(args[1:])

        used_attributes = [arg for arg in fun_args if hasattr(self, arg)]
        self_args = [getattr(self, attr) for attr in used_attributes]

        return fun(*(self_args + other_args), **kwargs)

    return fun_with_self

class QuadraticEquation:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    @const_self
    def roots(a, b, c, dummy, lazy = False):
        print("Dummy is", dummy)
        if lazy: return # A lazy calculator does not calculate
        return (-b - sqrt(b**2 - 4*a*c)) /2/a, (-b + sqrt(b**2 - 4*a*c)) /2/a

Of course a lot should be improved in that code: At least it fails if you define a method like def fun(a, dummy, b, c): print(a,b,c) here and it does not preserve the docstring. But I think it demonstrates the idea well enough.

Dichroism answered 3/9, 2022 at 18:58 Comment(0)
J
0

Yeah, self is tedious. But, is it better?

class Test:

    def __init__(_):
        _.test = 'test'

    def run(_):
        print _.test
Jemmie answered 25/4, 2013 at 2:48 Comment(2)
_ has special meaning in the Python shell, where it holds the last returned value. It's safe to use it like this, but potentially confusing; I'd avoid it.Remuneration
No that's not better but why not a single letter instead e.g. s or m (to mimic C++ )Talon

© 2022 - 2024 — McMap. All rights reserved.