views:

65

answers:

2

Here's some (simplified) code for what I'm trying to do:

class a:
    pass

class b:
    def printSelf(self):
        print self


instOfA = a()
instOfB = b()
instOfA.printSelf = instOfB.printSelf
instOfA.printSelf()
  <__main__.b instance at 0x0295D238>

When I call instOfA.printSelf(), it prints self as being instOfB.
But I want self to be instOfA when I call instOfA.printSelf(), and instOfB when I call instOfB.printSelf()
How would I go about doing this without manually defining printSelf in class a?

To those wondering why I would even want to do something like this, here's a longer example:

#Acts as a template for aInstance. I would have several aInstances that have common rules, which are defined by an instance of the aDefinition class (though I'd have multiple rule sets too)
class aDefinitionClass: 
    def setInput(self, val):
        self.inputStr = val
    def checkInputByLength(self):
        return len(self.inputStr) < 5
    def checkInputByCase(self):
        return self.inputStr == self.inputStr.upper()
    checkInput = checkInputByLength


class aInstance(aDefinition):
    inputStr = ""
    def __init__(self, ruleDefinition):
        self.checkInput = ruleDefinition.checkInput


aDef = aDefinitionClass()
aDef.checkInput = aDef.checkInputByCase #Changing one of the rules.
aInst = aInstance(aDef)
aInst.setInput("ABC")
aInst.checkInput()
  AttributeError: aDefinitionClass instance has no attribute 'inputStr'

I realize it's a bit unusual, but I couldn't think of a different way of doing it. I'm effectively trying to subclass an instance. It'd look something like this if Python allowed it:

class aInstance(aDef):
    inputStr = ""
+2  A: 

You can use the descriptor of the method to get a bound method:

instOfA.printSelf = b.printSelf.__get__(instOfA)

Of course, you can use __class__ if you don't know the type of instOfB:

instOfA.printSelf = instOfB.__class__.printSelf.__get__(instOfA)

If instOfA doesn't need the method stored, you can just pass in an instance of a as self:

instOfB.printSelf.__func__(instOfA)
Brian McKenna
A: 

The issue is that instOfB.printSelf is a bound method - the self variable is set to be instOfB when you create the object. What I would do, frankly, is just to set up the function slightly differently:

class b:
    def printSelf(self, other):
        print other

Then you simply do

instOfA = a()
instOfB = b()
instOfA.printSelf = instOfB.printSelf
instOfA.printSelf(instOfA)

And if you want to do that with instOfB:

instOfB.printSelf(instOfB)

It's slightly uglier that way, but it's a bit cleaner and more obvious than Brian's solution (which works just fine as well).

Edit:

An even better way is to use descriptors (although this still requires modifying your code):

class b:
    @staticmethod
    def printSelf(self):
        print self

Though you still have to include the instance of the object when calling the function.

Daniel G
That's a much better solution. I'd rename `object` though, it's fairly important in Python (even if it doesn't matter in this example).
Brian McKenna
Whilst this is a good, clean solution, it requires that I change all of my functions. Brian's solution allows me to work around that.
Wallacoloo
@Brian - oops, of course!
Daniel G
You changed part of it, put you're still trying to print object ;)
Wallacoloo
Wow... boy do I feel smart today :-X
Daniel G