0
\$\begingroup\$

Function:

Calculates delivery charges based on area and also shows number of deliveries (fast food shop).

Created to stop bickering from drivers and for stats.

code:

from decimal import Decimal

# local delivery area £2 being the charge num being number of deliveries

def local(num) -> Decimal:
    return Decimal(2 * num)

# City of kinross area £4.5 being the charge, nun being number of deliveries

def kinross(num) -> Decimal:
    return Decimal(4.5 * num)

# City of lochgelly area £3.5 being the charge, num being number of deliveries 

def lochgelly(num) -> Decimal:
    return Decimal(3.5 * num)

# City of Cowdenbeath area £4 being the delivery charge and num the number of deliveries

def cowdenbeath(num) -> Decimal:
    return Decimal(4 * num)


loc = local(2)
kin = kinross(3)
gel = lochgelly(2)
cow = cowdenbeath(2)

print(f'local: £{loc}')
print(f'kinross: £{kin}')
print(f'lochgelly: £{gel}')
print(f'cowdenbeath: £{cow}')

# -30 is petrol money 
print(f'\nTotal -> £{sum(list((loc, kin, gel, cow, -30)))}')

print(f'Deliveries -> {sum(list((2, 3, 2, 2)))}')

Output:

local: £4
kinross: £13.5
lochgelly: £7
cowdenbeath: £8

Total -> £2.5
Deliveries -> 9

Questions:

  • How can I format the £ signs to be on the same level?
  • There is input repetition in the code which is tedious, any ideas? I can’t pass parameters as I’ve coded this on my phone.
  • I don’t like the way this code is, can you please advice on how I could improve it?
  • I’m just a beginner so I don’t really know what I’m doing.
\$\endgroup\$
8
  • \$\begingroup\$ I don't understand what this code is calculating, and why the calculations are the way they are. Could you provide a specification for the computation task? Why are -30, 2, 3, 2, and 2 there? \$\endgroup\$ Jun 8 at 5:53
  • \$\begingroup\$ As written in the comment -30 is the drivers petrol money the integers you stated are the number for deliveries to each area \$\endgroup\$
    – Nickotine
    Jun 8 at 9:31
  • \$\begingroup\$ Added comments for you \$\endgroup\$
    – Nickotine
    Jun 8 at 9:39
  • \$\begingroup\$ Write docstrings for functions (rather than # block comments). \$\endgroup\$
    – JosefZ
    Jun 8 at 11:53
  • 1
    \$\begingroup\$ @Reinderien it’s ok the takeaway just has a flat rate of £30 for petrol \$\endgroup\$
    – Nickotine
    Jun 8 at 12:51

1 Answer 1

2
\$\begingroup\$

Python has built-in support for showing localised currencies; you might as well use this. It shows to the nearest pence so you don't really have to use Decimal for this application.

It's good that you're trying your hand at functions but you've chosen the wrong thing to capture. You don't need a function for every city.

Consider showing:

  • a fixed-width-formatted table
  • headings for item name, unit charge, quantity, and subtotal
  • petrol as a line item like any other

Don't write literals 2, 3, 2, 2 for your sum. Instead store and re-use the arguments you've passed to your subtotal-calculating routines. A NamedTuple is one convenient way.

Re.

How can I format the £ signs to be on the same level?

It's less important to do this, and much more important to align the decimal places for easy magnitude comparison. You can define one formatting string, bind to its .format() method, and use this for both your header and rows.

Suggested

from locale import setlocale, LC_ALL, currency
from typing import NamedTuple

setlocale(LC_ALL, 'en-GB')

format_row = '{name:>12} {charge:>7} {qty:>3} {subtotal:>8}'.format


class Item(NamedTuple):
    name: str
    qty: int
    charge: float

    @property
    def subtotal(self) -> float:
        return self.qty * self.charge

    def format_line(self) -> str:
        return format_row(
            name=self.name, charge=currency(self.charge),
            qty=self.qty, subtotal=currency(self.subtotal),
        )


def main() -> None:
    deliveries = (
        Item('Local',       qty=2, charge=2.0),
        Item('Kinross',     qty=3, charge=4.5),
        Item('Lochgelly',   qty=2, charge=3.5),
        Item('Cowdenbeath', qty=2, charge=4.0),
    )
    costs = Item('Petrol', qty=1, charge=-30),
    items = deliveries + costs

    print(format_row(name='Item', charge='Charge', qty='Qty', subtotal='Subtotal'))
    print('\n'.join(item.format_line() for item in items))

    total = sum(item.subtotal for item in items)
    n_deliveries = sum(item.qty for item in deliveries)
    print(f'\nTotal -> {currency(total)}')
    print(f'Deliveries -> {n_deliveries}')


if __name__ == '__main__':
    main()

Output

        Item  Charge Qty Subtotal
       Local   £2.00   2    £4.00
     Kinross   £4.50   3   £13.50
   Lochgelly   £3.50   2    £7.00
 Cowdenbeath   £4.00   2    £8.00
      Petrol £-30.00   1  £-30.00

Total -> £2.50
Deliveries -> 9

Symbol alignment

If you sorely want aligned currency symbols, it's possible, but you will want to have them left-aligned and keep your charges right-aligned:

from locale import setlocale, LC_ALL, currency, localeconv
from typing import NamedTuple

setlocale(LC_ALL, 'en-GB')
symbol = localeconv()['currency_symbol']


class Item(NamedTuple):
    name: str
    qty: int
    charge: float

    @property
    def subtotal(self) -> float:
        return self.qty * self.charge

    def format_line(self) -> str:
        return (
            f'{self.name:12}'
            f' {symbol}{self.charge:6.2f}'
            f' {self.qty:>3}'
            f' {symbol}{self.subtotal:7.2f}'
        )


def main() -> None:
    deliveries = (
        Item('Local',       qty=2, charge=2.0),
        Item('Kinross',     qty=3, charge=4.5),
        Item('Lochgelly',   qty=2, charge=3.5),
        Item('Cowdenbeath', qty=2, charge=4.0),
    )
    petrol = Item('Petrol', qty=1, charge=-30)
    items = (*deliveries, petrol)

    print(f'{"Item":12} {"Charge":>7} {"Qty":>3} {"Subtotal":>8}')
    print('\n'.join(item.format_line() for item in items))

    total = sum(item.subtotal for item in items)
    n_deliveries = sum(item.qty for item in deliveries)
    print(f'\nTotal -> {currency(total)}')
    print(f'Deliveries -> {n_deliveries}')


if __name__ == '__main__':
    main()
Item          Charge Qty Subtotal
Local        £  2.00   2 £   4.00
Kinross      £  4.50   3 £  13.50
Lochgelly    £  3.50   2 £   7.00
Cowdenbeath  £  4.00   2 £   8.00
Petrol       £-30.00   1 £ -30.00

Total -> £2.50
Deliveries -> 9
\$\endgroup\$
4
  • \$\begingroup\$ I should’ve known it would be you reinderien… hahaha while some people just played dumb you totally smashed this thanks so much once again, I’ll keep your first alignment it looks more sensible \$\endgroup\$
    – Nickotine
    Jun 8 at 12:50
  • 1
    \$\begingroup\$ @Nickotine Cool. In the first case, I edited the formatting definition to be centralised. \$\endgroup\$
    – Reinderien
    Jun 8 at 13:14
  • \$\begingroup\$ a named tuple seems a lot like a data class, I’m looking into it but sorry to be looking to spoon fed, what are the differences? \$\endgroup\$
    – Nickotine
    Jun 9 at 21:52
  • \$\begingroup\$ chat.stackexchange.com/rooms/136946/… for discussion \$\endgroup\$
    – Reinderien
    Jun 9 at 21:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.