5

Let's say I have a file containing the string "unpredictable_words". I would like to read in this string and then define a function as follows:

def test_unpredictable_words(self):
    do_important_stuff()

I would then like to inject this function into a class definition so that this function can be called on any instances of this class.

How can I accomplish this?

I looked a bit at this answer - https://stackoverflow.com/a/8160676/1701170 - but I don't think it does what I want, exactly, or at least I can't understand what is going on.

b4hand
  • 9,550
  • 4
  • 44
  • 49
tadasajon
  • 14,276
  • 29
  • 92
  • 144

2 Answers2

5
Python 2.7.3 (default, Sep 26 2012, 21:51:14) 
>>> def injected(self):
...     print 'injected'
... 
>>> class A(object):
...     pass
... 
>>> A.injected = injected
>>> a = A()
>>> a.injected()
injected
>>> def func2(self):
...     print 'func2'
... 
>>> setattr(A, 'injected2', func2)
>>> a.injected2()
func2
>>> 
warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • 1
    I don't follow. Your answer does not have a function name that is dynamically determined based on a string. Injecting the function isn't the hard part for me. Knowing how to define a function with a named based on a string is the part I don't understand. – tadasajon Dec 29 '12 at 03:12
  • 1
    I think the answer has all the necessary bits to accomplish what you need. You have a class `A` in which you want to inject a new method. Extract method name from a file, define any function (name doesn't matter) with the needed code, use `setattr(A, method_name, your_defined_function)` to inject a new method. – warvariuc Dec 29 '12 at 03:37
  • 1
    Functions in Python are first class citizens. Function name doesn't really matter and you can assign the same function to several variables. So your "Knowing how to define a function with a named based on a string" doesn't make sense for me. Define any function, then inject it under a different name into your class. – warvariuc Dec 29 '12 at 03:40
  • thanks. Your example seems to be working. I agree with you that function names should not usually matter, but I'm using Python unittest - it runs every function with a name that starts with "test" as a separate unit test, so it seems that the function name is important for using unittest. – tadasajon Dec 29 '12 at 03:46
  • Ok, so do something like `setattr(TestCase, 'test_' + test_function_name, defined_function)` – warvariuc Dec 29 '12 at 03:55
  • I was needing something like this, also for `unittest`. If you also need a dynamic function that changes action based on some variable input, take a look at closures. – CivFan Feb 12 '16 at 22:13
3

You don't need to define a function under one true name. Functions are first-class entitiens, you can pass them around and assign to variables. On top level, you use globals(), withing another function, locals() to bind a name:

>>> def foo(x):
...   return x + 1
... 
>>> name = 'unpredictable_words'
>>> 
>>> globals()['test_' + name] = foo
>>> 
>>> test_unpredictable_words(1)
2
>>> 
>>> def some_function():
...   locals()['test_' + name] = foo
...   return test_unpredictable_words(1)
... 
>>> some_function()
2
>>> 

Sometimes you still want that the function knows its name, in order to appear nicely in a stacktrace. Now test_unpredictable_words appear as foo in error messages. This is not easy to fix, since that name is stored in foo.func_code.co_name and can't be changed.

9000
  • 39,899
  • 9
  • 66
  • 104