I'm trying to learn using classes in Python, and have written this test program. It is to some extent based on code I found in another question I found here on Stack OverFlow.
The code looks as follows:
class Student(object):
name = ""
age = 0
major = ""
# The class "constructor" - It's actually an initializer
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def list_values():
print "Name: ", self.name
print "Age: ", self.age
print "Major: ", self.major
def make_student(name, age, major):
student = Student(name, age, major)
return student
print "A list of students."
Steve = make_student("Steven Schultz",23,"English")
Johnny = make_student("Jonathan Rosenberg",24,"Biology")
Penny = make_student("Penelope Meramveliotakis",21,"Physics")
Steve.list_values()
Johnny.list_values()
Penny.list_values()
When I run this, get the error "TypeError: list_values() takes no arguments (1 given)". In my oppinion I have not given any arguments, but I remove the parenthesis, giving the code
Steve.list_values
Johnny.list_values
Penny.list_values
This renders no errors, but does not do anything - nothing gets printed.
My questions:
- What's the deal with the parenthesis?
- What's the deal with the print statements?
4 Answers 4
The list_values method needs to be bound to your Student instance:
You should change:
def list_values()
to:
def list_values(self)
For an explanation of why, see:
Also this blog post by Guido covers the subject too:
Comments
Python requires you explicitly add the self arguments to member functions, you forgot to add self to your function decleration:
def list_values(self):
This defines it as a member function of the Student class. see here. When you call the functions as members of the Student instances, the self variable is added implicitly, thus triggering the exception, since you did not define a function named list_values that receives one parameter.
As for removing the parenthesis, this means you are not calling the functions but only referring to the function objects, doing nothing.
5 Comments
self variable - ebarr gave a link to Guido(The guy who started python) covering this. check it out: neopythonic.blogspot.com.au/2008/10/… ( ) operator is what actually calls the function (or other callable) referenced by the name.def list_values(): should be: def list_values(self):
In Python, instance methods take self as the first argument.
Comments
As others have mentioned, you should use self in list_values.
But you should really define one of the magic method __str__ or __repr__ instead. Additionally, you're setting some class properties that aren't necessary.
A simpler implementation would be:
class Student(object):
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def __str__(self):
fs = "<name: {}, age: {}, major: {}>"
return fs.format(self.name, self.age, self.major)
Use it like this:
In [9]: Steve = Student("Steven Schultz", 23, "English")
In [10]: Johnny = Student("Jonathan Rosenberg", 24, "Biology")
In [11]: Penny = Student("Penelope Meramveliotakis", 21, "Physics")
In [12]: print Steve
<name: Steven Schultz, age: 23, major: English>
In [13]: print Johnny
<name: Jonathan Rosenberg, age: 24, major: Biology>
In [14]: print Penny
<name: Penelope Meramveliotakis, age: 21, major: Physics>
Since you're not defining special methods, you might as well use a named tuple:
In [16]: from collections import namedtuple
In [17]: Student = namedtuple('Student', ['name', 'age', 'major'])
In [18]: Steve = Student("Steven Schultz", 23, "English")
In [19]: print Steve
Student(name='Steven Schultz', age=23, major='English')
3 Comments
__str__ is not "advanced". It's pythonic, as in "There should be one-- and preferably only one --obvious way to do it." And OOP is not a be-all and end-all. There are many instances where it is not appropriate. See Jack Diederich's excellent video "Stop Writing Classes".__str__ is not the first thing you would start with.