Velocity Reviews > (Very Newbie) Problems defining a variable

# (Very Newbie) Problems defining a variable

MRAB
Guest
Posts: n/a

 12-12-2008
Tim Rowe wrote:
> Since we all seem to be having a go, here's my take. By pulling the
> rates and thresholds into a dictionary I feel I'm getting a step
> closer to the real world, where these would presumably be pulled in
> from a database and the number of interest bands might vary. But is
> there a tidier way to get 'thresholds'? I was a bit surprised that
> rates.keys() didn't give me a list directly, so although the 3.0
> tutorial says "The keys() method of a dictionary object returns a list
> of all the keys used in the dictionary, in arbitrary order (if you
> want it sorted, just apply the sort() method to )" that's not /quite/
> such a given, because "the list of keys" doesn't seem to be there for
> the sorting any more.
>
> Is there a tidy way of making rates and thresholds local to get_rate,
> without recalculating each time? I suppose going object oriented is
> the proper way.
>
> #Py3k,UTF-8
>
> rates = {0: 0.006, 10000: 0.0085, 25000: 0.0124, 50000: 0.0149, 100000: 0.0173}
> thresholds = list(rates.keys())
> thresholds.sort()
> thresholds.reverse()
>

Why are you putting them into a dict at all? Surely a list of tuples is
better?

# I could've just written the list in descending order here!
rates = [(0, 0.006), (10000, 0.0085), (25000, 0.0124), (50000, 0.0149),
(100000, 0.0173)]
thresholds.sort(reversed=True)

> def get_rate(balance):
> for threshold in thresholds:
> if balance >= threshold:
> return rates[threshold]
> else:
> return 0.0
>

def get_rate(balance):
for threshold, rate in thresholds:
if balance >= threshold:
return rate
return 0.0

> balance = int(input("How much money is in your account?\n>>"))
> target = int(input("How much money would you like to earn each year?\n>>"))
>
> if balance <= 0:
> print("You'll never make your fortune that way!\n")
> else:
> interest = 0
> year = 0
> while interest < target:
> rate = get_rate(balance)
> interest = balance * rate
> balance += interest
> year += 1
> print("Year %s, at %s rate: %s paid, %s in bank." % (year,
> rate, interest, balance))
>

John Machin
Guest
Posts: n/a

 12-12-2008
On Dec 13, 4:50*am, Dennis Lee Bieber <(E-Mail Removed)> wrote:
> On Fri, 12 Dec 2008 03:42:55 -0800 (PST), (E-Mail Removed) declaimed the
> following in comp.lang.python:
>
> > #!/usr/bin/python
> > #Py3k, UTF-8

>
> > bank = int(input("How much money is in your account?\n>>"))
> > target = int(input("How much money would you like to earn each year?
> > \n>>"))

>
> * * * * Just for my curiosity -- did Python 3.x (besides turning print into
> a function) also change input() to behave as the old raw_input()?

Yup. There've been some other tectonic plate shift effects, e.g.:

xrange() -> range(); range() -> list(range())
dict.iteritems() -> dict.items(); dict.items() -> list(dict.items())
halfassci() -> repr(); repr() -> ascii()

Tim Rowe
Guest
Posts: n/a

 12-12-2008
2008/12/12 Kirk Strauser <(E-Mail Removed)>:

> def get_rate(balance):
> for threshold, rate in ((100000, .0173),
> (50000, .0149),
> (25000, .0124),
> (10000, .0085),
> (0, .006)):
> if balance > threshold:
> return rate
> return .0

Yes, once it's changed from a dictionary to tuples it becomes easier,
doesn't it? D'oh!

--
Tim Rowe

John Machin
Guest
Posts: n/a

 12-12-2008
On Dec 13, 5:18*am, Kirk Strauser <(E-Mail Removed)> wrote:
> At 2008-12-12T18:12:39Z, "Tim Rowe" <(E-Mail Removed)> writes:
>
>
>
> > Is there a tidy way of making rates and thresholds local to get_rate,
> > without recalculating each time? I suppose going object oriented is
> > the proper way.

>
> > #Py3k,UTF-8

>
> > rates = {0: 0.006, 10000: 0.0085, 25000: 0.0124, 50000: 0.0149, 100000: 0.0173}
> > thresholds = list(rates.keys())
> > thresholds.sort()
> > thresholds.reverse()

>
> > def get_rate(balance):
> > * * for threshold in thresholds:
> > * * * * if balance >= threshold:
> > * * * * * * return rates[threshold]
> > * * else:
> > * * * * return 0.0

>
> How 'bout:
>
> def get_rate(balance):
> * * for threshold, rate in ((100000, .0173),
> * * * * * * * * * * * * * * (50000, .0149),
> * * * * * * * * * * * * * * (25000, .0124),
> * * * * * * * * * * * * * * (10000, .0085),
> * * * * * * * * * * * * * * (0, .006)):
> * * * * if balance > threshold:
> * * * * * * return rate
> * * return .0

(1) you meant "if balance > threshold:"
(2) sequential search can be very fast if the sequence is in
descending order of probability of occurence ... you might like to
consider reversing the order
(3) for a much longer table, binary search using a function from the
bisect module could be considered
(4) in practice, the "default" action would not be "return 0.0";
perhaps something along these lines:

if balance < -overdraft_limit:
raise Exception(...)
return HUGE

Bruno Desthuilliers
Guest
Posts: n/a

 12-12-2008
Tim Rowe a écrit :
> 2008/12/12 Kirk Strauser <(E-Mail Removed)>:
>
>> def get_rate(balance):
>> for threshold, rate in ((100000, .0173),
>> (50000, .0149),
>> (25000, .0124),
>> (10000, .0085),
>> (0, .006)):
>> if balance > threshold:
>> return rate
>> return .0

>
> Yes, once it's changed from a dictionary to tuples it becomes easier,
> doesn't it? D'oh!
>

<comment>
A sequence of pairs and a dict are _almost_ interchangeable (mmm... is
that the correct word ?) representations of a same data set[1] - the
main difference being ordering. If ordering matters, choose a sequence
of pairs as main representation - you can easily build a dict from it
if/when you need it.

[1]
>>> d = dict(a=1, b=2, c=3)
>>> dict(d.items()) == d

True
>>>

</comment>

Tim Rowe
Guest
Posts: n/a

 12-12-2008
2008/12/12 John Machin <(E-Mail Removed)>:

> (2) sequential search can be very fast if the sequence is in
> descending order of probability of occurence ... you might like to
> consider reversing the order

I find it hard to imagine a bank with so many interest rate thresholds
that the search of the table is likely to be a significant
contribution to the run time!

> (3) for a much longer table, binary search using a function from the
> bisect module could be considered
> (4) in practice, the "default" action would not be "return 0.0";
> perhaps something along these lines:
>
> if balance < -overdraft_limit:
> raise Exception(...)

That's more likely to be in the withdrawal routine (and is probably
best not handled as an exception, because it's pretty much normal
flow). If a bank provided a service such as the one implemented by
this program, there'd be no need for it to know about overdraft limits
because it's not making actual transactions. Why would they increase
coupling unneccesarily?

--
Tim Rowe

John Machin
Guest
Posts: n/a

 12-12-2008
On Dec 13, 6:49*am, "Tim Rowe" <(E-Mail Removed)> wrote:
> 2008/12/12 John Machin <(E-Mail Removed)>:
>

> > (4) in practice, the "default" action would not be "return 0.0";
> > perhaps something along these lines:

>
> > if balance < -overdraft_limit:
> > * raise Exception(...)

>
> That's more likely to be in the withdrawal routine

You'd certainly hope that this test would appear in the withdrawal
routine.

> (and is probably
> best not handled as an exception, because it's pretty much normal
> flow). If a bank provided a service such as the one implemented by
> this program, there'd be no need for it to know about overdraft limits
> because it's not making actual transactions. Why would they increase
> coupling unneccesarily?

Yeah, you're right, much easier to return 0% interest on a negative
balance [customers happy; no wear and tear on the call centre] and
hope that anomalies are checked somewhere else *and* that somebody #1
is tasked with actioning the anomaly reports and that somebody #2 is
keeping an eye on somebody #1.

Lie Ryan
Guest
Posts: n/a

 12-12-2008
On Fri, 12 Dec 2008 04:58:36 -0800, feba wrote:

> Actually, I have gedit set to four spaces per tab. I have no reason why
> it's showing up that large on copy/paste, but the file itself is fine.

You've set gedit to _show tabs_ as four spaces, but not to substitute
tabs with four spaces.

Go to gedit's preference where you change how many spaces is used to
display tabs, right below it is "Insert spaces instead of tabs".

Lie Ryan
Guest
Posts: n/a

 12-12-2008
On Fri, 12 Dec 2008 09:50:43 -0800, Dennis Lee Bieber wrote:

> On Fri, 12 Dec 2008 03:42:55 -0800 (PST), http://www.velocityreviews.com/forums/(E-Mail Removed) declaimed the
> following in comp.lang.python:
>
>> #!/usr/bin/python
>> #Py3k, UTF-8
>>
>> bank = int(input("How much money is in your account?\n>>")) target =
>> int(input("How much money would you like to earn each year? \n>>"))
>>

> Just for my curiosity -- did Python 3.x (besides turning print

into
> a function) also change input() to behave as the old raw_input()?
>
> The above would be very discouraged in Python 2.x... in favor

of ...
> int(raw_input(...))
>

Actually, that's the first thing I wanted to bark on, before seeing the
little note above it: "#Py3k, UTF-8". I wonder though, there is a
potential problem if someone (users) is running this py3k code in a
python2.x. The code is a perfectly legal and correct python 2.x code, but
uses input() instead of raw_input(), we all know the evil of 2.x's input
().

bearophileHUGS@lycos.com
Guest
Posts: n/a

 12-12-2008
Kirk Strauser:

> def get_rate(balance):
> for threshold, rate in ((100000, .0173),
> (50000, .0149),
> (25000, .0124),
> (10000, .0085),
> (0, .006)):
> if balance > threshold:
> return rate
> return .0

Nice code. This operation, of choosing an item in a sorted list of
intervals that has no holes, is common enough. But something like an
interval dict is overkill here.
I suggest to put a zero before all those points, to improve
readability and avoid some possible errors: it's easy to not see a

----------------

Bruno Desthuilliers:

> A sequence of pairs and a dict are _almost_ interchangeable (mmm... is
> that the correct word ?) representations of a same data set[1] - the
> main difference being ordering. If ordering matters, choose a sequence
> of pairs as main representation - you can easily build a dict from it
> if/when you need it.

Generally(*) it's better to use the simpler data structure that does
the job. Here a list/tuple of tuples is good.
Very often programs get translated to other languages, so keeping
things as simple as possible helps that too.

---------

(*) I have used 'generally' because there's a compromise to be taken
here.

In C and other related languages you often use structs or records, so
if you have pairs you give a name to the fields, for example "x" and
"y" for the two coordinates of a 2D Point. In Python in such situation
you can create a Point class, but often you instead use a (x, y) or
[x, y]. In some situations you need to access the fields, so you use
[0] and [1]. This is (was) a case where Python looks lower-lever than
the C language. In Python3/Python2.6+ you can use a NamedTuple too.

Is it better to give and take a list of points to/from as a list of
[x,y] lists or as a list of Point2D? Probably a Java programmer thinks
that using Point2D is safer and is a way to document what the function
takes/returns too. Extending the list of pairs to 3D points is a
little simpler if they are represented as tuples/lists.

That's an example where you may not choose the simpler data structure
(that in Python is a list of pairs) and use a list of NamedTuple to
make code "safer" even if the data structure is a little more complex.

Bye,
bearophile