简体   繁体   中英

What is the proper way to make class data inheritable in python?

I'm new-ish to Python and coming from the Perl universe.

I'm trying to determine what the best practice is regarding the storage and access to class data so that it can be inherited and potentially extended by a subclass. Reading the Python 2.7 docs (I'm stuck using 2.6 really), Dive In to Python and past questions here, the answer to this is not clear.

In python pseudo code something like...

class baseClass:
    'DataMap' = {
        'key1': 'val1',
        'key2': 'val2',
        'key3': 'val2',
    }

class subClass1(baseClass): # has access to DataMap
    def myfunc:
        ...
        if DataMap[x] == 'val2':
            print 'foo' # if x equals 'key2' according to the data map
        y = DataMap['key4'] # error!
        ...

class subClass2(baseClass): # appends values to base DataMap
    DataMap['key4'] = 'val4'
    def myfunc:
        ...
        if DataMap[x] == 'val4':
            print 'foo' # if x equals 'key4' according to the data map
        elif DataMap[x] == 'val2':
            print 'bar' # if x equals 'key2' according to the data map
        ...

What I wrote above is somewhat Perl minded in that direct class data access is common and mostly encouraged because of the overhead to calling a method. I'm getting the feeling that approach isn't very pythonic though, but I wanted a sanity check to be sure.

Should DataMap, though immutable once compiled, reside in a class function where subClass1 would get that data via a class method when inheriting baseClass and subClass2 could override that same method to append/merge its datamap with the base?

Your insights and wisdom is appreciated.

Just so you know, using an mutable object like a dict as a default argument or outside of something like an __init__ method may not behave the way that you think it will.

As a simple example:

class A(object):
    a = {'foo':1}

a = A()
a.a['bar'] = 2

b = A()
print b.a

So now, ba is {'foo': 1, 'bar': 2} , even though you would expect it to be just {'foo':1}

For that reason, it's common to put mutable data inside the class's __init__ function. Eg

class A(object):
    def __init__(self):
        self.a = {'foo':1}

a = A()
a.a['bar'] = 2

b = A()
print b.a

If you define:

class baseClass:
    DataMap = {
        'key1': 'val1',
        'key2': 'val2',
        'key3': 'val2',
    }

then baseClass.__dict__ contains 'DataMap': {'key3': 'val2', 'key2': 'val2', 'key1': 'val1'} .

This makes it impossible to involve DataMap is class inheritance, since if you later define

class subClass2(baseClass): # appends values to base DataMap
    DataMap = {'key4':'val4'}

then subClass2.__dict__ has its own competing entry with key 'DataMap' . If s = subClass2() is an instance of subClass2 , then s.DataMap will access only the DataMap in subClass2.__dict__ and upon finding it, will never look in baseClass.__dict__ . So no inheritance occurs.

You could modify baseClass.__dict__ inside subClass2 , but that would violate OOP principles since a child class should not modify its parent. And that would not be inheritance anyway, since changes to baseClass.__dict__ would affect all instances of baseClass and all subclasses that use its DataMap .


Perhaps you can achieve what you are looking for by subclassing DataMap itself:

class DataMap(object):  
    key1='val1'
    key2='val2'
    key3='val2'

class subDataMap(DataMap):  
    key4='val4'

class baseClass(object):
    dataMap=DataMap

class subClass1(baseClass): 
    def myfunc(self,x):
        val=getattr(self.dataMap,x) 
        if val == 'val2':
            print 'foo' 

class subClass2(baseClass): 
    dataMap=subDataMap
    def myfunc(self,x):
        val=getattr(self.dataMap,x)
        if val == 'val4':
            print 'foo' 
        elif val == 'val2':
            print 'bar' 

s=subClass1()
s.myfunc('key2')
# foo
try:
    s.myfunc('key4')
except AttributeError as err:
    print(err)
    # subClass1 instance has no attribute 'key4'

s2=subClass2()
s2.myfunc('key2')
# bar
s2.myfunc('key4')
# foo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM