Reputation: 413
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.
Upvotes: 1
Views: 215
Reputation: 879351
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
Upvotes: 2
Reputation: 284582
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, b.a
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. E.g.
class A(object):
def __init__(self):
self.a = {'foo':1}
a = A()
a.a['bar'] = 2
b = A()
print b.a
Upvotes: 2