prometeu
prometeu

Reputation: 689

str object is not callable - calling a function with a function/string as an argument

when I execute this code:

clffunc = sys.argv[1]    

def fun(clffunc):
      error_vector = clffunc()
      print error_vector
      loss_total = sum(error_vector)
      loss_mean = np.mean(error_vector)
      print "The mean error is %.2f" % loss_mean

def svm_clf():
      #The clasificator object 
      clf = svm.SVC()
      clf.fit(train_features, train_targets)
      # Prediction
      test_predicted = clf.predict(test_features)
      # Analysis and output 
      return np.absolute(test_predicted-test_targets)

if __name__ == "__main__":
      fun(clffunc)

from the terminal as:

python GraspT.py svm_clf

I get the following error:

 File "/home/iki/griper validating/GraspT.py", line 24, in fun
    error_vector = clffunc()

TypeError: 'str' object is not callable

In internet I couldn't find a solution. 'str' object is not callable is almost always done when someone redefines a built-in function or something similar. This is not my case. Here I'm passing a string from terminal, and then this is used as a string in a function argument. This argument is in fact a function. So I want to choose the function (a classifier method in machine learning) that is going to be executed in the code.

Upvotes: 1

Views: 4750

Answers (4)

andreytata
andreytata

Reputation: 19

import sys

def foo(): sys.stdout.write("foo called\n")
def foo1(): sys.stdout.write("foo1 called\n")

if __name__ == "__main__":
    if len(sys.argv) < 2:            # prevent IndexError
        sys.stdout.write("Use commandline argument: foo or foo1\n")
        sys.exit()                   # Print --help and exit
    name = sys.argv[1]               # Get name (str is)
    m = sys.modules["__main__"]      # Get main module instance obj
    if hasattr(m, name):             # Check attribute exists
        a = getattr(m, name)         # Get attribute by str-name
        if hasattr(a, '__call__'):   # Verify callable is?
            a()                      # Call
        else:
            sys.stderr.write("ERROR: is not some callable '%s'\n" % name)
            sys.exit(1)
    else:
        sys.stderr.write("ERROR: has no attr named '%s'\n" % name)
        sys.exit(1)

Upvotes: 0

filvarga
filvarga

Reputation: 56

The problem is that you don't properly understand what you are trying to accomplish.

clffunc = sys.argv[1]    

def fun(clffunc):
      error_vector = clffunc()

You are trying to call a string. sys.argv[1] returns second argument as string. You are doing this : "svm_clf"(). The simple solution is to use eval buildin function. For example : eval('%s()' % clffunc). this expression will definitely do the job :).

Correction that should make it work :

if __name__ == "__main__":
  fun(eval(clffunc))

Upvotes: 0

Axel Lijdens
Axel Lijdens

Reputation: 21

You could directly access the globals and index by the function's name.

def some_func():
    print 'called some_func!'

def some_other_func():
    print 'called some_other_func!'

globals()['some_func']()
globals()['some_other_func']()

globals()[sys.argv[1]]()

Also, you could consider using eval.

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1124548

svm_clf is a string, not a function object. The contents of that string may match the name of a function, but that doesn't make it that function.

You could use the a dictionary to map valid names to function:

functions = {'svm_clf': svm_clf}

if __name__ == "__main__":
    fun(function[clffunc])

or you could use the dictionary that globals() returns for that purpose:

if __name__ == "__main__":
    fun(globals()[clffunc])

This is probably alright in a command-line tool, but take into account that this allows the user of the tool to make your script call anything with a global name.

Upvotes: 4

Related Questions