tags:

views:

47

answers:

2

Hello. I have something like that in my python code

class A:
  __mess = "Yeap!"
  def doSome(self):
    self.FN()
  def FN(self):
    pass

def myFN(self):
  print self.__mess

b = A()
b.FN = myFN
b.doSome()

But this doesn't work. Where am I wrong?

python 2.6.5

upd: I want to redefine method (FN) only for one exemplar (b).

upd2:

import new
class A:
  __mess = "Yeap!"
  def doSome(self):
    self.FN()
  def FN(self):
    pass

def myFN(self):
  print self.__mess

b = A()
b.FN = new.instancemethod(myFN, b, A)
b.doSome()

Doesn't work too.

Traceback (most recent call last):
File "", line 1, in
File "", line 4, in doSome
File "", line 2, in myFN AttributeError: A instance has no attribute '__mess'

+4  A: 

myLoopFN is a function, not an instance method. Do

import new
b.loopFN = new.instancemethod( myLoopFN, b, A )

The problem is that Python treats instance methods very slightly differently to regular functions: they get the instance upon which they are run as the default first argument. If you define a method inside a class definition it automagically becomes an instance method, so that when you instantiate the class it gets passed the instance. However, when you define myLoopFN you do it outside the class definition, so that it is an ordinary function instead of an instance method. You fix this by explicitly declaring it as an instance method.

...

BUT

This is icky because it's not something you should do; changing instance methods at runtime will lead to problems. You'll never be sure whether your A is an original A or a modified one, and you won't be able to debug it because you can't tell whether you've changed loopFN or not. This will give you the kind of bugs that Nyarlathotep himself would be proud of.

The right way to do this is to subclass A and override the method, so that you can distinguish between the different classes.

class myA( A ):
    def loopFN(self):
        #put modified function here

This way, you can instantiate the modified class and be certain of its methods.

Edit

You are using a double-underscore variable name, __mess. You (almost certainly) don't want to do this. For some reason known only to our Benevolent Dictator for Life and a select few others, Python automatically mangles these __ names to _<class-name>__, to serve as a sort-of faux private variable. This is horrible, and besides there's no reason to call it __mess instead of (the much nicer) mess.

If you absolutely must call it __mess, you can refer to it as follows:

def myFN(self):
    print( self._A__mess )

(mutatis mutandis when you change the name of A). This is nasty and unPythonic.

katrielalex
Please, look at upd2. Seems like it doesn't work too.Subclassing seems overweightly for this code. In Ruby this is standart code-style (maybe I'm wrong, don't use it for a long time).
Ximik
Ah, I hadn't noticed that you were using double-underscore variable names. The short answer is, don't use them. Python will mangle `__mess` into `_A__mess`, as a faux-private variable. There's no reason to call it anything but `mess`.
katrielalex
+1  A: 

Regarding the second error (with __mess):

Change

print self.__mess

to

print self._mess

And change

class A:
  __mess = "Yeap!"

to

class A:
  _mess = "Yeap!"

Double underscores tell Python to use name-mangling.

An alternative is to change

def myFN(self):
    print self.__mess

to

def myFN(self):
    print self._A__mess
unutbu
oh sorry, didn't notice. Thank you.
Ximik
@Ximik: Not a problem. It's hard to refresh frequently enough when everyone's posting :)
unutbu