Python: Nested Class Inheritance

2019-08-27 19:13发布

问题:

Would it be OK to declare an instance of the sub-classed class from its Base (super?) class as I do it here:

if 'classB_args' in dictArg.keys() and dictArg['classB_args']:
    self['classB']=ClassA( dictArg['classB_args'] )

Are there any side effects of doing so? What should I be aware before moving forward. I have a feeling sooner or later something would go wrong... with cPickle , pickle or may be it would be a PyQt drag-and-dropt?.. if so then why would the problem arise?

class Base(dict):
    def __init__(self, *args, **kwargs):
        super(Base, self).__init__(*args, **kwargs)
        self.setdefault('id', -1)
        self.setdefault('name', None)
        self.setdefault('classB', None)

        if not args or len(args)==0: return
        dictArg=args[0]

        if 'classB_args' in dictArg.keys() and dictArg['classB_args']:
            self['classB']=ClassA( dictArg['classB_args'] )

    def getClassB(self):
        return self['classB']

class ClassA(Base):
    def __init__(self, *args, **kwargs):
        if not (args or kwargs):   raise Exception('you need to give me *something*!')
        super(ClassA, self).__init__(*args, **kwargs)
        self.setdefault('win', None)
        self.setdefault('mac', None)

myDictArg= {'id':1, 'name':'MyName', 'win':'c:/windows', 'mac': '/Volumes/mac/', 'classB_args': {'id':1, 'name':'MyProject'}}

myInstance=ClassA(myDictArg)
print myInstance.getClassB()

回答1:

If you're asking whether it will work, the answer is yes, but I can't think of a situation where it is a good idea. The reason is that this locks your base class down to being really only useful with ClassA ... I think that the solution would probably be cleaner to do something like:

myDictArg = {'id':1, 'name':'MyName', 'win':'c:/windows', 'mac': '/Volumes/mac/', 'classB': ClassA(id=1, name='MyProject')}

and forgo all of the extra classB_args craziness in Base.__init__. It's more explicit so the user ends up knowing what to expect.

If you really don't like that, you could use the type of self to determine what to use rather than specifying ClassA directly which is a little better:

self['classB'] = type(self)(dictArg['classB_args'])

Now, if you derive a new class from Base, that will be used instead:

class Foo(Base): pass

instance = Foo(myDictArg)
print type(instance.getClassB())  # Foo !

a few other non-related points.

  1. Don't do x in dct.keys() -- It's horribly inefficient in python2.x. You can just do x in dct :-).
  2. Generally speaking, writing simple wrappers like getClassB are considered "unpythonic". You can just access the data directly in python.
  3. You can rewrite the if clause to clean it up a little:

Here's how:

   if 'classB_args' in dictArg.keys() and dictArg['classB_args']:
        self['classB']=ClassA( dictArg['classB_args'] )

goes to:

   # with this, you can remove the `self.setdefault('classB', None)` statement.
   item = dictArg.get('classB_args')
   self['classB'] = type(self)(item) if item else item