[Tutor] subclass problem: __names and type-checking

Brian van den Broek broek at cc.umanitoba.ca
Sat Oct 8 19:08:37 CEST 2005


Kent Johnson said unto the world upon 2005-10-08 07:08:
> Brian van den Broek wrote:

<snip problem spec of wanting a class and its subclass to each call a 
sanity-check on the arguments to __init__ from within the __init__>


>>
>>Here's a sketch of where I'm at:

<code below trimmed for repost>

>>class _BaseClass(object):
>>
>>     def __init__(self, arg1, arg2):
>>         self.arg1 = arg1
>>         self.arg2 = arg2
>>         if type(self) == _BaseClass:
>>             self._validate_args()
>>
>>     def _validate_args(self):
>>         if not type(self.arg1) in (int, long):
>>             raise TypeError
>>
>>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:
>>             self._validate_args()
>>
>>     def _validate_args(self):
>>         super(SubClass, self)._validate_args()
>>         if not isinstance(self.arg3, basestring):
>>             raise TypeError
 >>
>>
>>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


Thanks for the reply, Kent.

> I can think of two alternatives: 

<snip alternative which is clear to me, leaving:>

> - 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.

I think I see the idea. But I take it you didn't mean to have:

 >   def _validate_args(self):
 >     super(_BaseClass, self)._validate_args()

within a method of _BaseClass (a subclass of object), as that will 
produce:
AttributeError: 'super' object has no attribute '_validate_args'


>>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.


OK, thanks. But I'm still not quite there.

Consider this example code:

class _OneUnderBase(object):
     def __init__(self):
         if type(self) == _OneUnderBase:
             print "From _OneUnderBase"
         else:
             print "From subclass",

class __TwoUnderBase(object):
     def __init__(self):
         if type(self) == __TwoUnderBase:  # What to write here
             print "From __TwoUnderBase"
         else:
             print "From subclass",

class Sub1(_OneUnderBase):
     def __init__(self):
         super(Sub1, self).__init__()
         print "Sub1"

class Sub2(__TwoUnderBase):
     def __init__(self):
         super(Sub2, self).__init__()
         print "Sub2"

s1 = Sub1()
s2 = Sub2()


When run, this gives:

 From subclass Sub1

Traceback (most recent call last):
   File "C:/Python24/foofoofoo.py", line 26, in -toplevel-
     s2 = Sub2()
   File "C:/Python24/foofoofoo.py", line 22, in __init__
     super(Sub2, self).__init__()
   File "C:/Python24/foofoofoo.py", line 10, in __init__
     if type(self) == __TwoUnderBase:  # What to write here
NameError: global name '_TwoUnderBase__TwoUnderBase' is not defined
 >>>

What should I write in the if test of __TwoUnderBase.__init__() to 
make it work? (Nevermind the desired behaviour here could be obtained 
without the type test. How to work that test is the point I'm 
interested in.)

Thanks,

Brian vdB




More information about the Tutor mailing list