A java hobbyist programmer learning python

E

elhombre

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
 
C

Chris Rebert

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
 
P

Paul Rubin

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.
 
C

Chris Rebert

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.

Cheers,
Chris
 
J

John Machin

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
 
S

Steven D'Aprano

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
 
E

elhombre

Chris Rebert said:
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.
 
E

elhombre

Paul Rubin said:
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.


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.
 
E

elhombre

John Machin said:
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

Thanks John.
 
E

elhombre

Steven D'Aprano said:
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

Excellent links. Thanks Steven !
 
R

Rhodri James

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

:)
 
A

Aahz

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.
 
T

TheFlyingDutchman

* 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."
 
T

TheFlyingDutchman

        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.
 
T

TheFlyingDutchman

        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
        (e-mail address removed)         (e-mail address removed)
                HTTP://wlfraed.home.netcom.com/
        (Bestiaria Support Staff:               (e-mail address removed))
                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.
 
T

Tim Rowe

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.
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,128
Latest member
ElwoodPhil
Top