Intro to Python, Chapter 4 – Functions

This post was originally published here

Running through the door, Baldric found himself in an enormous cavern, its ceiling lost in shadow. Great columns of black stone soared from the ground, and pools of lava bubbled throughout, lighting the cavern in a dark red. The heat was suffocating. Baldric saw Bill standing on a stone outcrop nearby, apparently scanning for something. Beyond him, in the center of the cavern, was large mahogany desk. Baldric could just make out the gold nameplate from this distance which read “HR Manager”.

With a disgruntled roar Bill brought his warhammer down on the ground, lava seeping through the resulting fissure. “I come all the way to see the HR Manager, and it’s not even here? Bah, the coward!”

“Bill,” said Baldric, panting and heaving as he climbed the rocky slope, “The HR Manager isn’t supposed to be here right now.”

“What? Not supposed to be here? What makes you say that?”

“It’s out devouring the dreams of the workforce right now. If you could see Magic, you would’ve seen its dream web covering the sky tonight. Since you apparently came here to do more than talk with it, I should tell you that I came here to take something from its desk.”

“So you’re a fellow rebel?” Bill laughed heartily and put his arm around Baldric’s shoulders. “I knew you were a good man. I should tell you, my name isn’t actually Bill. It’s Geofram, Geofram Hammerfell.”

A glass-shattering shriek pierced the cavern, and a massive black body fell from the shadows above, its landing crushing boulders and splashing lava. It was an obsidian-scaled creature out of a nightmare with four heads, eight legs, and two wings like the sails of some warship of the damned. The creature extended its wings and let out another deafening screech (cue battle music).

Geofram threw his head back and roared with laughter. “Quite a pair of lungs you’ve got there, oh fearsome HR Manager. Let’s see what they look like!” With that, he leapt off the stone outcrop and charged the beast, running between lava pools and letting out a fierce battlecry of his own.

For a split second, Baldric thought the creature was actually turning to run! Then he saw a thick, scaly tail whipping around from the side, crashing through columns of rock, and cringed at the sickening crunch of it impacting with Geofram. Baldric watched in horror as the warrior sailed through the air and slammed into the side of the cavern. He didn’t get up.

Completing its spin to face Baldric’s direction once again, the four faces of the HR Manager appeared to be smiling. One of those heads opened its mouth and, to Baldric’s surprise, started weaving threads of Magic. It was a simple but powerful weave of pure fire, likely some sort of fire-based projectile. Frantically, Baldric thought back to the Book of Magic.

Taken in its entirety, the multiverse is in perfect magical balance. Water balances with Fire…

“Of course, Water cancels out Fire! So I just need to…” In the middle of thought, the weave completed and a bolt of molten flame shot through the air at Baldric’s head. In a panic he slipped and tumbled down the rocky slope, feeling the heat from the bolt of fire that passed through where his head had been a moment ago.

Getting up on his knees, he crouched behind some rocks. “There’s no time to think, I just have to react. But I don’t know this stuff by heart yet! Wait, maybe I can use a conditional statement to tell me what element to counter with.”

attack = "Fire"

if attack == "Fire":
    print("Counter with Water!")
elif attack == "Water":
    print("Counter with Fire!")
Counter with Water!

“That seems to work. Now I just need to add in the rest of the elements. Let’s see, I think the Book said Wind balances with Earth, and…”

Baldric’s cover exploded into fragments, sending him flying several feet. Gathering himself, he turned to see more Magic being prepared by one of the heads. It looked like Earth this time.

attack = "Earth"

if attack == "Fire":
    print("Counter with Water!")
elif attack == "Water":
    print("Counter with Fire!")
elif attack == "Wind":
    print("Counter with Earth!")
elif attack == "Earth":
    print("Counter with Wind!")
Counter with Wind!

By the time Baldric finished with his conditional statement though, a great earthen spike was already descending on him from above. Without time to respond magically, he rolled to the side just in time to avoid impalement. Shrouded in a cloud of debris, he scrambled over to another stone outcrop and took a moment to strategize.

“I don’t have time to think through what I need to counter with, and I don’t have time to weave a full conditional statement for every single spell either. If only I could weave this conditional Magic just once, and reuse it whenever it was needed without weaving it all over again…Oh yeah that’s right, I need to use functions! I can bundle up a bunch of Logic inside a function and reuse it in an instant.”

# create a function named counterattack like so
# note that the name of the function and its input can be anything you want
# also note how everything inside a function must be indented

def counterattack(attack):
    if attack == "Fire":
        print("Counter with Water!")
    elif attack == "Water":
        print("Counter with Fire!")
    elif attack == "Wind":
        print("Counter with Earth!")
    elif attack == "Earth":
        print("Counter with Wind!")

“So there’s my function. Now I just have to feed in the element of attack, and then the Logic will run without me having to weave the whole conditional statement over again. Not to mention I can reuse the function endlessly.”

# let's test it out

>>> counterattack("Water")
'Counter with Fire!'

>>> counterattack("Earth")
'Counter with Wind!'

He could hear the creature breathing, but it apparently didn’t know where he was. A boulder nearby exploded, and Baldric peered out from behind his rocks to see the manager turning towards his position next. It was forming another Fire attack.

>>> counterattack("Fire")
'Counter with Water!'

Using his function, Baldric instantly knew what to counter with. Just as the fire spell was released, Baldric finished his own simple weave of Water, and a jet of water met firebolt midair and exploded in a harmless burst of vapor. The creature seemed stunned for a moment, then responded with a barrage of attacks: Earth, then Water, then Wind. But Baldric was prepared.

>>> counterattack('Earth')
'Counter with Wind!'

>>> counterattack('Water')
'Counter with Fire!'

>>> counterattack('Wind')
'Counter with Earth!'

Baldric wove Magic faster than he ever had before, countering Earth with Wind, Water with Fire, and Wind with Earth. Seeing all of its attacks nullified, the beast shrieked in rage and began to craft a new attack.

“Wait, that’s different from the other attacks. What is that!? It looks like Water, Earth, and Wind all at once. Uh oh.”

Baldric’s hair stood on end and the air crackled with energy. A figure landed on the ground in front of him just as a blinding light and deafening boom nearly knocked Baldric over. Once his vision recovered, he saw Geofram standing in front of him, electricity arcing throughout his plate mail, his great hammer raised straight overhead.

Geofram threw back his head and laughed. “Bahahaha, well that sure woke me up! And now it’s time to put you to sleep, foul beast. Baldric, you and me, let’s finish this thing.”

“Geofram, I need a moment to work something out.”

“Alright, I’ve got you covered, friend.”

The HR Manager let loose a barrage of elemental attacks. Wielding his hammer, Geofram stood in front of Baldric and deflected firebolts, earthen spikes, and spears of ice, one after another.

Baldric took the chance to weave the ultimate counterattack function, based on everything he remembered from the Book of Magic.

# to account for combos of elements, the function needs to be structured differently
# its inputs will be 5 booleans (True or False) based on whether a given element is involved or not

def counterattack(fire, water, earth, wind, logic):
    # light
    if (fire and water and earth and wind and logic):
        print("Counter with Darkness (all elements but Logic)!")
    # darkness
    elif (fire and water and earth and wind):
        print("Counter with Light (all elements)!")
    # lightning
    elif (water and earth and wind):
        print("Counter with Fire, Earth and Wind!")
    # ice
    elif (water and wind):
        print("Counter with Lava (Fire and Earth)!")
    # lava
    elif (fire and earth):
        print("Counter with Ice (Water and Wind)!")
    elif fire:
        print("Counter with Water!")
    elif water:
        print("Counter with Fire!")
    elif wind:
        print("Counter with Earth!")
    elif earth:
        print("Counter with Wind!")
        print("I don't know, take cover!")

The four heads were all casting spells now, a constant stream of firebolts and ice shards, molten lava and chunks of rock. Hammerfell, with his gleaming warhammer, danced gracefully from one stance to another as his weapon whirled through the air with inhuman speed and repelled attack after attack. Above Hammerfell, Baldric could see the HR Manager preparing that same mix of Water, Earth, and Wind as before.

>>> counterattack(False, True, True, True, False)
'Counter Lightning with Fire, Earth and Wind!'

Not sure what to expect, Baldric wove Fire, Earth, and Wind together in a way that intuitively seemed protective in nature. A nearly transparent dome formed over him and Hammerfell just as the lightning struck. The blinding bolt crashed into the barrier with a roar and was gone, not leaving so much as a mark on the dome. But the creature was already forming more spells: lava, then fire, then ice.

>>> counterattack(True, False, True, False, False)
'Counter Lava with Ice (Water and Wind)!'

# when there are lots of arguments, you can use their names to clarify what's happening
# in this case, it's now obvious from the function call that only Fire is involved
>>> counterattack(fire=True, water=False, earth=False, wind=False, logic=False)
'Counter with Water!'

# if you use argument names, you can change the order of arguments and it still works like it should
>>> counterattack(water=True, earth=False, wind=True, logic=False, fire=False)
'Counter Ice with Lava (Fire and Earth)!'

Using his counterattack function, Baldric took over on defense and negated the entire Magical flurry. A wall of ice blocked a wave of lava, a jet of water cancelled out a bolt of fire, and pillars of molten rock deflected ice spears.

“Looks like you’ve got a handle on the beast’s magic tricks Master Baldric, so I’d say it’s time for a little offense.” And with that, Hammerfell charged at the monster once again. A furious stream of lethal Magic rained down on Hammerfell, but Baldric made sure it never touched him. As Hammerfell closed the distance, Baldric saw the attacks stop as all four heads seemed to be working together on one massive spell, weaving together Fire, Water, Earth, and Wind all at once. A dark, throbbing mass that seemed to absorb the light around it formed in the air.

>>> counterattack(True, True, True, True, False)
'Counter Darkness with Light!'

Frantically, Baldric channeled raw Light Magic at the orb, weaving all five elements together in as great a quantity as he could muster. A beam of Light from Baldric’s hand impacted the orb, which seemed to weaken but not destroy it. The HR Manager roared and the still sizeable orb of darkness flew at Hammerfell.

“Geofram, look out!” As the pulsating orb hurtled toward Hammerfell, his hammer suddenly began to glow with a radiant light. It was far brighter than even Baldric’s beam had been. Gleaming hammer connected with Darkness, and in a brilliant flash the orb was gone. His path now clear, Hammerfell leapt into the air with a roar as his hammer grew brighter still. Baldric shielded his eyes from the blinding light, and otherworldly screams erupted in the cavern like a chorus of demons being simultaneously immolated.

After picking himself up and blinking through the spots in his eyes, Baldric saw the remains of the HR Manager splattered across the cavern. Hammerfell strolled back over towards Baldric, casually wiping oily black blood off his hammer with his cloak as he walked.

“That was incredible Geofram! We’d better get out of here though. That demonic cacophony probably woke half the city.”

“Actually, this is where we must part ways, Baldric my friend. There’s much of dire importance still to do, and there’s no time for me to be wandering through any more labyrinths. Not to mention that you’ll be fine without me, you clearly know how to handle yourself. One question before I go though. This probably seems like an odd thing to ask, but how do you convert a binary…I think that’s what it’s called, you know, a number with all 1’s and 0’s…into a regular decimal number?”

After a moment of thought, Baldric remembered that the int() function he had used in the past had a second optional argument that could be used to convert a binary string into a decimal number. For instance…

>>> int('101', 2)

>>> int('11000', 2)

“Well Bill, if you can use Logic it’s pretty simple, but it might take a little explaining if you want to do it by hand.”

“Argh, nevermind Master Baldric, I’m no good with channeling Magic except for wielding Light through my hammer, and I really must be off. Oh, I found this in the ruins of the desk, figure it must be what you came here for,” said Hammerfell, handing a small, black metal lockbox to Baldric. “I pray that our paths cross once again.” And with that, Hammerfell darted up the side of the cavern wall, leaping from ledge to ledge until he disappeared into the shadows above and the sound of his passage was lost to the darkness.

Baldric noticed now that there were in fact two doors in the cavern: the one he had entered through, and a second similar one which was closed. As he reentered the first door, he could hear what sounded like a distant rumble and clinking. It sure sounded a lot like armored guards in a rush. He hurried back out and over to the second door. It opened silently, and he closed it behind him.

He was in an earthen tunnel that sloped upward. Baldric jogged up the slope as fast as he could, which wasn’t saying much. Almost out of breath and the shuffle of armored feet echoing throughout the tunnel, he found himself in a chamber much like those he had passed through to get to the HR Manager’s office. Across from him though, instead of multiple doors, was a single heavy stone door.

On each side of the doorway was a number. And on the ceiling there was what appeared to be instructions for some sort of Magical procedure: “Add 11, multiply by 13, raise to the power of 17, and find the remainder of division with 19. Do this for each of x, y, and z, and answer with the sum.”

The numbers around the door were 3, 5, and 7.

“Okay, okay, I need to think quickly now. It looks as if I need to perform the same procedure three different times. I can probably use a function to speed things up in that case.”

def procedure(number):
    number = number + 11
    number = number * 13
    number = number**17
    number = number % 19
>>> procedure(3)

“…nothing happened. Ugh, come on…oh that’s right, I need a print() statement to see the result.

def procedure(number):
    number = number + 11
    number = number * 13
    number = number**17
    number = number % 19
>>> procedure(3)

“Great, yeah, but I also want to store that result so I can later add it to the other results.”

>>> result1 = procedure(3)

>>> print(result1)

“Something isn’t right here. When I call the function and assign it to result1, it’s printing the result. I guess that makes sense, since that’s what the function is supposed to do when it’s called. But it’s not actually assigning that number to the variable result1. How can I…oh I remember now, that’s what return statements are for!”

# the print function just displays objects
# return statements make those objects actually usable

def procedure(number):
    number = number + 11
    number = number * 13
    number = number**17
    number = number % 19
    return number
>>> result1 = procedure(3)

# notice that nothing was printed this time
# let's see if result1 actually contains something now

>>> print(result1)

# success

“There we go. Now instead of just displaying the result, the procedure() function actually outputs, or returns, the result, meaning it can be used in calculations or stored in variables and things like that (i.e. >>> procedure(3) + procedure(5) works and will sum the results of those two function calls). Now I just need to do this with the other two numbers, then sum them all together.”

>>> result2 = procedure(5)

>>> print(result2) # checking to make sure it's working

>>> result3 = procedure(7)

>>> print(result3)

>>> final_result = result1 + result2 + result3

>>> print(final_result)

# also try the quicker >>> print(procedure(3) + procedure(5) + procedure(7))

“Forty one!” Baldric called out. The stone door immediately swung open and Baldric hurried inside. It was dark except for the light from the torches in the chamber he had just left. There was a snap, and something nicked his ear. He instinctively dropped to the ground just as two more arrows shot over him. He turned as he fell and saw the chamber beyond the door filling with Imperial guards, several with bows drawn. He also saw that this end of the magical stone door had a different set of symbols by each of its sides, and he could just make out some text on the ceiling:

  • Left of doorway: [41, 29, 17, 7]
  • Above doorway: [37, 23, 13, 5]
  • Right of doorway: [31, 19, 11, 3]
  • Ceiling: To the first add the second. Take of the product of the sum and the third. Raise the product to the fourth. Do this for each, and sum the results.

As Baldric hit the ground he thought to himself, “My only chance is if solving this puzzle closes the door. I need to write a function that can take a list as input.”

def procedure(number_list):
    answer = number_list[0]
    answer = answer + number_list[1]
    answer = answer * number_list[2]
    answer = answer ** number_list[3]
    return answer

l1 = [41, 29, 17, 7]
l2 = [37, 23, 13, 5]
l3 = [31, 19, 11, 3]

final_answer = procedure(l1) + procedure(l2) + procedure(l3)

Thinking and weaving faster than he ever had before, Baldric finished his Logic and printed out the result, causing the heavy stone door to swiftly swing closed. He rolled out of the way of a few more arrows, and with a satisfying thud the door was shut and all was silent. Still out of breath, he touched his ear and saw blood on his fingers. Panting, he thought to himself, “Whew, that was a close one. Hopefully no Logic casters are back there.” He stood there for a minute, catching his breath and watching the door. It didn’t budge.

“I…I think I did it. Haha, I did it! Yes sir, this old dwarf’s still got the Magic, boom! Take that Empire! You can’t fire me, because I QUIT!!! HA!!!!!”

“I’ll be the judge of that.”

Baldric nearly fell over in shock at the unexpected voice. He turned around to see Cassandra silently walking towards him.

“Cassandra! Hoo boy, you sure frightened me. Here, I got your lockbox. Glad to see you somehow escaped, by the way. You won’t believe what just happened. Me and…” Cassandra’s spin-kick took Baldric off his feet and sent him crashing into the stone floor. As he struggled to process what had just happened, she placed her foot over his throat. “I thought you might end up here. Just a little ways from HR’s facility actually. How thoughtful, you won’t need to be carried far at all.”

He noticed several figures emerging from the shadows around him, including two half-elves that looked vaguely familiar. Baldric began weaving Magic. Maybe he could use that same barrier that blocked the lightning to give him some time to…all at once he felt the Magic drain out of him, as if a well had suddenly run dry. The individuals around him were weaving complex Magic that seemed to be blocking his own. All of them bore the Imperial Seal on their robes. Management.

“Cassandra, I don’t know what’s going on, but…”

“Save your breath, dwarf. You’ll need it for screaming during your performance review.”

Something struck Baldric’s head. Darkness.

Congratulations, you earned 2,568 experience and 1,542 gold! You are now a Level 6 Dwarven Evoker! (cue victory music)

Here are the Python topics you covered (and may want to DuckDuckGo for further inquiry):

  • functions
  • function inputs, referred to as arguments (if referring to function call) or parameters (if referring to the function itself)
  • named and unnamed function arguments
  • function outputs via the return statement
  • None (which functions return by default)
  • the difference between printing and returning something in a function
  • converting from binary to decimal

Chapter 5 – Loops >>>

Related Posts

Local Interpretable Model-agnostic Explanations – LIME in Python When working with classification and/or regression techniques, its always good to have the ability to ‘explain’ what your model is doing. ...
Python – TechEuler Python – TechEulerUnOrdered Linked list – Prepend, Append, Insert At, Reverse, Remove, SearchUse of __slots__ in Python ClassUsage of Unde...
Introduction to Python Ensembles Stacking models in Python efficiently Ensembles have rapidly become one of the hottest and most popular methods in applied machine learning. Virtually...
Postgres Internals: Building a Description Tool In previous blog posts, we have described the Postgres database and ways to interact with it using Python. Those posts provided the basics, but if you...