Bound Python method accessed with getattr throwing:" takes no arguments (1 given) " [duplicate]

StackOverflow https://stackoverflow.com/questions/14249390

  •  14-01-2022
  •  | 
  •  

Question

Something rather odd is happening in an interaction between bound methods, inheritance, and getattr that I am failing to understand.

I have a directory setup like:

/a
__init__.py
start_module.py
  /b
  __init__.py
  imported_module.py 

imported_module.py contains a number of class objects one of which is of this form:

class Foo(some_parent_class):
    def bar(self):
       return [1,2,3]

A function in start_module.py uses inspect to get a list of strings representing the classes in imported_module.py. "Foo" is the first of those strings. The goal is to run bar in start_module.py using that string and getattr.*

To do this I use code in start_module of the form:

for class_name in class_name_list:
  instance = getattr(b.imported_module, class_name)()
  function = getattr(instance, "bar")
  for doodad in [x for x in function()]:
     print doodad 

Which does successfully start to iterate over the list comprehension, but on the first string, "bar", I get a bizarre error. Despite bar being a bound method, and so as far as I understand expecting an instance of Foo as an argument, I am told:

TypeError: bar() takes no arguments (1 given)

This makes it seem like my call to function() is passing the Foo instance, but the code is not expecting to receive it.

I really have no idea what is going on here and couldn't parse out an explanation through looking on Google and Stack Overflow. Is the double getattr causing some weird interaction? Is my understanding of class objects in Python too hazy? I'd love to hear your thoughts.

*To avoid the anti-pattern, the real end objective is to have start_module.py automatically have access to all methods of name bar across a variety of classes similar to Foo in imported_module.py. I am doing this in the hopes of avoiding making my successors maintain a list for what could be a very large number of Foo-resembling classes.

Answered below: I think the biggest takeaways here are that inspect is very useful, and that if there is a common cause for the bug you are experiencing, make absolutely sure you've ruled that out before moving on to search for other possibilities. In this case I overlooked the fact that the module I was looking at that had correct code might not be the one being imported due to recent edits to the file structure.

Was it helpful?

Solution

Since the sample code you posted is wrong, I'm guessing that you have another module with the Foo class somewhere - maybe bar is defined like this

class Foo(object):
    def bar():   # <-- missing self parameter
        return [1,2,3]

This does give that error message

>>> Foo().bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes no arguments (1 given)

OTHER TIPS

Class method have a self argument that is essentially automatically passed. It is just the class instance on which you are calling the method. You don't need to pass another parameter.

I'm not able to reproduce the error you're getting. Here's my attempt at a short, self-contained compilable example, run from the Python shell:

>>> class Foo(object):
    def bar(self):
        print("Foo.bar!")

>>> import __main__ as mod
>>> cls = getattr(mod, "Foo")
>>> inst = cls()
>>> func = getattr(inst, "bar")
>>> func()
Foo.bar!

Perhaps you can try adapting your inspect based code to an example like this one and see where it is going wrong.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top