Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A java hobbyist programmer learning python

3 views
Skip to first unread message

elhombre

unread,
Jan 17, 2009, 8:11:45 PM1/17/09
to
Hello, below is my first fragment of working python code. As you can see it
is very java like as that is all I know. Is this the right approach to be
taking?
Should I be taking a different approach? Thanks in advance.

import sys

class Calculator():

def __init__(self):
self.operator = sys.argv[1]
self.arg1 = sys.argv[2]
self.arg2 = sys.argv[3]

def getOperator(self):
return sys.argv[1]

def getArg1(self):
return sys.argv[2]

def getArg2(self):
return sys.argv[3]

def calculate(self):
if self.getOperator() == '+' :
return int(self.getArg1()) + int(self.getArg2())
elif self.getOperator() == '*' :
return int(self.getArg1()) * int(self.getArg2())
elif self.getOperator() == '/' :
return int(self.getArg1()) / int(self.getArg2())
elif self.getOperator() == '-' :
return int(self.getArg1()) - int(self.getArg2())
else:
return 'Wrong argument supplied'

x = Calculator()
y = x.calculate()
print y

Chris Rebert

unread,
Jan 17, 2009, 8:27:56 PM1/17/09
to elhombre, pytho...@python.org
On Sat, Jan 17, 2009 at 5:11 PM, elhombre <elh...@ozemail.com.au> wrote:
> Hello, below is my first fragment of working python code. As you can see it
> is very java like as that is all I know. Is this the right approach to be
> taking?
> Should I be taking a different approach? Thanks in advance.
>
> import sys
>
> class Calculator():
>
> def __init__(self):
> self.operator = sys.argv[1]
> self.arg1 = sys.argv[2]
> self.arg2 = sys.argv[3]
>
> def getOperator(self):
> return sys.argv[1]
>
> def getArg1(self):
> return sys.argv[2]
>
> def getArg2(self):
> return sys.argv[3]

Delete the 3 Java-ish accessor methods; good Python style just uses
the attributes directly (i.e. self.operator instead of
self.getOperator()).

>
> def calculate(self):
> if self.getOperator() == '+' :
> return int(self.getArg1()) + int(self.getArg2())
> elif self.getOperator() == '*' :
> return int(self.getArg1()) * int(self.getArg2())
> elif self.getOperator() == '/' :
> return int(self.getArg1()) / int(self.getArg2())
> elif self.getOperator() == '-' :
> return int(self.getArg1()) - int(self.getArg2())
> else:
> return 'Wrong argument supplied'

Rather than have a long if-elif-else chain like this, you can use a
dictionary with functions as values. For example:

def add(x, y):
return x + y

def sub(x, y):
return x - y

OPER2FUNC = {'+' : add, '-' : sub}
print OPER2FUNC['+'](3,4) #==> 7

You can use the same technique with the functions in the `operator`
module to significantly shorten your calculate() method.

Cheers,
Chris

--
Follow the path of the Iguana...
http://rebertia.com

Paul Rubin

unread,
Jan 17, 2009, 8:53:06 PM1/17/09
to
Chris Rebert <cl...@rebertia.com> writes:
> > class Calculator(): ...

> Delete the 3 Java-ish accessor methods; good Python style just uses
> the attributes directly (i.e. self.operator instead of
> self.getOperator()).

I think I would get rid of the whole Calculator class unless there was
a good reason to keep it (i.e. you are going to have several
Calculators active in the program simultaneously). Just write
straightforward imperative code without bothering with the OO stuff
that is mandatory in Java.

> Rather than have a long if-elif-else chain like this, you can use a
> dictionary with functions as values. For example:
>
> def add(x, y):
> return x + y

These functions are already defined in the operator module, and you
can also define them inline with the lambda operator.

Here is my version of the program:

import sys
from operator import add, mul, sub, div

op, x, y = sys.argv[1:4]

opdict = {'+': add, '*': mul, '-': sub, '/': div}

try:
func = opdict[op]
except KeyError:
print 'wrong argument supplied'
sys.exit()

print func(int(x), int(y))

Note that like the original, it doesn't check for valid numeric args.

Chris Rebert

unread,
Jan 17, 2009, 9:01:10 PM1/17/09
to pytho...@python.org
On Sat, Jan 17, 2009 at 5:53 PM, Paul Rubin
<"http://phr.cx"@nospam.invalid> wrote:

> Chris Rebert <cl...@rebertia.com> writes:
>> Rather than have a long if-elif-else chain like this, you can use a
>> dictionary with functions as values. For example:
>>
>> def add(x, y):
>> return x + y
>
> These functions are already defined in the operator module, and you
> can also define them inline with the lambda operator.

Did you completely skip over the last sentence of my email? I
specifically mentioned the `operator` module.

John Machin

unread,
Jan 17, 2009, 9:04:47 PM1/17/09
to
On Jan 18, 12:11 pm, "elhombre" <elhm...@ozemail.com.au> wrote:
> Hello, below is my first fragment of working python code. As you can see it
> is very java like as that is all I know. Is this the right approach to be
> taking?
> Should I be taking a different approach? Thanks in advance.
>
> import sys
>
> class Calculator():
>
>     def __init__(self):
>         self.operator = sys.argv[1]
>         self.arg1 = sys.argv[2]
>         self.arg2 = sys.argv[3]

Try this:

def __init__(self, operator, arg1, arg2):
self.operator = operator
self.arg1 = arg1
self.arg2 = arg2

Then you can do
x1 = Calculator('+', '1.0', '2.0')
x2 = Calculator('-', '666', '42')
or
x3 = Calculator(*sys.argv[1:4])
if you're really desperate to use the command line args.

>
>     def getOperator(self):
>         return sys.argv[1]

Chris has already told you to give such accessor functions the flick,
but it should have done
return self.operator

Steven D'Aprano

unread,
Jan 17, 2009, 9:24:51 PM1/17/09
to
On Sun, 18 Jan 2009 11:11:45 +1000, elhombre wrote:

> Hello, below is my first fragment of working python code. As you can see
> it is very java like as that is all I know. Is this the right approach
> to be taking?

You might find it very useful to read:

http://dirtsimple.org/2004/12/python-is-not-java.html

http://dirtsimple.org/2004/12/java-is-not-python-either.html

> Should I be taking a different approach? Thanks in advance.

This is obviously a very minimal program, so I won't criticise you for
failing to do any error checking :-) However, I will make some broad
points:

* No getters and setters. Python takes a very permissive approach to
class attributes, taking the philosophy "we're all adults here". It's
easy to change a public attribute to a private attribute with a getter/
setter if you need to, so there's nothing to be gained by writing getters
for straight attribute access. It just makes things slow.

* Don't return error values, raise an exception. Setting up a
try...except block is really fast in Python, almost as fast as a pass
statement (according to my tests). Catching the exception itself is slow,
but most of the time you won't care about that.

Let me re-write your code in a more Pythonic way. This is not the only
way to do this, and it probably isn't the best way, but it may give you a
flavour for the way Python is usually written.


import sys
import operator

class Calculator():
dispatch = { # dispatch table mapping symbol to function
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv,


}
def __init__(self):
self.operator = sys.argv[1]

self.arg1 = int(sys.argv[2])
self.arg2 = int(sys.argv[3])
def calculate(self):
func = self.dispatch[self.operator]
return func(self.arg1, self.arg2)


if __name__ == '__main__':
# run this block only when running as a script, not
# when the module is being imported (say, for testing).
x = Calculator('+', 23, 42)
try:
y = x.calculate()
except KeyError:
print "Unrecognised operator '%s'" % x.operator
else:
print y


--
Steven

elhombre

unread,
Jan 18, 2009, 2:12:45 AM1/18/09
to
"Chris Rebert" <cl...@rebertia.com> wrote in message
news:mailman.7468.1232242...@python.org...

> On Sat, Jan 17, 2009 at 5:11 PM, elhombre <elh...@ozemail.com.au> wrote:
...

>
> Rather than have a long if-elif-else chain like this, you can use a
> dictionary with functions as values. For example:
>
> def add(x, y):
> return x + y
>
> def sub(x, y):
> return x - y
>
> OPER2FUNC = {'+' : add, '-' : sub}
> print OPER2FUNC['+'](3,4) #==> 7
>
> You can use the same technique with the functions in the `operator`
> module to significantly shorten your calculate() method.
>
> Cheers,
> Chris

Thanks very much Chris. That is much more concise ! I have a lot of reading
to do and a different mindset to work towards.

elhombre

unread,
Jan 18, 2009, 2:16:04 AM1/18/09
to

"Paul Rubin" <http://phr...@NOSPAM.invalid> wrote in message
news:7xy6x9n...@ruckus.brouhaha.com...


Good point about the class. I really only did that to begin to learn the
class syntax. I had not added any exception handling as I was taking it a
step at a time. Most of the first few hours were spent mucking around with
TextMate, Netbeans and Wing IDE. I finally got Netbeans working to the point
where something would run.

Thanks very much Paul.

elhombre

unread,
Jan 18, 2009, 2:16:39 AM1/18/09
to
"John Machin" <sjma...@lexicon.net> wrote in message
news:5d2c588a-9b01-4a85...@o40g2000prn.googlegroups.com...

Thanks John.
>

elhombre

unread,
Jan 18, 2009, 2:17:09 AM1/18/09
to

"Steven D'Aprano" <st...@REMOVE-THIS-cybersource.com.au> wrote in message
news:0182896d$0$8693$c3e...@news.astraweb.com...

Excellent links. Thanks Steven !

Rhodri James

unread,
Jan 19, 2009, 7:53:09 PM1/19/09
to pytho...@python.org
On Sun, 18 Jan 2009 02:24:51 -0000, Steven D'Aprano
<st...@remove-this-cybersource.com.au> wrote:

> Let me re-write your code in a more Pythonic way. This is not the only
> way to do this, and it probably isn't the best way, but it may give you a
> flavour for the way Python is usually written.
>
>
> import sys
> import operator

> class Calculator():
> dispatch = { # dispatch table mapping symbol to function
> '+': operator.add,
> '-': operator.sub,
> '*': operator.mul,
> '/': operator.truediv,
> }
> def __init__(self):
> self.operator = sys.argv[1]
> self.arg1 = int(sys.argv[2])
> self.arg2 = int(sys.argv[3])

If you want the test code to work, I think you mean:

def __init__(self, op, arg1, arg2):
self.operator = op


self.arg1 = arg1
self.arg2 = arg2

:)
--
Rhodri James *-* Wildebeeste Herder to the Masses

Aahz

unread,
Jan 22, 2009, 10:11:53 PM1/22/09
to
In article <7xy6x9n...@ruckus.brouhaha.com>,
Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
>Chris Rebert <cl...@rebertia.com> writes:
>>attribution deleted by Paul Rubin:

>>>
>>> class Calculator(): ...
>>
>> Delete the 3 Java-ish accessor methods; good Python style just uses
>> the attributes directly (i.e. self.operator instead of
>> self.getOperator()).
>
>I think I would get rid of the whole Calculator class unless there
>was a good reason to keep it (i.e. you are going to have several
>Calculators active in the program simultaneously). Just write
>straightforward imperative code without bothering with the OO stuff
>that is mandatory in Java.

IMO "good reason" is simply that using a class makes keeping track of
namespaces easier, e.g. if you add a memory capability. I think that if
there's clearly an object that you will be manipulating, a class is
usually the right approach even if it doesn't look like it's needed.
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

Weinberg's Second Law: If builders built buildings the way programmers wrote
programs, then the first woodpecker that came along would destroy civilization.

TheFlyingDutchman

unread,
Jan 23, 2009, 4:48:32 AM1/23/09
to

>
> * No getters and setters. Python takes a very permissive approach to
> class attributes, taking the philosophy "we're all adults here". It's
> easy to change a public attribute to a private attribute with a getter/
> setter if you need to, so there's nothing to be gained by writing getters
> for straight attribute access. It just makes things slow.

If adding a getter/setter made data private, then per a tenet of
Object Oriented Programming, there would be something to be gained
from it. But I don't see getter/setters would do that.

The statically typed object oriented languages, like Java, C++ and C#,
all permit member data and functions to be public - allowing a
programmer to implement a "we're all adults here" programming
philosophy if they so choose. However, they also allow a programmer to
make member data and functions private, thus allowing the
implementation one of the tenets of OOP. I don't use Ruby, a
dynamically typed language like Python, but from a web search it
appears that Ruby does allow at least data to be declared private. But
it appears that a user of a class can get around this private
declaration by writing their own methods and adding them to the class
dynamically.

In his book "Core Python Programming", noted Python expert and PyCon
speaker Wesley J. Chun makes the following statements regarding one of
the main principles of Object Oriented Programming (OOP):

"Encapsulation/Interfaces
Encapsulation describes the concept of data/information hiding and
providing interfaces or accessor functions to the data attributes.
Direct access to data by any client, bypassing the interfaces, goes
against the principles of encapsulation, but the programmer is free to
allow such access. As part of the implementation, the client should
not even know how the data attributes are architected within the
abstraction. In Python, all class attributes are public but names may
be "mangled" to discourage unauthorized access, but otherwise not
prevented. It is up to the designer to provide the appropriate
interfaces to the data so that the client programmer does not have to
resort to manipulating the encapsulated data attributes."

Message has been deleted

TheFlyingDutchman

unread,
Jan 24, 2009, 7:14:18 AM1/24/09
to
On Jan 23, 8:57 am, Dennis Lee Bieber <wlfr...@ix.netcom.com> wrote:
> On Fri, 23 Jan 2009 01:48:32 -0800 (PST), TheFlyingDutchman
> <zzbba...@aol.com> declaimed the following in comp.lang.python:

>
> > abstraction. In Python, all class attributes are public but names may
> > be "mangled" to discourage unauthorized access, but otherwise not
> > prevented. It is up to the designer to provide the appropriate
> > interfaces to the data so that the client programmer does not have to
> > resort to manipulating the encapsulated data attributes."
>
>         Double underscore "mangling" was not implemented to "discourage
> unauthorized access". Its primary purpose is to prevent name space
> conflicts when an extended subclass and its parent class use the same
> name for an attribute, but that attribute is not of the same "meaning".
> Using the __ prefix means BOTH attributes are part of the instance, but
> the subclass only see's its variant and should make calls into
> superclass methods to modify the parent variant.
>
>         Python convention is that a single underscore -- which does NOT
> perform name mangling -- is the indicator meant to "discourage
> unauthorized access".
>

Is there a significant performance hit with using the double
underscore for signifying a variable you want to be private? It seems
like it is advantageous that someone trying for direct access has to
use a different notation, which will help to emphasize that it
shouldn't be access directly.

Message has been deleted

TheFlyingDutchman

unread,
Jan 25, 2009, 9:04:59 PM1/25/09
to
>         If you're building an extension tree, you'll either have to supply
> layers of getter/setter methods, or hand-mangle references to attributes
> defined in the superclass.
>
>         Say you start with a "Point2D" class, and make the X, Y coordinates
> double underscore.
>
>         Now extend it to a "Point3D" class via inheritance. The 3D class
> will not be able to access (set) the X, Y values without a setter method
> defined in the parent OR by unmangling the parent names.
>
>         If you'd used the common convention of single underscore as "don't
> touch if you're an outsider", the 3D extension can be considered an
> insider and directly access the X, Y
>
>         Which would you rather read in a 3D point class derived by extending
> a 2D point?
>
>         def move(self, xmod, ymod, zmod):
>                 self._z += zmod
>                 self._y += ymod
>                 self._x += xmod
>
> or
>
>         def move(self, xmod, ymod, zmod):
>                 super(Point3D, self).move(xmod, ymod)
>                 self._z += zmod
>
> or
>
>         def move(self, xmod, ymod, zmod):
>                 self._Point2D__x += xmod
>                 self._Point2D__y += ymod
>                 self.__z += zmod
>
>         Speaking for myself, I'd prefer the first
> --
>         Wulfraed        Dennis Lee Bieber               KD6MOG
>         wlfr...@ix.netcom.com         wulfr...@bestiaria.com
>                 HTTP://wlfraed.home.netcom.com/
>         (Bestiaria Support Staff:               web-a...@bestiaria.com)
>                 HTTP://www.bestiaria.com/

I like the latter two styles, particularly the last one. That way you
can see at a glance that those member variables are defined in the
super class. But then I am a fan of Hungarian notation, which many
programmers can't stand.

Tim Rowe

unread,
Jan 26, 2009, 6:45:35 AM1/26/09
to pytho...@python.org
> I like the latter two styles, particularly the last one. That way you
> can see at a glance that those member variables are defined in the
> super class.

I like the second style because it makes it leaves the 2-d
implementation hidden, which is the whole point of encapsulation.

> But then I am a fan of Hungarian notation, which many
> programmers can't stand.

Is it that programmers can't stand it, or is it that they can't stand
it when it's imposed when not needed? As a pseudo type system for
languages with no typing it's pretty useful. To the extent that a
language provides typing it's useless verging on dangerous because it
can get out of synch with the actual type. I believe that any case of
Hungarian notation being useful is evidence of a flaw in the language
being used -- but arguably all languages are flawed in some way or
other, so Hungarian /can/ be useful. At this level I don't recognise a
difference between System and Applications Hungarian, by the way --
the difference is eliminated if you declare types corresponding to the
"meanings", which is commonplace in, for example, Ada.

--
Tim Rowe

Scott David Daniels

unread,
Jan 26, 2009, 2:16:53 PM1/26/09
to
Tim Rowe wrote:
> ... I like the second style because it makes it leaves the 2-d

> implementation hidden, which is the whole point of encapsulation.
I like the second as well, in that it it allows the parent to update any
related data structures (for example, updating a display). However, I
am a bit nervous about changing the signature of the move message, and
would be more tempted to add a move3d, for multiple inheritance reasons.

>> But then I am a fan of Hungarian notation, which many
>> programmers can't stand.
>
> Is it that programmers can't stand it, or is it that they can't stand

> it when it's imposed when not needed? ....
Well, I tend to be one who hates Hungarian. I spent a long time being
a fan of strong typing. Then, I felt the compiler would enforce the
typing, and the Hungarian muddied the readability of the expressions.
I felt that you should define a type for distance_in_yards, and not have
that confusable with distance_in_meters (though you might provide an
automatic conversion.

Now, I feel strong-typing systems cannot express the type relationships
that I want as a programmer in the face of sub-typing, and I hold
no hope that (A) such a language will appear, or (B) that the strong
majority of the bugs I produce in Python will be caught by a statically
typed system. I do however, still find the neddling little text
annotations in the variable naming to be irritating noise that distracts
from the readability of the expressions.

The kinds of type systems that I want(ed) is most closely expressed by
F-Bounded polymorphism, and that doesn't manage to be both expressive
enough and computationally feasible to use as a production type system.
For example, I'd like to type a sort function or a project function,
and all I've seen looks like its fit will feel more like a suit of armor
than a shirt.

--Scott David Daniels
Scott....@Acm.Org

0 new messages