Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Defining a method final

0 views
Skip to first unread message

Fabio Corneti

unread,
Jun 11, 2002, 7:35:30 AM6/11/02
to
Is there any way to define a method final in Python?
I've searched through the docs and through the web, but
it seems there's no way to to such a thing using standard
language statements. Some suggestions?

--
Fabio Corneti
Network Administrator
fcorneti AT libero DOT it

holger krekel

unread,
Jun 11, 2002, 7:47:54 AM6/11/02
to
Fabio Corneti wrote:
> Is there any way to define a method final in Python?
> I've searched through the docs and through the web, but
> it seems there's no way to to such a thing using standard
> language statements. Some suggestions?

not that i know of. unless you write it in C :-)

would you care to present your reasoning for doing a final method?

regards,

holger


Fabio Corneti

unread,
Jun 11, 2002, 8:45:09 AM6/11/02
to
I would like to define a method for a class which has
not to be overriden. Of course, since the developer of
this project are two, this could be established by
convention, but if the project will grow consistently
another developer could override the method by mistake,
causing unpleasant side effects.

--
Fabio Corneti

Jerzy Karczmarczuk

unread,
Jun 11, 2002, 8:55:02 AM6/11/02
to

Hm. A classical problem.

Will you ask tomorrow for private methods and private inheritance
as well?

Python, like Smalltalk was never designed for paranoid [*NO* disrespect
meant or implied] projects, whose members need to protect themselves
from themselves. If such a danger is real, use qualified names.


Jerzy Karczmarczuk
Caen, France

Emile van Sebille

unread,
Jun 11, 2002, 9:01:30 AM6/11/02
to
"Fabio Corneti" <fcor...@libero.it> wrote in message
news:phmN8.36164$K4.8...@twister2.libero.it...

Accepted practice is to use a single underscore for objects to be
considered private. This does not prevent their use, but strongly
signals that re-use ought not to be done.

>>> class Test:
... def _private(self): pass
...

HTH,

--

Emile van Sebille
em...@fenx.com

---------

Eric Brunel

unread,
Jun 11, 2002, 11:35:30 AM6/11/02
to
Emile van Sebille wrote:
> Accepted practice is to use a single underscore for objects to be
> considered private. This does not prevent their use, but strongly
> signals that re-use ought not to be done.
>
>>>> class Test:
> ... def _private(self): pass
> ...
>

Python now have an "official" means to make attributes private by prefixing
them with a double-underscore. And it *does* prevent their use or
overloading:

class A:
def __private(self): pass
class B(A):
pass
o = B()
o.__private()

results in:

Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: B instance has no attribute '__private'

Regarding the original question (final methods), it has however obvious
drawbacks:
- the method can be *redefined*: that doesn't mean it can be overloaded,
but class B can have its own __private method
- the method is actually *private*, which means that neither sub-classes,
nor "outside" classes can call it.

I don't think that actual final methods can be defined in Python...
--
- Eric Brunel <eric....@pragmadev.com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com

Jerzy Karczmarczuk

unread,
Jun 11, 2002, 9:42:30 AM6/11/02
to
Eric Brunel wrote:

> Python now have an "official" means to make attributes private by prefixing
> them with a double-underscore. And it *does* prevent their use or
> overloading:
>
> class A:
> def __private(self): pass
> class B(A):
> pass
> o = B()
> o.__private()
>
> results in:
>
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> AttributeError: B instance has no attribute '__private'

Some newbies may understand this wrongly. The attribute is still
accessible, it has just a different name: _A__private etc.

(You don't even need the class B to find out that
o=A()
o.__private()

won't work. But launch dir(A) and look.)

Jerzy Karczmarczuk

holger krekel

unread,
Jun 11, 2002, 9:32:30 AM6/11/02
to
Hello Fabio,

[you explained]

I see. But did you know that usually pythonic objects work like this:

class stream:
def readline(self):
return ..someline...

class filestream: # no inheritance needed!
def readline(self):
return ..readfromfile...

and that a method wanting to have an instance which it can
call readline on, would not need to check types etc...

def tokenize(provider):
l=provider.readline()

works with a stream or a filestream-instance, it even works
with a 'file' instance or a StringIO-instance :-)

I imagine that this might sound fragile to you. But you
spare yourself and other a *lot* of effort if you don't
insist on exact type checking but rather use the
*behaviour* of objects. After all, working with behaviour
is the great promise of OOP and python has it. Java/C++
would require you to group all objects into an
inheritance-hierarchy which usually makes things *more*
difficult and verbose.

OTOH for big enough programs (say >50.000 LOC) you should:

- write many tests which thoroughly check for desired behaviour
(ask Peter Hansen for more details:-)

- dig deeper into 'interface' concepts for python. It's
also discussed on python-lists from time to time...

not that someone will certainly point out, that you should
write tests for smaller programs, too :-)

regards,

holger


David LeBlanc

unread,
Jun 11, 2002, 9:52:27 AM6/11/02
to
"final" is a Java concept not supported in Python.

You could possibly simulate it with an 'init' method called after an
instance of a subclass is created to adjust the dictionary so that the base
classes' method is always called in preference to any same-named method in
the derived class(es). Potentially this could even be done in the derived
classes' __init__ method that calls the base class __init__ and thus not
need an additional explict initialization step.

David LeBlanc
Seattle, WA USA

> --
> http://mail.python.org/mailman/listinfo/python-list

Emile van Sebille

unread,
Jun 11, 2002, 10:21:53 AM6/11/02
to
"Eric Brunel" <eric....@pragmadev.com> wrote in message
news:ae4tvv$rvd$1...@wanadoo.fr...

> Python now have an "official" means to make attributes private by
prefixing
> them with a double-underscore. And it *does* prevent their use or
> overloading:
>

I don't know why I thought name mangling only happened at the module
level... But note that even here it's still usable, and that the user
has broken the rule of 'leading underscore == leave it alone'.

>>> class Test:
... def __private(self): pass
...
>>> dir(Test)
['_Test__private', '__doc__', '__module__']
>>> dir(Test)
['_Test__private', '__doc__', '__module__']
>>> Test._Test__private
<unbound method Test.__private>

David LeBlanc

unread,
Jun 11, 2002, 10:19:53 AM6/11/02
to
I think the point of what he is asking for has been missed. Final methods
are not necessisarily private, it means they can't be redefined
("overridden") in derived classes, thus freezing the semantics of the
method.

A plausible scenario for something like this is a class that wraps hardware.
While I might like to create derived classes for text or binary I/O on this
widget, the exact sequence of manipulating the hardware is tricky and can
result in expensive damage if not done exactly right. Therefore, I don't
want derived classes changing the read or write methods of the base class.

In another post, I suggested the idea of pulling the base classes methods
down into the dictionary of the derived classes during __init__ I don't know
if this is a pythonic way to do things (it strikes me as being so), but I
think it would have the desired effect.

David LeBlanc
Seattle, WA USA

--
http://mail.python.org/mailman/listinfo/python-list

Richard Barrett

unread,
Jun 11, 2002, 1:09:53 PM6/11/02
to
At 15:35 11/06/2002 +0000, Eric Brunel wrote:
>Emile van Sebille wrote:
> > Accepted practice is to use a single underscore for objects to be
> > considered private. This does not prevent their use, but strongly
> > signals that re-use ought not to be done.
> >
> >>>> class Test:
> > ... def _private(self): pass
> > ...
> >
>
>Python now have an "official" means to make attributes private by prefixing
>them with a double-underscore. And it *does* prevent their use or
>overloading:

I'm not criticising the double underscore prefix feature but it prevents
neither, if you factor in the name mangling that supports the feature. See
the following transcript from Python 2.2.1 command line:

>>> class A:
... def __private(self): print "class A private"
... def printit(self): self.__private()
...
>>> class B(A):
... pass
...
>>> class C(A):
... def _A__private(self): print "class C private"
...
>>> a1 = A()
>>> a1.printit()
class A private
>>> a1._A__private()
class A private
>>> b1 = B()
>>> b1.printit()
class A private
>>> b1._A__private()
class A private
>>> c1 = C()
>>> c1.printit()
class C private
>>> c1._A__private()
class C private

Jeff Epler

unread,
Jun 11, 2002, 12:20:40 PM6/11/02
to
The following code uses a metaclass to attempt to enforce "final"
methods. Warning: Use of metaclasses has exploded brains. Accessing
directly through __dict__ or object.__setattr__ can bypass these
protections.

def finalmethod(f):
"""Marks a method as a final method. Use like classmethod(), etc. Only
works in subclasses of FinalMethods:
class C(FinalMethods):
def f(x): ...
f = finalmethod(f)"""
f.__final__ = 1
return f

class FinalMethodsMeta(type):
"""Metatype for FinalMethods"""
def __init__(cls, name, bases, dict):
super(FinalMethodsMeta, cls).__init__(name, bases, dict)
for base in cls.__mro__:
if base is cls: continue
for attrname in base.__dict__:
attr = base.__dict__[attrname]
if hasattr(attr, "__final__") and attr.__final__:
func = getattr(cls, attrname).im_func
print attrname, attr, func
if func is not attr:
raise ValueError, \
"Subclasses of %s may not override the method %s" \
% (base.__name__, attrname)

def __setattr__(cls, name, attr):
oldval = getattr(cls, name, None)
if hasattr(oldval, "__final__") and oldval.__final__:
raise ValueError, "final methods may not be overridden by assignment to class"
super(FinalMethodsMeta, cls).__setattr__(name, attr)

class FinalMethods:
"""Subclasses of FinalMethods may define a method to be a finalmethod().
This probably only works with instancemethods, not classmethods or
staticmethods. A subclass may not override a finalmethod"""


__metaclass__ = FinalMethodsMeta

def __setattr__(self, name, attr):
oldval = getattr(self, name, None)
if hasattr(oldval, "__final__") and oldval.__final__:
raise ValueError, "final methods may not be overridden by assignment to instance"
super(FinalMethods, self).__setattr__(name, attr)

def _test():
class c1(FinalMethods):
def f(x): pass
f = finalmethod(f)

def g(x): pass

class c2(FinalMethods):
def g(x): pass
g = finalmethod(g)

# Test that FinalMethods classes can be subclassed when they don't
# interfere with each others' final methods
class c3(c2, c1): pass
assert c3.f.im_func is c1.f.im_func

# Test that a FinalMethods class can be subclassed when the added
# methods do not interfere with the super's final methods
class c4(c1):
def g(x): pass

# Test that when a final method is concealed by a non-final method,
# it blows up
try:
class c5(c1, c2): pass
except ValueError, detail:
print "Caught expected ValueError:", detail
else:
print "Did not catch expected error"
print c5.g, c1.g, c2.g
raise RuntimeError

# Test that when a final method is overridden in the subclass, it
# blows up
try:
class c5(c1):
def f(x): pass
except ValueError, detail:
print "Caught expected ValueError:", detail
else:
print c5.f, c1.f
print "Did not catch expected error"
raise RuntimeError

# Test that when a final method is overridden in the sub-subclass,
# it blows up
try:
class c6(c3):
def f(x): pass
except ValueError, detail:
print "Caught expected ValueError:", detail
else:
print c6.f, c3.f
print "Did not catch expected error"
raise RuntimeError

# Test that assigning to non-final attributes works (class)
class c7(c1): pass
c7.g = lambda: None

# Test that assigning to final attributes fails (class)
try:
class c7(c3): pass
c7.f = None
except ValueError, detail:
print "Caught expected ValueError:", detail
else:
print "Did not catch expected error"
raise RuntimeError

# Test that assigning to non-final attributes works (instance)
i = c1()
i.g = None

# Test that assigning to final attributes fails (instance)
try:
i = c1();
i.f = None
except ValueError, detail:
print "Caught expected ValueError:", detail
else:
print "Did not catch expected error"
raise RuntimeError

print "seems ta work"

if __name__ == '__main__': _test()


0 new messages