What does "bound method" error mean when I call a function?

Question:

I am creating a word parsing class and I keep getting a

bound method Word_Parser.sort_word_list of <__main__.Word_Parser instance at 0x1037dd3b0>

error when I run this:

class Word_Parser:
    """docstring for Word_Parser"""
    def __init__(self, sentences):
        self.sentences = sentences

    def parser(self):
        self.word_list = self.sentences.split()

    def sort_word_list(self):
        self.sorted_word_list = self.word_list.sort()

    def num_words(self):
        self.num_words = len(self.word_list)

test = Word_Parser("mary had a little lamb")
test.parser()
test.sort_word_list()
test.num_words()
print test.word_list
print test.sort_word_list
print test.num_words
Asked By: Michael Conlin

||

Answers:

You have an instance method called num_words, but you also have a variable called num_words. They have the same name. When you run num_words(), the function replaces itself with its own output, which probably isn’t what you want to do. Consider returning your values.

To fix your problem, change def num_words to something like def get_num_words and your code should work fine. Also, change print test.sort_word_list to print test.sorted_word_list.

Answered By: Blender

There’s no error here. You’re printing a function, and that’s what functions look like.

To actually call the function, you have to put parens after that. You’re already doing that above. If you want to print the result of calling the function, just have the function return the value, and put the print there. For example:

print test.sort_word_list()

On the other hand, if you want the function to mutate the object’s state, and then print the state some other way, that’s fine too.

Now, your code seems to work in some places, but not others; let’s look at why:

  • parser sets a variable called word_list, and you later print test.word_list, so that works.
  • sort_word_list sets a variable called sorted_word_list, and you later print test.sort_word_list—that is, the function, not the variable. So, you see the bound method. (Also, as Jon Clements points out, even if you fix this, you’re going to print None, because that’s what sort returns.)
  • num_words sets a variable called num_words, and you again print the function—but in this case, the variable has the same name as the function, meaning that you’re actually replacing the function with its output, so it works. This is probably not what you want to do, however.

(There are cases where, at first glance, that seems like it might be a good idea—you only want to compute something once, and then access it over and over again without constantly recomputing that. But this isn’t the way to do it. Either use a @property, or use a memoization decorator.)

Answered By: abarnert

I think you meant print test.sorted_word_list instead of print test.sort_word_list.

In addition list.sort() sorts a list in place and returns None, so you probably want to change sort_word_list() to do the following:

self.sorted_word_list = sorted(self.word_list)

You should also consider either renaming your num_words() function, or changing the attribute that the function assigns to, because currently you overwrite the function with an integer on the first call.

Answered By: Andrew Clark

The syntax problem is shadowing method and variable names. In the current version sort_word_list() is a method, and sorted_word_list is a variable, whereas num_words is both. Also, list.sort() modifies the list and replaces it with a sorted version; the sorted(list) function actually returns a new list.

But I suspect this indicates a design problem. What’s the point of calls like

test.parser()
test.sort_word_list()
test.num_words()

which don’t do anything? You should probably just have the methods figure out whether the appropriate counting and/or sorting has been done, and, if appropriate, do the count or sort and otherwise just return something.

E.G.,

def sort_word_list(self):
   if self.sorted_word_list is not None:
      self.sorted_word_list = sorted(self.word_list)
   return self.sorted_word_list

(Alternately, you could use properties.)

Answered By: Andrew Jaffe

Your helpful comments led me to the following solution:

class Word_Parser:
    """docstring for Word_Parser"""
    def __init__(self, sentences):
        self.sentences = sentences

    def parser(self):
        self.word_list = self.sentences.split()
        word_list = []
        word_list = self.word_list
        return word_list

    def sort_word_list(self):
        self.sorted_word_list = sorted(self.sentences.split())
        sorted_word_list = self.sorted_word_list
        return sorted_word_list

    def get_num_words(self):
        self.num_words = len(self.word_list)
        num_words = self.num_words
        return num_words

test = Word_Parser("mary had a little lamb")
test.parser()
test.sort_word_list()
test.get_num_words()
print test.word_list
print test.sorted_word_list
print test.num_words

and returns:
[‘mary’, ‘had’, ‘a’, ‘little’, ‘lamb’]
[‘a’, ‘had’, ‘lamb’, ‘little’, ‘mary’]
5

Thank you all.

Answered By: Michael Conlin

This problem happens as a result of calling a method without brackets. Take a look at the example below:

class SomeClass(object):
    def __init__(self):
        print 'I am starting'

    def some_meth(self):
        print 'I am a method()'

x = SomeClass()
''' Not adding the bracket after the method call would result in method bound error '''
print x.some_meth
''' However this is how it should be called and it does solve it '''
x.some_meth()
Answered By: blakroku

For this thing you can use @property as an decorator, so you could use instance methods as attributes. For example:

class Word_Parser:
    def __init__(self, sentences):
        self.sentences = sentences

    @property
    def parser(self):
        self.word_list = self.sentences.split()

    @property
    def sort_word_list(self):
        self.sorted_word_list = self.word_list.sort()

    @property
    def num_words(self):
        self.num_words = len(self.word_list)

test = Word_Parser("mary had a little lamb")
test.parser()
test.sort_word_list()
test.num_words()
print test.word_list
print test.sort_word_list
print test.num_words

so you can use access the attributes without calling (i.e., without the ()).

Answered By: JUstice
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.