Skip to content

ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ

Arguments in depth

4 min read

In lesson 5.1 each argument went to the parameter in the same place. That's one of two ways Python matches them. By the end of this lesson you'll pass arguments by position or by name, give parameters default values, and avoid a default that quietly remembers every call.

Position decides

A taxi charges a starting fare plus 12 birr per kilometre (lesson 1.2). This version takes the distance first, then the starting fare. Predict:

ውጤቱን ገምቱ

Decide before you look. Guessing wrong is how this sticks.

def taxi_fare(km, base):
    return base + km * 12

print(taxi_fare(10, 15))
Pick the output

Python prints

135

The first argument goes to the first parameter, whatever the numbers look like. km is 10 and base is 15, so it's 15 + 10 * 12.

Python doesn't guess which number is which. A goes to the parameter in the same place, so swapping them changes the answer:

def taxi_fare(km, base):
    return base + km * 12

print(taxi_fare(10, 15))
print(taxi_fare(15, 10))

In the editor, press Escape then Tab to move on.

Arguments by name

You can also name the parameter in the call. A goes to the parameter with that name, so its place doesn't matter, and the call says what each number means:

def taxi_fare(km, base):
    return base + km * 12

print(taxi_fare(base=15, km=10))
print(taxi_fare(10, base=15))

In the editor, press Escape then Tab to move on.

The second call mixes both. That works when the positional arguments come first. The other way round, Python can't tell which place 15 is meant for:

Every parameter needs exactly one value. Leave one out, or give one too many, and the error names the function and counts for you:

Default values

Most prices use the standard 15% VAT, so make that the rate unless the call says otherwise. rate=0.15 in the def gives rate a :

def vat(price, rate=0.15):
    return price * (1 + rate)

print(vat(1000))
print(vat(1000, rate=0.05))

In the editor, press Escape then Tab to move on.

The first call leaves rate out, so it's 0.15. The second passes 0.05 (an example rate), which replaces the default for that call only. Parameters with defaults come after the ones without.

A default that remembers

A default value is made once, when def runs, not at each call. For a number that never matters, because a number can't change. For a list, it does. Predict:

ውጤቱን ገምቱ

Decide before you look. Guessing wrong is how this sticks.

def add(item, items=[]):
    items.append(item)
    return items

print(add(1))
print(add(2))
Pick the output

Python prints

[1]
[1, 2]

Both calls leave items out, so both get the same default list, made once when def ran. The first call appends 1 to it, and the second finds the 1 still there.

Step through it. The default list is kept with the function, so it's there before any call, and it stays after each call ends:

One default list for every call

Press Next to run one line at a time. Each arrow shows the object a name refers to. Each call gets its own frame of names, below the frame that called it.

def add(item, items=[]):
items.append(item)
return items
first = add(1)
second = add(2)

Frames, oldest first: global. add's default list is []; no name refers to it.

Step 1 of 9

Step 1 of 9. Line 1: def add(item, items=[]):. Nothing in memory changed.

Both calls' items refer to one list, and so do first and second. That's lesson 4.8 again: one list with several names, so a change through one name shows through all of them. The only surprise is when the list was made: once, when def ran. The fix is to use None as the default and make a new list inside the call, which runs every time:

def add(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add(1))
print(add(2))

In the editor, press Escape then Tab to move on.

Use None as the default for any list, dict, or set.

Two markers you'll see in documentation

Python's documentation writes sorted as sorted(iterable, /, *, key=None, reverse=False). The two markers are rules about how to pass arguments. Parameters before a / must be positional: you can't write sorted(iterable=...). Parameters after a * must be keyword arguments: reverse only works as reverse=True.

print(sorted([2, 3, 1], reverse=True))

In the editor, press Escape then Tab to move on.

Your own functions can use them too. A / after price makes it positional only:

You won't need either marker for a long time, but now you can read them.

ጥያቄ

With def taxi_fare(km, base=50):, which call is an error?

መልመጃ

A fare with defaults

Write fare(km, base=20, per_km=5) returning base + km * per_km (example prices). Call it three ways: 10 km with both defaults, 10 km with a base of 30, and 10 km at 8 birr per km, using a keyword argument so base keeps its default.

Output
70
80
100

Your code

# Define fare, then print three calls

In the editor, press Escape then Tab to move on.

መፍትሄውን አሳይ

This is one way to solve it, not the only one. If yours prints the same thing, it works.

def fare(km, base=20, per_km=5):
    return base + km * per_km

print(fare(10))
print(fare(10, 30))
print(fare(10, per_km=8))

ዋና ዋና ነጥቦች

  • Positional arguments match parameters by place; keyword arguments (base=15) match by name.
  • In a call, positional arguments come before keyword arguments.
  • Missing or extra arguments raise a TypeError that names and counts them.
  • A default value (rate=0.15) is used when the call leaves that argument out.
  • A default is made once, so never use a list as one: default to None and make the list inside.