The Mayor of Py Town's Local Experiment: A Global Disaster
Why variables within functions are local • [This short article has a different style and format from the usual articles]
Py Town is a tranquil place. Time runs a bit slower here. Or so it seems. Nothing much ever happens in this town.
Crime is low. People are happy. The mayor was bored. So he kept himself busy by thinking of new plans for the town.
And that's when the problems started.
The mayor's idea was to make every item in Py Town available to every resident at all times.
Py Town had just been granted Tier 1 Magical Status from the regional authorities. This had been the mayor's pet project since he was first elected. He persisted through two failed applications. The third time was lucky, indeed.
Tier 1 Magical Status only grants the town relatively low-level magical powers. One day, he'll try to get Tier 2. But not just yet. Tier 1 was perfect for his new scheme to make every item available to everyone when they need it. The mayor was sure that Py Towners would be so grateful once they got used to the efficiency of this new plan. And the next mayoral election is only a year away.
What could go wrong?
Theo was sure he had just packed three loaves of bread in the basket. Meg would be collecting her order any time now. But there were only two loaves in the basket. And he could see Meg crossing the road and heading towards his bakery. Where's the missing loaf? He looked around on the worktop but couldn't find it.
Ines is the teacher in the primary school three blocks away from Theo's bakery. She had instantly fetched a loaf of bread using the mayor's new scheme. She was impressed. All this magic was still new to everyone. She had just saved herself a twenty-minute round trip to buy bread. She had also magicked the money directly to Theo's cash register, of course. She could start preparing lunch right away.
But Ines was less impressed after the lunch break when she tried to set up for the art lesson. She couldn't find the paintbrushes and watercolours. She's always meticulous and stores the art supplies in the green drawer. But the green drawer was empty.
Gustav, the local artist, started panicking. He was running his first-ever workshop for customers. Ten eager students were about to arrive at his studio any minute. He didn't have enough paintbrushes and watercolours for everyone. Luckily, he knew that his friend Ines had plenty of supplies at the school. He didn't have time to go to the school where Ines teaches, but he could magically borrow them instantly. Thank you, mayor, for the new scheme! He'll magically put them back at the end of the workshop. He didn't know Ines was planning an art lesson, though.
But Gustav's laptop was running low on power, and the charger was missing. Gustav's brother, Karl, was at the fancy coffee shop overlooking the park. Karl's laptop charger wasn't working, but he had to finish three urgent emails, so he thought he'd borrow Gustav's charger. They used the same laptop model. The mayor's new scheme was working well, Karl thought.
Items kept disappearing all day all over town as Py Towners started to use the mayor's new scheme. Every item in Py Town could be anywhere at any time. It didn't take long before chaos reigned. Services started to break down. People were getting more frustrated by the minute. Everything ground to a halt.
The mayor's re-election prospects weren't looking so good now.
We'll get back to Py Town later. Let's look at this short code snippet:
I'll now ask you to take a moment to predict the output of this code. Yes, I know, it's not hard. Just play along, please.
Do you have an answer?
Here's what I get when I run this code:
Starting the demo
Traceback (most recent call last):
...
for value in range(start, end):
^^^^^^^^^^^^^^^^^
TypeError: 'str' object cannot be interpreted as an integer
It's OK. You don't need another coffee. I should warn you at this stage that there's something funny going on behind the scenes. The ellipsis ...
in the code is a placeholder for this skulduggery. But more on this soon.
Let's debug. The error message points to the for
statement. And if you're using the latest version of Python, you'll also see arrows highlighting range(start, end)
.
So, let's confirm that start
and end
are the values we expect them to be, 2
and 10
:
This code outputs the following:
Starting the demo
2
No, there are no typos in the output block shown above. Only the "Starting the demo"
line and the number 2
are displayed. Where's the other value hiding?
If printing the value of a variable doesn't help with finding the bug, we should check its data type:
This gives the following output:
Starting the demo
2
<class 'str'>
We're getting more clues. Using the built-in `repr()` may help further:
And the result unveils part of the mystery of what's going on:
Starting the demo
2
'\n'
There's the string with the newline character stored in end
. That’s why there was a blank line in the earlier printout. Now we know why the TypeError
was raised when calling range()
. Good.
But where's this value coming from? And where's the number 10
? You clearly assigned 10
to the variable end
in the code.
This is the same chaos the mayor of Py Town unleashed when he made every object in the town available to everyone all the time. Imagine if Python worked like the mayor's not-so-clever brainwave. Imagine if every variable name you define in a function definition is available to any other function at any time, all the time—just like all the items in Py Town.
I've hacked and tweaked a few things behind the scenes to replicate PyTown's silly scheme in the code above.
And here's the problem. The built-in print()
function has an end
parameter that's set to "\n"
by default. Here's the function signature you'll find in the Python documentation:
print(*objects, sep=' ', end='\n', file=None, flush=False)
In my Py-Town-inspired-don't-do-this-at-home hack, print()
shares the same end
variable as the main program. The variable end
is global. So, even though you define end = 10
in the main scope of your program, the variable end
gets assigned a different value the moment you call print()
. The print()
function needs to use end
to assign the string "\n"
to it.
It's chaos. There's only one variable named end
. It must be reused.
Let me finish with a more straightforward example using a user-defined function. Let's assume you have this function that you use in many of your projects:
It's not the most useful function you'll ever need. In fact, it's not a function you'll ever need. But it will do to demonstrate the point. In the Py-Town-foolery-inspired version of programming, the variable name result
will be accessible and available everywhere you use this function. [PS: in this weird universe, you wouldn't need a return
statement, either. But let's ignore that fact here.]
And therefore, in this alternate universe, you cannot reliably use the variable name result
anywhere in your code as it may conflict with the one in this function.
And, of course, you'll need to check every function you plan to use in your program. Not just any function you write, but every function, whether built-in or defined in a third-party package. You won't be able to safely use any variable name used in any of those functions.
Get ready to keep a long list of names you can't use in your program. A very long list.
Thankfully, back in the real world, any variable defined in a Python function definition is local. It only exists within the function and is not accessible by other functions or the main program.
This is a safety net. Remove this safety net at your own peril!
And it only took two days and one morning for Py Town's mayor to reverse his new policy. Much harm had been done in those two and a bit days.
Was the mayor's reputation fatally harmed?
Code in this article uses Python 3.11
Stop Stack
#22
This article followed a different style and format compared to the usual posts. If you're a regular reader of The Stack, you'll know that I often (nearly always?) steer away from the classic programming articles and tutorials. But sometimes, I want to push the boundaries a bit further. If you also follow posts on my other substack, Breaking the Rules, then you know more about this. If you have feedback about this, or indeed any, article, good or bad, let me know either in the comments below or in the Substack Chat.
Recently published articles on The Python Coding Stack:
Time for Something Special • Special Methods in Python Classes (Harry Potter OOP Series #6) Year 6 at Hogwarts School of Codecraft and Algorithmancy • Special Methods (aka Dunder Methods)
A Picture is Worth More Than a Thousand Words • Images & 2D Fourier Transforms in Python. For article #20 on The Python Coding Stack, I'm revisiting one of my tutorials from the pre-Substack era
A One-Way Stream of Data • Iterators in Python (Data Structure Categories #6) Iterators • Part 6 of the Data Structure Categories Series
Collecting Things • Python's Collections (Data Structure Categories #5) Collections • Part 5 of the Data Structure Categories Series
And Now for the Conclusion: The Manor's Oak-Panelled Library and getitem()[Part 2]. The second in this two-part article on Python's
__getitem__()
special method
Recently published articles on Breaking the Rules, my other substack about narrative technical writing:
Mystery in the Manor (Ep. 4). The best story is the one narrated by the technical detail itself
Frame It (Ep. 3). You can't replace the technical content with a story. But you can frame it within a story.
Whizzing Through Wormholes (Ep. 2). Travelling to the other end of the universe—with the help of analogies
Sharing Cupcakes (Ep. 1). Linking abstract concepts to a narrative • Our brain works in funny ways
Once Upon an Article (Pilot Episode) …because Once Upon a Technical Article didn't sound right. What's this Substack about?
Stats on the Stack
Age: 3 months, 2 weeks, and 4 days old
Number of articles: 22
Subscribers: 794
Each article is the result of years of experience and many hours of work. Hope you enjoy each one and find them useful. If you're in a position to do so, you can support this Substack further with a paid subscription. In addition to supporting this work, you'll get access to the full archive of articles and some paid-only articles.