473,382 Members | 1,353 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,382 software developers and data experts.

Default attribute values pattern

A situation that often comes up is having to initialize several
instance attributes that accept a default value. For a single class,
passing the default values in __init__ is fine:

class Base(object):
def __init__(self, x=0, y=None):
self.x = x
self.y = y

For inherited classes that need to override __init__ while keeping a
compatible interface though, the default values have to be repeated:

class Derived(Base):
def __init__(self, x=0, y=None, z=''):
super(Derived,self).__init__(self,x,y)
self.z = ''

For just two attributes and two classes that's maybe not too bad but
for many attributes and/or derived classes that may span multiple
modules, that doesn't seem to scale from a maintenance point of view,
especially if the defaults change over time.

A pattern I've been using lately instead is store the defaults in
class attributes and let __init__ accept keyword arguments:

class Base(object):

x = 0
y = None

def __init__(self, **kwds):
setattrs(self, kwds)

where setattrs is:

def setattrs(self, attrvals, strict=True):
if strict:
# raise AttributeError if some attr doesn't exist already
for attr in attrvals.iterkeys():
getattr(self,attr)
for attr,val in attrvals.iteritems():
setattr(self, attr, val)

This way, only the new and overriden default attributes have to
repeated in derived classes:

class Derived(Base):

x = 1
z = ''

def __init__(self, **kwds):
super(Derived,self).__init__(**kwds)
print 'In Derived.__init__'
Is this a good way of doing it ? Is there a better pattern ?

George
Jan 19 '08 #1
7 1429
Hello,

Seems to me that setattrs sort of assumes that you want to have all your
initialization arguments set as attributes of the same name. I would think
you'd sometimes want to be able to process the extra arguments inside of each
__init__, assign them to attributes with different names, etc.

My approach would be to treat each __init__ as a wrapping function, grabbing
the items it needs out of the keyword dictionary and then calling the next
__init__. Curious to hear other approaches though:
def Grab(argdict, key, default):
"""Like argdict.get(key, default), but also deletes key from argdict."""
if key in argdict:
retval = argdict["key"]
del(argdict[key])
else:
retval = default
return retval
class Base(object):
def __init__(self, x=0, y=None):
print "in Base init"
self.x = x
self.y = y
class Derived1(Base):
def __init__(self, **kwargs):
print "in Derived1 init"
self.z = Grab(kwargs, "z", None)
super(Derived1, self).__init__(**kwargs)
class Derived2(Derived1):
def __init__(self, **kwargs):
print "in Derived2 init"
self.a = Grab(kwargs, "a", 0)
self.b = Grab(kwargs, "b", False)
super(Derived2, self).__init__(**kwargs)
print self.__dict__
newthing = Derived2(x=234, y="blah", a=55555)
On Jan 19, 2008 10:14 AM, George Sakkis <ge***********@gmail.comwrote:
A situation that often comes up is having to initialize several
instance attributes that accept a default value. For a single class,
passing the default values in __init__ is fine:

class Base(object):
def __init__(self, x=0, y=None):
self.x = x
self.y = y

For inherited classes that need to override __init__ while keeping a
compatible interface though, the default values have to be repeated:

class Derived(Base):
def __init__(self, x=0, y=None, z=''):
super(Derived,self).__init__(self,x,y)
self.z = ''

For just two attributes and two classes that's maybe not too bad but
for many attributes and/or derived classes that may span multiple
modules, that doesn't seem to scale from a maintenance point of view,
especially if the defaults change over time.

A pattern I've been using lately instead is store the defaults in
class attributes and let __init__ accept keyword arguments:

class Base(object):

x = 0
y = None

def __init__(self, **kwds):
setattrs(self, kwds)

where setattrs is:

def setattrs(self, attrvals, strict=True):
if strict:
# raise AttributeError if some attr doesn't exist already
for attr in attrvals.iterkeys():
getattr(self,attr)
for attr,val in attrvals.iteritems():
setattr(self, attr, val)

This way, only the new and overriden default attributes have to
repeated in derived classes:

class Derived(Base):

x = 1
z = ''

def __init__(self, **kwds):
super(Derived,self).__init__(**kwds)
print 'In Derived.__init__'
Is this a good way of doing it ? Is there a better pattern ?

George
--
http://mail.python.org/mailman/listinfo/python-list


--
-David
Jan 19 '08 #2
On Jan 19, 11:02*pm, "David Tweet" <davidtw...@gmail.comwrote:
def Grab(argdict, key, default):
* """Like argdict.get(key, default), but also deletes key from argdict."""
* if key in argdict:
* * retval = argdict["key"]
* * del(argdict[key])
* else:
* * retval = default
* return retval
Dictionaries already have a method for this. It's called pop. It's a
good idea to have a look at methods of builtin types before
reimplementing the wheel!

Grab(argdict, key, default) is argdict.pop(key, default)

--
Arnaud

Jan 20 '08 #3
Ah! nice, thanks, knew I was probably missing something.

On Jan 19, 2008 5:01 PM, Arnaud Delobelle <ar*****@googlemail.comwrote:
On Jan 19, 11:02pm, "David Tweet" <davidtw...@gmail.comwrote:
def Grab(argdict, key, default):
"""Like argdict.get(key, default), but also deletes key from argdict."""
if key in argdict:
retval = argdict["key"]
del(argdict[key])
else:
retval = default
return retval

Dictionaries already have a method for this. It's called pop. It's a
good idea to have a look at methods of builtin types before
reimplementing the wheel!

Grab(argdict, key, default) is argdict.pop(key, default)

--
Arnaud
--
http://mail.python.org/mailman/listinfo/python-list


--
-David
Jan 20 '08 #4
David Tweet a écrit :
(<ot>please, don't top-post</ot>)
>
def Grab(argdict, key, default):
cf pep08 for naming conventions...
"""Like argdict.get(key, default), but also deletes key from argdict."""
if key in argdict:
retval = argdict["key"]
del(argdict[key])
else:
retval = default
return retval
def grab(kw, key, default=None):
try:
return kw.pop(key)
except KeyError:
return default

(snip)
Jan 21 '08 #5
Grab(argdict, key, default) is argdict.pop(key, default)

"pop() raises a KeyError when no default value is given and the key is
not found."
def grab(kw, key, default=None):
try:
return kw.pop(key)
except KeyError:
return default
So Bruno's technique seems to me to be the correct one as it catches
the KeyError.
Jan 21 '08 #6
On Jan 21, 10:09*am, cokofree...@gmail.com wrote:
Grab(argdict, key, default) is argdict.pop(key, default)

"pop() raises a KeyError when no default value is given and the key is
not found."
And it doesn't if a default is provided, which is always the case in
the uses of Grab(...), so it seems the right tool for the job.
def grab(kw, key, default=None):
* *try:
* * *return kw.pop(key)
* *except KeyError:
* * *return default

So Bruno's technique seems to me to be the correct one as it catches
the KeyError.
If you really really want to write a grab function (IMHO pop is good
enough):

def grab(kw, key, default=None):
return kw.pop(key, default)

--
Arnaud
Jan 21 '08 #7
co*********@gmail.com a écrit :
>Grab(argdict, key, default) is argdict.pop(key, default)

"pop() raises a KeyError when no default value is given and the key is
not found."
Then use it with a default value !-)
>def grab(kw, key, default=None):
try:
return kw.pop(key)
except KeyError:
return default

So Bruno's technique seems to me to be the correct one as it catches
the KeyError.
Note that I cancelled the message (too bad, doesn't work everywhere). I
totally agree with Arnaud on this, and should sometimes re-read the doc
for stuff I use so often I think I know them.
Jan 21 '08 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: UndoMiel | last post by:
Hi, I have a situation where i would like to validate the occurance of certain elements, based on the value of an attribute. What is the "best" way to handle such validations? I am fairly new...
4
by: Lénaïc Huard | last post by:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello, I've some namespace problems when defining default values for attributes. My problem seems to come from the fact that the attributes are...
0
by: pathisunil | last post by:
Dear All I have an xmldocument which is as formed below. It is a bit of loopy in nature. can anyone kindly let me know how can i write a xslt which would take a parameter which is an attribute...
2
by: Bill Cohagan | last post by:
In my app I'm validating an XML file against an XSD which contains several attribute default value specifications. I'm performing the validation via an xml document load() using a...
12
by: Stefano | last post by:
Hi all, what is the correct use of the "default" attribute in XML Schema? For example: <xs:element name="myProperty" type="xs:string" default="myDefaultValue"/> What can I do with it? What...
0
by: pathisunil | last post by:
Dear All I have an xmldocument which is as formed below. It is a bit of loopy in nature. can anyone kindly let me know how can i write a xslt which would take a parameter which is an...
44
by: gregory.petrosyan | last post by:
Hello everybody! I have little problem: class A: def __init__(self, n): self.data = n def f(self, x = ????) print x All I want is to make self.data the default argument for self.f(). (I
4
by: Dave Burns | last post by:
Hello, I am trying to specify a logical default value for a in a WCF Web Service using basicHttpBinding. I realize that the language defaults are: int - 0 string - null bool - false
14
by: Roedy Green | last post by:
Is there a shortcut way to define the default font family (and characteristics) to be applied to all styles? -- Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.