Is it reasonable to let __init__ member must take self parameter? - python

I find when __init__ method lacks self parameter, only if there is no instantiation of this class, the compiler won't complain:
$ cat test.py
#!/usr/bin/python
class A():
def __init__():
print("A()")
$ ./test.py
But if there is a instantiation, the running time error will occur:
$ cat test.py
#!/usr/bin/python
class A():
def __init__():
print("A()")
A()
$ ./test.py
Traceback (most recent call last):
File "./test.py", line 6, in <module>
A()
TypeError: __init__() takes 0 positional arguments but 1 was given
Per my understanding, __init__() seems no use because it can't make any instance. So why doesn't the Python compiler enforce limitation such as when no self parameter in __init__ function, it will show error message? Is it reasonable? Or I miss something.

__init__ is not a special name at compilation time.
It is possible to do things with the symbol A.__init__ other than invoke it by trying to construct an A, and I think it is possible to replace the unusable __init__ function with a different function at runtime prior to trying to construct an A.
The check for a correct number of arguments is made when __init__ is called, as it is for any other method.

it must be one argument at least, we call it "self" usually, so your Python code maybe have a small change
#!/usr/bin/python
class A(object):
def __init__(self):
print("A()")
A()

__init__ is the initialization of an already created instance of a class, therefore it needs self, just like every other class method. If you want to handle the creation of the class, that is the __new__ method. This seems like a good description.
Don't let the fact that python doesn't complain unless the method is called confuse you.

Related

Difference between having #staticmethod and not having it

In Python 3.x what can I do with bar() that I cannot do with foo()?
class A:
def foo():
print("some code")
#staticmethod
def bar():
print("some code")
Note: I initially forgot to specify self as an argument to foo(), but I'm leaving the mistake there, since the answers andress that.
a staticmethod is a method that does not require an object as its first parameter. This means it is a method useful to the class itself and all instantiations of it, rather than just instances of it (object initialized as A().
What this means in practical terms, is that Python does not implicitly send the object itself as a parameter. Your first method will break once you call it:
>>> a.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes 0 positional arguments but 1 was given
This is because Python supplies object methods with the object itself as a first parameter. Hence the ubiquitous self argument:
def foo(self): #Proper signature
On the other hand,
A.bar()
will work just fine, and so will
a.bar()
The object is not supplied as a first argument. Use staticmethods for methods that are supposed to be helpful to the class and its instances, but do not require knowledge of either. Usually I use these as utility functions.
Note there is a third version, a classmethod, which is similar to a regular method in that it accepts a first parameter by default - the class of the caller. In this case the minimal signature is
#classmethod
def operateOnClass(cls):
Use this to make changes that affect all instances, such as changing class variables.
bar() can be called from an uninstantiated class object. foo() needs to be fed self as an argument, and as such can only be called from an object already declared as an instance of class A

Does a method of a class should have at least one parameter referring to an instance?

Python In a Nutshell says that:
a method defined in a class body has a mandatory first
parameter, conventionally named self , that refers to the instance
on which you call the method.
Does a method of a class should have at least one parameter referring to an instance?
Is it a bad practice to create a method without any parameter?
Is it a good practice to always make a method work when calling it on either the class or an instance of the class?
Note that I am not talking about a static method or class method, but an ordinary method.
>>> class C5(object):
... def hello():
... print('Hello')
...
>>> C5.hello()
Hello
>>> C5().hello()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: hello() takes 0 positional arguments but 1 was given
Thanks.
You should always put self as the first parameter in the class method. If you want call class method without creating a class instance, need to write following:
class Foo:
#staticmethod
def hello():
print("Hi")
Python wants you to pass self as an argument into your class methods so that python knows that the methods belong to the class that they are in.

Unbound method error

I'm trying to understand the self keyword in python classes. Ergo I made up a simple class:
class Question(object):
"""A class for answering my OO questions about python.
attributes: a_number"""
def __init__():
print "You've initialized a Question!"
def myself_add(self, new_number):
self.a_number += new_number
And in a __main__ function below the class definition I'm running the code
my_q = Question
print my_q
my_q.a_number = 12
print 'A number:',my_q.a_number
my_q.myself_add(3)
print 'A number:',my_q.a_number
The result I'm getting (including error) is
<class '__main__.Question'>
A number: 12
Traceback (most recent call last):
File "question.py", line 21, in <module>
my_q.myself_add(3)
TypeError: unbound method myself_add() must be called with Question instance as first argument (got int instance instead)
I'm trying to understand why the method myself_add is considered unbound. What does that mean? And why doesn't it know that I'm calling it on an instance of the Question class? Also, why doesn't my __init__ print happen?
In order to create an instance you need to write Question() not Question.
__init__ should take at least self argument
You may also want to initialize self.a_number in __init__ or put in into the class body, otherwise the call of myself_add will fail if you do not execute my_q.a_number = 12
The "self" argument can be anything, but is called self by convention.
It's passed in for you by python on default.
You can try running this simple code snippet to see what I mean:
class A(object):
def __init__(self):
pass
def check(self, checked):
print self is checked
and then from the command line:
a=A()
a.check(a)
You can take this further like this:
In [74]: b=A()
In [75]: a.check(b)
False
So here I've created two instances of A, one called a one called b. Only when comparing and instance of a's self to a itself is the statement true.
Hopefully that makes sense.
Specifically in your case, your class Question needs to be instantiated (Question()) and your __init__ needs an argument (self by convention).
On when a function is bound, you might find this answer helpful:
What is the difference between a function, an unbound method and a bound method? (but might be a bid advanced)
First of all , when you initialize an instance of an class you use opening and closing parenthesis which calls the __init__ method by convention.
my_q = Question()
However, in your case your __init__ method is not bound to an object using self, so if you run as is it will give error,
my_q = Question()
TypeError: __init__() takes no arguments (1 given)
>>>
You need to initialize __init__ with self so that instance can make implicit call to the object.
def __init__(self):
Now , the program runs smoothly
First print is the my_q object itself.
>>>
You've initialized a Question!
<__main__.Question object at 0x028ED2F0>
A number: 12
A number: 15

Why is #staticmethod not preserved across classes, when #classmethod is?

Take the following example script:
class A(object):
#classmethod
def one(cls):
print("I am class")
#staticmethod
def two():
print("I am static")
class B(object):
one = A.one
two = A.two
B.one()
B.two()
When I run this script with Python 2.7.11 I get:
I am class
Traceback (most recent call last):
File "test.py", line 17, in <module>
B.two()
TypeError: unbound method two() must be called with B instance as first argument (got nothing instead)
It appears that the #classmethod decorator is preserved across the classes, but #staticmethod is not.
Python 3.4 behaves as expected:
I am class
I am static
Why does Python2 not preserve #staticmethod, and is there a workaround?
edit: taking two out of a class (and retaining #staticmethod) seems to work, but this still seems strange to me.
classmethod and staticmethod are descriptors, and neither of them are doing what you expect, not just staticmethod.
When you access A.one, it's creating a bound method on A, then making that an attribute of B, but because it's bound to A, the cls argument will always be A, even if you call B.one (this is the case on both Python 2 and Python 3; it's wrong everywhere).
When you access A.two, it's returning the raw function object (the staticmethod descriptor doesn't need to do anything special aside from preventing binding that would pass self or cls, so it just returns what it wrapped). But that raw function object then gets attached to B as an unbound instance method, because without the staticmethod wrapping, it's just like you'd defined it normally.
The reason the latter works in Python 3 is that Python 3 has no concept of unbound methods. It has functions (which if accessed via an instance of a class become bound methods) and bound methods, where Python 2 has functions, unbound methods and bound methods.
Unbound methods check that they're called with an object of the correct type, thus your error. Plain functions just want the correct number of arguments.
The staticmethod decorator in Python 3 is still returning the raw function object, but in Python 3, that's fine; since it's not a special unbound method object, if you call it on the class itself, it's just like a namespaced function, not a method of any sort. You'd see the problem if you tried to do:
B().two()
though, because that will make a bound method out of that instance of B and the two function, passing an extra argument (self) that two does not accept. Basically, on Python 3, staticmethod is a convenience to let you call the function on instances without causing binding, but if you only ever call the function by referencing the class itself, it's not needed, because it's just a plain function, not the Python 2 "unbound method".
If you had some reason to perform this copy (normally, I'd suggest inheriting from A, but whatever), and you want to make sure you get the descriptor wrapped version of the function, not whatever the descriptor gives you when accessed on A, you'd bypass the descriptor protocol by directly accessing A's __dict__:
class B(object):
one = A.__dict__['one']
two = A.__dict__['two']
By directly copying from the class dictionary, the descriptor protocol magic is never invoked, and you get the staticmethod and classmethod wrapped versions of one and two.
DISCLAIMER: This is not really an answer, but it doesn't fit into a comment format either.
Note that with Python2 #classmethod is NOT correctly preserved across classes either. In the code below, the call to B.one() works as though it was invoked through class A:
$ cat test.py
class A(object):
#classmethod
def one(cls):
print("I am class", cls.__name__)
class A2(A):
pass
class B(object):
one = A.one
A.one()
A2.one()
B.one()
$ python2 test.py
('I am class', 'A')
('I am class', 'A2')
('I am class', 'A')

How do I call a base class method from within the same overloaded derived class method in python?

I have the following classes setup in my python project,
In MicroSim.py
class MicroSim:
def __init__(self, other_values):
# init stuff here
def _generate_file_name(self, integer_value):
# do some stuff here
def run(self):
# do some more stuff
self._generate_file_name(i)
In ThresholdCollabSim.py
from MicroSim import MicroSim
class ThresholdCollabSim (MicroSim):
# no __init__() implmented
def _generate_file_name(self, integer_value):
# do stuff here
super(ThresholdCollabSim, self)._generate_file_name(integer_value) # I'm trying to call MicroSim._generate_file_name() here
# run() method is not re-implemented in Derived!
In MicroSimRunner.py
from ThresholdCollabSim import ThresholdCollabSim
def run_sims(values):
thresholdSim = ThresholdCollabSim(some_values) # I assume since ThresholdCollabSim doesn't have it's own __init__() the MicroSim.__init() will be used here
thresholdSim.run() # again, the MicroSim.run() method should be called here since ThresholdCollabSim.run() doesn't exist
When I run this code I get the error msg,
Traceback (most recent call last): File "stdin", line 1, in
File "H:...\MicroSimRunner.py", line 11, in run_sims
thresholdSim.run() File "H:...\MicroSim.py", line 42, in run
self._generate_file_name(r) File "H:...\ThresholdCollabSim.py", line 17, in _generate_file_name
super(ThresholdCollabSim, self)._generate_file_name(curr_run) TypeError: unbound method _generate_file_name() must be
called with MicroSim instance as first argument (got int instance
instead)
I have tried searching for issues like this here and have found similar posts and have tried all the solutions discussed there but this error doesn't seem to go away. I have tried changing the line in question to,
super(ThresholdCollabSim, self)._generate_file_name(self, curr_run)
but it changes nothing (same error). I am relatively new at Python programming so this may just be a silly mistake. Any help is much appreciated. Thanks!
You forgot the self argument in your derived _generate_file_name method. Also, you need to make MicroSim a new-style class by using class MicroSim(object).
As a supplement.
You use super in the old-style class.
From the super documentation, we know that:
super() only works for new-style classes.
And a new-style class is
Any class which inherits from object.

Categories

Resources