Implementing class attribute access methods via pseudo-function overloading.

D

Doran_Dermot

Hi All,

I've seen lots of code in which the attributes of a class are accessed and
modified using two separate methods. For example:

class Problems:
def __init__( self, refNum ):
self._refNum = refNum
self._title = ""
self._problem = ""

def setTitle( self, title="" ):
self._title = title

def setProblem( self, problem="" ):
self._problem = problem

def getTitle( self ):
return self._title

def getProblem( self ):
return self._problem

I prefer to use the following implementation that simulates function
overloading (an OOP feature that I like and that Python does not support):

class Problems:

def __init__( self, refNum ):
self._refNum = refNum
self._title = ""
self._problem = ""

def title( self, title=None ):
if title == None:
return self._title
self._title = title

def problem( self, problem=None ):
if problem == None:
return self._problem
self._problem = problem

This approach reduces the number of required accessor methods by 50% (bit of
an obvious statement I know). I also think that it this allows you to write
cleaner looking code. For Example:

theProblem = Problems( "12345" )

print "Title: ", theProblem.title()
print "Problem: ", theProblem.problem()

theProblem.title( "Java affecting adoption of Python." )
theProblem.problem( "Developers are more inclined to use Java instead of
Python due to the fact that Java is seen as a defacto standard." )

print "Title: ", theProblem.title()
print "Problem: ", theProblem.problem()


Am I correct in stating that Python does not support function overloading?
Have I been hiding under a rock and not noticed the thousands of examples
that illustrate this approach?
Any comments are welcome!
Cheers!!
Dermot Doran
EMC2 GTS Solutions Level 2
Office: +31-20-7768439
Mobile: +31-6-55815258
 
M

Michael Hoffman

I've seen lots of code in which the attributes of a class are accessed and
modified using two separate methods. For example:

I think this is a great illustration of what properties can be used for:

http://www.python.org/2.2.2/descrintro.html#property

Then you can reduce your class to:

class Problems:
def __init__(self, refNum):
self._refNum = refNum

This is a LOT less code.

And use theProblem.title, theProblem.problem without any apparent
function calls. As far as those fancy accessor methods go, YAGNI. If you
do need them later, you can always add them:

def _get_title(self):
return self._title

def _set_title(self, title):
assert isinstance(title, basestring)
self._title = title

title = property(_get_title, _set_title)

I would much rather use theProblem.title = "the title" rather than
theProblem.title("the title").
 
D

Daniel Dittmar

def title( self, title=None ):
if title == None:
return self._title
self._title = title

You probably meant
def title( self, title=None ):
if title == None:
return self._title
else:
self._title = title

or every read access would clear the attribute.

1. Some people dislike methods that do very different things depending
on the parameters. These are difficult to explain. Though in your case,
one central explanation and links from all the methods should be enough.

2. None is often a useful value, so perhaps you should use a module
local variable like _GetValue (actual value is irrelevant)
def title (self, title = _GetValue):

Daniel
 
D

Diez B. Roggisch

Am I correct in stating that Python does not support function overloading?
Have I been hiding under a rock and not noticed the thousands of examples
that illustrate this approach?

No, you are basically right - there is no implicit type-based dispatch in
python. There are some recipes for that, but basically they do the same
you to - check for arguments types, and dispatch accordingly
Any comments are welcome!

Why don't you use properties? That even spares you the () for accessing
variables, and allows direct left-hand-side assignment:

class Foo(object):
def __init__(self):
self._bar = "bar"

def _g_bar(self):
return self._bar

def _s_bar(self, value):
self._bar = value

bar = property(_g_bar, _s_bar)

f = Foo()

print f.bar
f.bar = "baz"

print f.bar


I really prefer that over all other mechanisms, and it allows for bar not
beeing simply stored in the object itself, but instead e.g. fetched lazily
from a database or received/transmitted over a network.
 
D

Duncan Booth

Am I correct in stating that Python does not support function
overloading? Have I been hiding under a rock and not noticed the
thousands of examples that illustrate this approach?

Have you considered writing your example this way:

class Problems:
def __init__( self, refNum ):
self._refNum = refNum
self.Title = ""
self.Problem = ""

Now you can write your code as:

theProblem = Problems( "12345" )

print "Title: ", theProblem.Title
print "Problem: ", theProblem.Problem

theProblem.Title = "Java affecting adoption of Python."
theProblem.Problem = '''Developers are more inclined to use Java instead of
Python due to the fact that Java is seen as a defacto standard.'''

This is much clearer than wrapping your attributes up in accessor and
mutator functions and doesn't lose you *anything*. If your code ever
evolves to the point where you need to intercept the attribute access or
mutation then you simply change the affected attributes into properties,
but there is no need to make them properties until this happens.

Python does support function overloading (if you care to write a library
that implements it), but in general it isn't needed. Some languages use
overloading primarily as a means of specifying default arguments (in fact
that is all you did in your example) and Python already has default
arguments. Alternatively you might use overloading to allow different types
to be passed to a function, but Python will already let you do this. If the
function implementations are significantly different then it may mean that
overloading isn't appropriate anyway. If the function implementations are
largely the same then you may be able to share the definition in Python,
possibly with a line or two to sort out the argument types.

It can often be clearer to use different names for functions instead of
overloading them as the names can be used to hint at the type of argument
expected. Doing it this way also means that you can 'overload' on semantics
rather than just the type.

For example consider the function buildFrobozz(x) which I want to overload
to accept either a string or a filename. Oops! I can't use overloaded
functions for that, I have to call my methods buildFrobozzFromString(s) and
buildFrobozzFromFilename(fname). Now I add another function that builds a
frobozz from an open file. Calling it buildFrobozzFromFile(f) doesn't seem
to me to be losing anything.

(Actually, I would probably make all of those class methods of the Frobozz
class and call them fromString, fromFilename, fromFile for a bit more
brevity.)
 
M

Michael Hoffman

Daniel said:
You probably meant
def title( self, title=None ):
if title == None:
return self._title
else:
self._title = title

or every read access would clear the attribute.

No, the OP was right here--the return occurs before the attribute can be
set.
 
V

Ville Vainio

Duncan> theProblem.Title = "Java affecting adoption of Python."

....

Duncan> This is much clearer than wrapping your attributes up in
Duncan> accessor and mutator functions and doesn't lose you
Duncan> *anything*. If your code ever evolves to the point where
Duncan> you need to intercept the attribute access or mutation
Duncan> then you simply change the affected attributes into
Duncan> properties, but there is no need to make them properties
Duncan> until this happens.

I felt this is something worth highlighting - in Java you *need* to
implement accessors because you can't convert direct attribute access
to accessor methods if/when you are start to second-guess the
design. In Python (and some other languages) you don't need to do
that.

That's yet another "guilt" that must be washed away from aspiring
Pythonista's minds, just like while 1, if cond: break...
 
L

Lonnie Princehouse

Am I correct in stating that Python does not support function overloading?

Technically, yes. Two methods with the same name can't coexist in the
same namespace. Overloading makes sense in C++ because the compiler
is able to decide which function to use at compile time based on
number and type of arguments. Python is (a) not compiled and (b) not
statically typed, so overloading as a part of the language makes a lot
less sense.

You yourself have demonstrated why overloading isn't necessary: A
function can implement its own dispatch mechanism when invoked, based
on inspection of the arguments passed to it.

Additionally, considering that one can write functions with totally
arbitrary calling sequences,

def foo(*args, **keywords):
...

....you can go _beyond_ the C++ notion of overloading --- a mechanism
that only takes number and type of arguments into account.

As an example, here's one common way of simulating overloading with
Python. We'll dispatch to functions that follow a certain naming
convention based on the class name of the argument:

def foo(arg):
try:
subfunc = eval("foo_%s" % arg.__class__.__name__)
except:
subfunc = foo_default
return subfunc(arg)

def foo_default(arg):
print "default foo behavior"

def foo_int(arg):
print "argument is an integer"

def foo_str(arg):
print "argument is a string"


foo('hello world')

foo({}) # we didn't implement foo_dict
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top