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@python.org > http://mail.python.org/mailman/listinfo/tutor > > _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor