Is there a reason not to do this?

Carl Banks pavlovevidence at gmail.com
Fri Dec 1 09:27:06 EST 2006


Ron Garret wrote:
> In article <rNOSPAMon-ACA0D1.23364830112006 at news.gha.chartermi.net>,
>  Ron Garret <rNOSPAMon at flownet.com> wrote:
> > I don't want to get into a philosophical debate.
>
> Actually, I changed my mind.  Consider:
>
> def g(): print 'G'
>
> def h(): print 'H'
>
> def f(): g()
>
> class C1:
>   def m1(self): f()
>
> class C2:
>   def m1(self): g()
>
> c1 = C1()
> c2 = C2()
>
> def f(): h()
>
> class C2:
>   def m1(self): h()
>
> c1.m1()  # Prints H
> c2.m1()  # Prints G
>
> On what principled basis can you justify two different outputs in this
> case?  Why should I be able to change the definition of f and not have
> to go back and recompile all references to it, but not m1?

I see what you were asking now: you want to know why a class statement
doesn't modify a previously existing class (as is the case in Ruby)
rather than to create a new one.

The principle behind this is pretty much "it was just a language design
decision".

The designers of Python felt it was generally best to have whole
classes in one place, rather than spread out over many locations.  I
tend to agree with this.  Changing classes in-place violates the
"principle of least surprise"--keep in mind the "surprise" we're
talking about is the reader's surprise, not the writer's.  A person
might be reading a class definition wondering, "WTF is happening, why
doesn't it match the behavior?", not knowing that the class was
modified in-place somewhere else.  (That person could be you three
months later.)

Valid use cases like yours are exceptional, and can be done
straightforwardly without changing class statement to modify in-place,
so I think it was the right decision.

Your opinion may differ.  It doesn't seem to have wreaked havoc in
Common Lisp and Ruby.  But that's not how Python is.  I have things I
don't like about Python, too.  You just deal with it.


P.S. If you want to be truly evil, you could use a class hook to get
the modifying in-place behavior:

def modify_in_place(name,bases,clsdict):
    cls = globals()[name]
    for attr,val in clsdict.iteritems():
        setattr(cls,attr,val)
    return cls

# Replace second C2 class above with this
class C2:
    __metaclass__ = modify_in_place
    def m1(self): h()


Carl Banks




More information about the Python-list mailing list