redefining a function through assignment

Michael Spencer mahs at telcopartners.com
Thu Sep 8 22:19:55 EDT 2005


Daniel Britt wrote:
> Hello All,
> I am new to Python so if there is an obvious answer to my question please 
> forgive me. Lets say I have the following code in mod1.py
> 
> class test:
> def func1(self):
> print 'hello'
> 
> 
> Now lets say I have another file called main.py:
> 
> import mod1
> 
> inst = mod1.test()
> inst.func1()
> 
> 
> This will print out hello. Now if I added the following to main:
> def newFunc(var):
> print 'new method'
> 
> mod1.test.func1 = newFunc
> 
> inst.func1()
> 
> 
> This will print out 'new method'. If any other instance of mod1.test is 
> created calling func1, func1 will always reference the newFunc function. 
> This is less than desirable to say the least. Is there any way of preventing 
> this from ever happening? I searched around for quite a while and I haven't 
> been able to find anyone who has a solution. The reason I am asking this is 
> b/c I want to build an application in python that has plugins. I want to 
> make sure that a programmer could not accidently or intentionally clobber 
> over another plugins code, which they could easily do. Any help would be 
> appreciated. Thanks
> 
> ~DJ
> 
> 
The obvious answer is not to give a programmer access to an object that you 
don't want to be messed with.  However, you've probably thought of that...

You could deter (not completely prevent) modification of the class by 
intercepting the __setattr__ of its metaclass:

  >>> class meta_writeonce(type):
  ...     def __setattr__(cls, attrname, val):
  ...         raise TypeError
  ...
  >>> class A(object):
  ...     __metaclass__ = meta_writeonce
  ...     def func(self):
  ...         print "hello from the unmodified class A"
  ...
  >>> A.func = None
  Traceback (most recent call last):
    File "<input>", line 1, in ?
    File "<input>", line 3, in __setattr__
  TypeError
  >>> a = A()
  >>> a.func()
  hello from the unmodified class A
  >>>

If you want only to deter overwriting existing class attributes, you could do:

  >>> class meta_writeonlyattributes(type):
  ...     def __setattr__(cls, attrname, val):
  ...         if hasattr(cls, attrname):
  ...             raise TypeError
  ...         else:
  ...             type.__setattr__(cls, attrname, val)
  ...
  >>> class B(object):
  ...     __metaclass__ = meta_writeonlyattributes
  ...     def func(self):
  ...         print "hello from the unmodified class B"
  ...
  >>> B.func = None
  Traceback (most recent call last):
    File "<input>", line 1, in ?
    File "<input>", line 4, in __setattr__
  TypeError
  >>> B.func2 = lambda self: "hello from func2"
  >>> b = B()
  >>> b.func()
  hello from the unmodified class B
  >>> b.func2()
  'hello from func2'
  >>>

This is good enough to prevent accidental 'clobbering', but would not prevent a 
programmer rebinding an attribute deliberately:

  >>> type.__setattr__(B,"func",lambda self: "I've got you now")
  >>> b = B()
  >>> b.func()
  "I've got you now"
  >>>

Michael




More information about the Python-list mailing list