1

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:

  1. What's the deal with the parenthesis?
  2. What's the deal with the print statements?
asked Apr 22, 2014 at 8:10

4 Answers 4

1

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:

answered Apr 22, 2014 at 8:13
Sign up to request clarification or add additional context in comments.

Comments

1

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.

answered Apr 22, 2014 at 8:12

5 Comments

What does that mean? Does it have any practical purpose?
Assuming you mean the self variable - ebarr gave a link to Guido(The guy who started python) covering this. check it out: neopythonic.blogspot.com.au/2008/10/…
That was interresting, but actually I meant the other thing, am I just mentioning the name of functions without executing them? It seems terribly strange.
Functions in python are first-class objects, meaning they can be reffered to by name and passed as parameters to functions/assigned to variables just like any other type. Using the ( ) operator is what actually calls the function (or other callable) referenced by the name.
It is useful to pass a function object as an argument to another function for example.
0

def list_values(): should be: def list_values(self):

In Python, instance methods take self as the first argument.

answered Apr 22, 2014 at 8:12

Comments

0

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')
answered Apr 22, 2014 at 10:52

3 Comments

not nitpicking, but the question was about OOP in python and your answer is about avoiding aspects of classes, or using advance methods such as casting to string.
@WeaselFox Using __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".
I agree with what you say, but in the context of the question its not really relevant IMHO. The OP stated he's trying to learn OOP in python, and __str__ is not the first thing you would start with.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.