Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
is 'self' optional ?
#1
I'm coming from a language that doesn't use the keywords 'self'. This 'self' example found on the net doesn't explain to me why self is necessary. In fact when I removed the 'self' the code still worked.

class Restaurant(object):
   bankrupt = False
   def open_branch(self):
       if not self.bankrupt:
           print("branch opened")

x=Restaurant()
x.bankrupt= True
print x.bankrupt
class Restaurant(object):
    bankrupt = False
    def open_branch():
        if not bankrupt:
            print("branch opened")

x=Restaurant()
x.bankrupt= True
print x.bankrupt
Code still works with self removed.

I've seen other examples where functions that are defined to take a 'self' argument, don't actually require then when called.
e.g.

class BankAccount(object):
   def __init__(self, initial_balance=0):
       self.balance = initial_balance
   def deposit(self, amount):
       self.balance += amount
   def withdraw(self, amount):
       self.balance -= amount
   def overdrawn(self):
       return self.balance < 0

my_account = BankAccount(15)
my_account.withdraw(5)
print my_account.balance
calling the withdraw function doesn't require any variable to fill in the 'self' parameter.

So....
Is 'self' redundant? What is the simplest code you know of where self is essential, without which the code won't work?
Reply
#2
Quote:
   def open_branch(self):
self identifies this as an instance method, whereas without it would be a class method. 

Quote:Code still works with self removed.
you never actually called the open_branch method if you did via the isntance it would give you the error
Error:
Traceback (most recent call last):   File "test1.py", line 9, in <module>     x.open_branch() TypeError: open_branch() takes no arguments (1 given)
same with the withdra method, if you removed self, you would get 
Error:
Traceback (most recent call last):   File "test1.py", line 12, in <module>     my_account.withdraw(5) TypeError: withdraw() takes exactly 1 argument (2 given)
my_account instance is calling a method it expects to take the first parameter as itself

http://neopythonic.blogspot.com/2008/10/...-stay.html
Guido van Rossum Wrote:Bruce Eckel has blogged about a proposal to remove 'self' from the formal parameter list of methods. I'm going to explain why this proposal can't fly.

Bruce's Proposal

Bruce understands that we still need a way to distinguish references to instance variables from references to other variables, so he proposes to make 'self' a keyword instead. Consider a typical class with one method, for example:

class C:
  def meth(self, arg):
     self.val = arg
     return self.val
Under Bruce's proposal this would become:

class C:
  def meth(arg):  # Look ma, no self!
     self.val = arg
     return self.val
That's a saving of 6 characters per method. However, I don't believe Bruce proposes this so that he has to type less. I think he's more concerned about the time wasted by programmers (presumably coming from other languages) where the 'self' parameter doesn't need to be specified, and who occasionally forget it (even though they know better -- habit is a powerful force). It's true that omitting 'self' from the parameter list tends to lead to more obscure error messages than forgetting to type 'self.' in front of an instance variable or method reference. Perhaps even worse (as Bruce mentions) is the error message you get when the method is declared correctly but the call has the wrong number of arguments, like in this example given by Bruce:

Error:
Traceback (most recent call last): File "classes.py", line 9, in   obj.m2(1) TypeError: m2() takes exactly 3 arguments (2 given)
I agree that this is confusing, but I would rather fix this error message without changing the language.

Why Bruce's Proposal Can't Work

Let me first bring up a few typical arguments that are brought in against Bruce's proposal.

There's a pretty good argument to make that requiring explicit 'self' in the parameter list reinforces the theoretical equivalency between these two ways of calling a method, given that 'foo' is an instance of 'C':
foo.meth(arg) == C.meth(foo, arg)
Another argument for keeping explicit 'self' in the parameter list is the ability to dynamically modify a class by poking a function into it, which creates a corresponding method. For example, we could create a class that is completely equivalent to 'C' above as follows:
# Define an empty class:

class C:
  pass
# Define a global function:

def meth(myself, arg):
  myself.val = arg
  return myself.val
# Poke the method into the class:
C.meth = meth
Note that I renamed the 'self' parameter to 'myself' to emphasize that (syntactically) we're not defining a method here. Now instances of C have a method with one argument named 'meth' that works exactly as before. It even works for instances of C that were created before the method was poked into the class.

I suppose that Bruce doesn't particularly care about the former equivalency. I agree that it's more of theoretical importance. The only exception I can think of is the old idiom for calling a super method. However, this idiom is pretty error-prone (exactly due to the requirement to explicitly pass 'self'), and that's why in Python 3000 I'm recommending the use of 'super()' in all cases.

Bruce can probably think of a way to make the second equivalency work -- there are some use cases where this is really important. I don't know how much time Bruce spent thinking about how to implement his proposal, but I suppose he is thinking along the lines of automatically adding an extra formal parameter named 'self' to all methods defined directly inside a class (I have to add 'directly' so that functions nested inside methods are exempted from this automatism). This way the first equivalency can be made to hold still.

However, there's one situation that I don't think Bruce can fix without adding some kind of ESP to the compiler: decorators. This I believe is the ultimate downfall of Bruce's proposal.

When a method definition is decorated, we don't know whether to automatically give it a 'self' parameter or not: the decorator could turn the function into a static method (which has no 'self'), or a class method (which has a funny kind of self that refers to a class instead of an instance), or it could do something completely different (it's trivial to write a decorator that implements '@classmethod' or '@staticmethod' in pure Python). There's no way without knowing what the decorator does whether to endow the method being defined with an implicit 'self' argument or not.

I reject hacks like special-casing '@classmethod' and '@staticmethod'. I also don't think it would be a good idea to automagically decide whether something is supposed to be a class method, instance method, or static method from inspection of the body alone (as someone proposed in the comments on Bruce's proposal): this makes it harder to tell how it should be called from the 'def' heading alone.

In the comments I saw some pretty extreme proposals to save Bruce's proposal, but generally at the cost of making the rules harder to follow, or requiring deeper changes elsewhere to the language -- making it infinitely harder to accept the proposal as something we could do in Python 3.1. For 3.1, by the way, the rule will be once again that new features are only acceptable if they remain backwards compatible.

The one proposal that has something going for it (and which can trivially be made backwards compatible) is to simply accept
def self.foo(arg): ...
inside a class as syntactic sugar for
def foo(self, arg): ...
I see no reason with this proposal to make 'self' a reserved word or to require that the prefix name be exactly 'self'. It would be easy enough to allow this for class methods as well:

@classmethod

def cls.foo(arg): ...
Now, I'm not saying that I like this better than the status quo. But I like it a lot better than Bruce's proposal or the more extreme proposals brought up in the comments to his blog, and it has the great advantage that it is backward compatible, and can be evolved into a PEP with a reference implementation without too much effort. (I think Bruce would have found out the flaws in his own proposal if he had actually gone through the effort of writing a solid PEP for it or trying to implement it.)

I could go on more, but it's a nice sunny Sunday morning, and I have other plans... :-)

Posted by Guido van Rossum
Recommended Tutorials:
Reply
#3
(Nov-25-2016, 08:33 PM)meems Wrote: I'm coming from a language that doesn't use the keywords 'self'. This 'self' example found on the net doesn't explain to me why self is necessary. In fact when I removed the 'self' the code still worked.

class Restaurant(object):
   bankrupt = False
   def open_branch(self):
       if not self.bankrupt:
           print("branch opened")

x=Restaurant()
x.bankrupt= True
print x.bankrupt
class Restaurant(object):
    bankrupt = False
    def open_branch():
        if not bankrupt:
            print("branch opened")

x=Restaurant()
x.bankrupt= True
print x.bankrupt
Code still works with self removed.

I've seen other examples where functions that are defined to take a 'self' argument, don't actually require then when called.
e.g.

class BankAccount(object):
   def __init__(self, initial_balance=0):
       self.balance = initial_balance
   def deposit(self, amount):
       self.balance += amount
   def withdraw(self, amount):
       self.balance -= amount
   def overdrawn(self):
       return self.balance < 0

my_account = BankAccount(15)
my_account.withdraw(5)
print my_account.balance
calling the withdraw function doesn't require any variable to fill in the 'self' parameter.

So....
Is 'self' redundant? What is the simplest code you know of where self is essential, without which the code won't work?

You code works because as you use it "bankrupt" is actually a class variable in Python. You code won't work with two distinct instances of Restaurant. You should use self.bankrupt=false to create an instance variable/attribute.
Unless noted otherwise, code in my posts should be understood as "coding suggestions", and its use may require more neurones than the two necessary for Ctrl-C/Ctrl-V.
Your one-stop place for all your GIMP needs: gimp-forum.net
Reply
#4
thanks I see now it was obvious I needed to call the class method to test whether the code worked without self.

2 things remainth :
a.) My point that when a function is called, self is not put in the parameter list, but it does appear in the function definition. This is dumb, and will take some getting used to.

e.g.
def deposit(self,amount) # 2 parameters when defined
but then when called...
my_account.deposit(10) # 1 parameter when called
b.) Still don't get why self is needed. Seems its a pretty deep routed reason to do with 'decorators', which is a concept i don't know of and have never used. If anyone knows of the simplest example of code or pseudo code that a complier would not be able to understand due to lack of 'self' I'd be interested to see it.

The wiki entry on 'this' says that lexical scoping can be used to fix problems that arise in with not having 'this'.
Lexical scoping is something I understand and use. However I don't see how it solves the problem of not having a 'this' because I don't see there's a problem to start with :/
https://en.wikipedia.org/wiki/This_(comp...ogramming)

Let me put it yet another way :

To my mind, 'self' is implicitly called in the variable name

my_account.deposit(10) # 'my_account' is 'self' !
that 'self' doesn't need to be in the parameters is a symptom of self being redundant, but seems the python dev team don't want to accept this !
Reply
#5
Quote:that 'self' doesn't need to be in the parameters is a symptom of self being redundant, but seems the python dev team don't want to accept this !


explicit is better Wink
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>> 
Quote:a.) My point that when a function is called, self is not put in the parameter list, but it does appear in the function definition. This is dumb, and will take some getting used to.
I must of just used python for so long i dont even think about it. I (personally) consider self in the class definition to be the switch, to say i want this to be an instance method. Its an easy identifier for methods in a class to determine which is a class/instance method. And when calling it from an instance, not needed it because it is obviously an the instance method. 


If you think its redundant to put self in the parameters, then it would be even more redundant to put self in the call.
Recommended Tutorials:
Reply
#6
It doesn't HAVE to be self...
class Spam(object):
 def eggs(this):
   this.is_not_self = True
:p
Reply
#7
(Dec-06-2016, 08:11 PM)nilamo Wrote: It doesn't HAVE to be self...
class Spam(object):  
    def eggs(this):    
        this.is_not_self = True 
:p

As true as that is, i believe the OP is concerned more about the fact of anything in the parameters referring to the object, rather than what it is defined as.
Recommended Tutorials:
Reply
#8
I don't understand why the OP would want that. I consider it to be a design flaw that other languages inject magic variables into places.
...but I also think from spam import * should be a syntax error, so maybe I'm weird.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Trouble making an argument optional linuxnoob 2 2,865 Aug-31-2018, 01:52 AM
Last Post: linuxnoob

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020