[Tutor] subclass problem: __names and type-checking
Kent Johnson
kent37 at tds.net
Sat Oct 8 14:08:14 CEST 2005
Brian van den Broek wrote:
> I have a class which I want to subclass. The subclass adds some
> additional arguments to __init__. I want both classes to run a sanity
> check on their arguments before leaving their respective __init__
> methods. I need both to do so, as the _BaseClass may be directly
> instantiated. I need to ask permission for the arguments on instance
> creation rather than for forgiveness later, as bad arguments passed to
> __init__ could take many cpu cycles of other code before they
> manifested themselves.
>
> Here's a sketch of where I'm at:
>
> class _BaseClass(object):
>
> def __init__(self, arg1, arg2):
> self.arg1 = arg1
> self.arg2 = arg2
> if type(self) == _BaseClass:
> # Problem (2) mentioned below shows up here.
> #
> # type test needed otherwise Subclass._validate_args
> # will be called before all subclass args processed by
> # SubClass.__init__, causing AttriuteError
> self._validate_args()
>
> def _validate_args(self):
> '''Performs sanity check on arguments'''
> if not type(self.arg1) in (int, long):
> raise TypeError
> # etc
>
> class SubClass(_BaseClass):
>
> def __init__(self, arg1, arg2, arg3, arg4):
> super(SubClass, self).__init__(arg1, arg2)
> self.arg3 = arg3
> self.arg4 = arg4
> if type(self) == SubClass:
> # same reasoning as before -- leaving room for further
> # subclassing.
> self._validate_args()
>
> def _validate_args(self):
> super(SubClass, self)._validate_args()
> if not isinstance(self.arg3, basestring):
> raise TypeError
> # etc
>
>
> This works as desired, but leaves two problems:
>
> 1) I suspect there may be a better way, as a) this doesn't feel quite
> right and b) in general with Python, it seems that if you are tempted
> to type test, you should rethink, and
I can think of two alternatives:
- If you don't need to call _validate_args() outside of __init__(), just put the code inline in __init__(). Not as clean a class structure but it's a simple solution to the problem.
- Have two validate functions in each class - the shared _validate_args() and a class-specific _validate_SubClassArgs(). Call the class-specific version from __init__() and the shared one from other clients. Then you would have
class _BaseClass(object):
def __init__(self):
...
self._validate_BaseClass()
def _validate_args(self):
super(_BaseClass, self)._validate_args()
self._validate_BaseClass()
and similar code in SubClass.
>
> 2) I originally had __BaseClass rather than _BaseClass. But, with that
> naming, cannot figure out how to write the line
>
> if type(self) == __BaseClass:
>
> so as to make it work. I know about the name mangling with __somename
> names, but I don't know how to manage it in this case.
>
> The attempt of 4 lines up produces:
>
> NameError: global name '_BaseClass__BaseClass' is not defined
>
> This confuses me. I don't see why the error msg prepends '_BaseClass'
> as that name appears nowhere. That confusion aside, I've no idea how
> to effect what I want.
The __ name only gets mangled inside the class definition. The class name itself is not getting mangled. From the language reference:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them.
Kent
>
> I think I won't want __BaseClass in the end, as I do expect it is
> possible that it will be instantiated directly, so the '__' seems
> inappropriate. But, the issue of how to do it remains.
>
> So, details of '_' vs '__' aside, is my approach sound? And, how to
> deal with __BaseClass?
>
>
> Best to all,
>
> Brian vdB
>
>
>
> _______________________________________________
> Tutor maillist - Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
>
>
More information about the Tutor
mailing list