Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setattr and getattr with methods

I have a boiler platey class that delegates some actions to a reference class. It looks like this:

class MyClass():

    def __init__(self, someClass):            
        self.refClass = someClass

    def action1(self):
        self.refClass.action1()

    def action2(self):
        self.refClass.action2()

    def action3(self):
        self.refClass.action3()

This is the refClass:

class RefClass():

    def __init__(self):
        self.myClass = MyClass(self)

    def action1(self):
        #Stuff to execute action1

    def action2(self):
        #Stuff to execute action2

    def action3(self):
        #Stuff to execute action3

I'd like to use Python Metaprogramming to make this more elegant and readable, but I'm not sure how.

I've heard of setattr and getattr, and I think I could do something like

class MyClass():

    def __init__(self, someClass):            
        self.refClass = someClass

    for action in ['action1', 'action2', 'action3']:
        def _delegate(self):
            getattr(self.refClass, action)()

And then I know I need to do this from somewhere, I guess:

MyClass.setattr(action, delegate)

I just can't totally grasp this concept. I understand the basics about not repeating code, and generating the methods with a for loop with functional programming, but then I don't know how to call this methods from elsewhere. Heeeelp!

like image 245
zapatilla Avatar asked Sep 28 '15 17:09

zapatilla


People also ask

What is __ Setattr __ in Python?

Python setattr() method is used to assign the object attribute its value.

What is Setattr () and Getattr () used for?

Python setattr() and getattr() goes hand-in-hand. As we have already seen what getattr() does; The setattr() function is used to assign a new value to an object/instance attribute.

What is use of Setattr () method in inheritance?

Python setattr() function is used to set a value to the object's attribute. It takes three arguments an object, a string, and an arbitrary value, and returns none. It is helpful when we want to add a new attribute to an object and set a value to it.

What is Getattr method used for?

Python getattr() function is used to access the attribute value of an object and also gives an option of executing the default value in case of unavailability of the key.


2 Answers

Python already includes support for generalized delegation to a contained class. Just change the definition of MyClass to:

class MyClass:

    def __init__(self, someClass):            
        self.refClass = someClass  # Note: You call this someClass, but it's actually some object, not some class in your example

    def __getattr__(self, name):
        return getattr(self.refClass, name)

When defined, __getattr__ is called on the instance with the name of the accessed attribute any time an attribute is not found on the instance itself. You then delegate to the contained object by calling getattr to look up the attribute on the contained object and return it. This costs a little each time to do the dynamic lookup, so if you want to avoid it, you can lazily cache attributes when they're first requested by __getattr__, so subsequent access is direct:

def __getattr__(self, name):
     attr = getattr(self.refClass, name)
     setattr(self, name, attr)
     return attr
like image 175
ShadowRanger Avatar answered Sep 29 '22 03:09

ShadowRanger


Personally, for delegating things I usually do something like that:

def delegate(prop_name, meth_name):
    def proxy(self, *args, **kwargs):
        prop = getattr(self, prop_name)
        meth = getattr(prop, meth_name)
        return meth(*args, **kwargs)
    return proxy

class MyClass(object):
    def __init__(self, someClass):
        self.refClass = someClass

    action1 = delegate('refClass', 'action1')
    action2 = delegate('refClass', 'action2')

This will create all delegate methods you need :)

For some explanations, the delegate function here just create a "proxy" function which will act as a class method (see the self argument?) and will pass all arguments given to it to the referenced object's method with the args and kwargs arguments (see *args and **kwargs? for more informations about these arguments)

You can create this with a list too, but I prefer the first because it's more explicit for me :)

class MyClass(object):
    delegated_methods = ['action1', 'action2']

    def __init__(self, someClass):
        self.refClass = someClass

        for meth_name in self.delegated_methods:
            setattr(self, meth_name, delegate('refClass', meth_name))
like image 43
KokaKiwi Avatar answered Sep 29 '22 01:09

KokaKiwi