[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