简体   繁体   中英

How to programmatically set python instance methods

I have a class for making an anonymous class:

class Anonyclass(object):
    def __init__(self, **kwargs):
        for kwarg in kwargs:
            self.__setattr__(kwarg, kwargs[kwarg])

It works great for setting properties dynamically, however I cannot set instance methods this way because they don't have access to self . eg Anonyclass(foo = lambda x: x**2).foo(5) == 25 , but I can't seem to shove a self in there...

Anybody know how to make this happen?

This is not creating new "classes" just instances of Anonyclass . Just as you can set instance attributes, you can set callable attributes that know to which instance they are bound.

So, assuming any callable passed as an argument will take self as the first argument, you can change your code to:

from functools import partial

class Anonyclass(object):
    def __init__(self, **kwargs):
        for kwarg, attr in kwargs.items():
            if callable(attr):
                  attr = partial(attr, self)
            setattr(self, kwarg, attr)

This is needed because a callable being set in the instance bypass the mechanism Python uses to bind a method to an instance auto-adding the "self" argument to all calls. So we use functools.partial to do the same. (It could be done with lambdas, but we'd need two levels of lambda's so that the "attr" variable would keep itself bound to the correct method, and not point to the last element assigned in the for loop)

Also, if you want to actually create classes and not instances with attributes bound, you could just make a call to type , passing the same arguments you get as kwargs on your code:

def anon_class_factory(**kwargs):
   return type("Anonyclass", (object,), kwargs)

This will make any function passed in kwargs behave as a "real" method.

You could do it like the following. You may have to modify the for kwarg, value in kwargs.items(): loop to check what kind of value is being assigned and handle data- and/or property-types of attributes differently. I didn't try it with anything else since there weren't any example in your question.

class _Callable(object):
    def __init__(self, instance, name, value):
        self.name = name
        self.instance = instance
        self.__setattr__(name, value)

    def __call__(self, *args):
        return self.__dict__[self.name](self.instance, *args)

class AnonyClass(object):
    def __init__(self, **kwargs):
        for kwarg, value in kwargs.items():
            setattr(self, kwarg, _Callable(self, kwarg, value))

value = 6.480740698407860230965967436088
print( AnonyClass(foo=lambda self, x: x**2).foo(value) )  # -> 42.0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM