Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it true that "The set of methods, however, is fixed when the class is first defined"?

From Programming Language Pragmatics, by Scott

Both Python and Ruby are more flexible than PHP or more traditional object- oriented languages regarding the contents (members) of a class. New fields can be added to a Python object simply by assigning to them: my_object.new_field = value. The set of methods, however, is fixed when the class is first defined. In Ruby only methods are visible outside a class (“put” and “get” methods must be used to access fields), and all methods must be explicitly declared. It is possible, however, to modify an existing class declaration, adding or overriding methods. One can even do this on an object-by-object basis. As a result, two objects of the same class may not display the same behavior.

What does "The set of methods, however, is fixed when the class is first defined" mean?

I seem to have found a counterexample:

>>> class E:
...     pass
... 
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'E' objects>})
>>> def myfun():
...     pass
... 
>>> E.mf=myfun
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'E' objects>, 'mf': <function myfun at 0x7f6561daba60>})
like image 226
Tim Avatar asked Sep 05 '17 13:09

Tim


1 Answers

Like shown in the question: it's trivial to add a function to a class object that is behaving just like any method would:

def fake_method(self,idx):
    print(self, idx)

class MyClass(object):
    pass

MyClass.new_method = fake_method

n = MyClass()
n.new_method(10)
# <__main__.MyClass object at 0x000001BBA6E90860> 10

You can also add "method"-like "callable attributes" to an instance:

import types

def fake_method(self,idx):
    print(self, idx)

class MyClass(object):
    pass

n = MyClass()
n.new_method = types.MethodType(fake_method, n)

n.new_method(10)
# <__main__.MyClass object at 0x000001BBA6E9C2E8> 10

The types.MethodType is needed here because it would otherwise behave like a staticmethod.

My summary: Either I'm missing some crucial point of the quote or it's wrong.

like image 74
MSeifert Avatar answered Sep 20 '22 19:09

MSeifert