0

I am curious how to create a custom method for a class at runtime...

I mean for example with name of method, name of parameters, body of method read from database and assign this method to a class or to an instance.

I have a found possibility to add method that is already written:

class A:
    def __init__(self):
        pass

def method(self):
    return True

A.method = method
a = A()
print(a.method())

but I am interested in completely assembling a new method from scratch:

name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
# To create method from pieces

Is it possible using __dict__ ? Or how else this be done?

4
  • In your mind what is the difference between an already written method and a method from scratch? Commented May 7, 2017 at 20:53
  • @salparadise: The following method: def method(): return True should be written in py-file. From scratch means: name = "method", body = "return True", params = "", - when I create method from pieces and bound somehow it to class, make it looks like a already created Commented May 7, 2017 at 21:00
  • Could you add the example to your code (maybe including an example how you would like to use it)? I'm still not sure I understand what you're trying to do and what the expected result would be. Commented May 7, 2017 at 21:03
  • 1
    @MSeifert: I have updated question with better explanation Commented May 7, 2017 at 21:10

3 Answers 3

2

Methods are another attribute on the object that is the class. They can be added like other attributes:

Code:

class A:
    def __init__(self):
        pass

    def method(self):
        return True

def another_method(self):
    return False

setattr(A, 'another_method', another_method)

Test Code:

a = A()
print(a.another_method())

Results:

False

Methods from a string:

Add if you really need to get your methods from a database or such you can use exec like:

method_string = """

def yet_another_method(self):
    return type(self).__name__

"""

exec(method_string)
setattr(A, 'yet_another_method', yet_another_method)

a = A()
print(a.yet_another_method())

Results:

A
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Stephen. I have forgot that using exec Python execute code and the function in string created at this moment without call
2

This answer has to be treated with care, using exec or eval can run arbitary code and may compromise your system. So if you rely on user-input to create the function you mustn't use this!!!


The warning aside you can simply create anything using exec:

exec("""
def method():
    return True
""")

>>> method()
True

So what you basically need is just a way to get your requirements in there:

functionname = 'funfunc'
parameters = ['a', 'b']
body = 'return a + b'

exec("""
def {functionname}({parameters}):
{body}
""".format(
    functionname=functionname,
    parameters=', '.join(parameters),
    body='\n'.join(['    {line}'.format(line=line) for line in body.split('\n')])))

The body will be indented so that it's valid syntax and the parameter list will be joined using ,. And the test:

>>> funfunc(1, 2)
3

Comments

0

One of the best solutions that I have found is the following:

def import_code(code, name, add_to_sys_modules=0):
    """
    Import dynamically generated code as a module. code is the
    object containing the code (a string, a file handle or an
    actual compiled code object, same types as accepted by an
    exec statement). The name is the name to give to the module,
    and the final argument says wheter to add it to sys.modules
    or not. If it is added, a subsequent import statement using
    name will return this module. If it is not added to sys.modules
    import will try to load it in the normal fashion.

    import foo

    is equivalent to

    foofile = open("/path/to/foo.py")
    foo = importCode(foofile,"foo",1)

    Returns a newly generated module.
    """
    import sys,imp

    module = imp.new_module(name)

    exec(code,module.__dict__)
    if add_to_sys_modules:
        sys.modules[name] = module

    return module

class A:
    def __init__(self):
        pass

name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"

scratch = "def {0}({1}):\n\t{2}".format(name, ','.join(params), body)

new_module = import_code(scratch, "test")
A.method = new_module.method
a = A()
print(a.method())

Original function import_code by the following link http://code.activestate.com/recipes/82234-importing-a-dynamically-generated-module/

Using this solution I can dynamically create methods, load them in runtime and link to whatever I want object !!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.