Use name of a class as a parameter of a function in Python to make it work for several class types

Question:

I write a function that gets a filename, reads out information from the file and creates a Read object out of it.

def read_file(filename):   
  with open(filename, 'r') as filetoread:
        readList = []
        for line in filetoread:
            readList.append(Read(line))
        return readList

This implementation works.

Now I want to generalize my function and make it work for two object/class types: Read and Reference.
So I want to use a class name as a parameter of a function.
The function gets a filename and a classname now. It reads out information from the file and creates an object of a specified classname out of it.

My attempt lookes like this.

def read_file(filename, classname):
  with open(filename, 'r') as filetoread:
        readList = []
        for line in filetoread:
            readList.append(classname(line))
        return readList

I get TypeError: ‘str’ object is not callable.

My idea was using this solution:

def str_to_class(classname):
    return getattr(sys.modules[__name__], classname)

Source: Convert string to Python class object?

I still get an error though (TypeError: getattr(): attribute name must be string)

Asked By: Kate_teryna

||

Answers:

Lets imagine you have a class A

class A:
    pass

If you call str the result should be <class '__main__.A'>:

str(A) == "<class '__main__.A'>"

for get class name you can use __name__ method

str_to_class(Reference.__name__)

or modify your function to str_or_class_to_class 😉

Answered By: Kapustin Alexander

The error: TypeError: 'str' object is not callable. is telling you your problem.

For an object to be "callable" it must implement the __callable__() magic method. Strings do not implement this method, and therefore you get this error.

But wait! You know what does implement __callable__()? Classes!

Now rather than trying to do some conversion, just pass in the raw characters. This classname is a token and will be treated as such.

Therefore when calling your function

Use: read_file("myFile.txt", Read)

and NOT: read_file("myFile.txt", "Read")

Answered By: Hutch