What Programmers and Creatives Can Learn From Each Other
CJFP 05 - JUly 12TH, 2024
If you’re reading this, it’s too late! This article was written and delivered to our newsletter subscribers a week ago. If you’d like to get our latest articles as soon as they’re released, consider signing up for our newsletter CaJu’s ‘Fresh Picks’ at www.caju-creative.com/newsletter.
Read to the end for a special recommendation on my favorite book for learning the Python programming language from scratch.
“The Zen of Python” as Method and Poetry
In “My Qual-to-Quant Journey,” an article I wrote for LinkedIn detailing my career decision to expand from the arts to the sciences, I put forward the idea that creatives and STEM heads can learn a lot from one another’s methods. I’d like to expand on that sentiment today using one of the more unexpected Python modules as a concrete reference, but before I do that, I need to introduce you to Tim Peters.
Tim Peters is a software engineer, a very good one at that. This won’t appeal to non-technical readers, but some of his accolades include developing his own sorting algorithm in addition to being a major contributor to the open-source Python programming language and one of the key original developers for CPython.
He’s got cred, but what I think might shock readers is, arguably, what Tim Peters is most known for is a poem he wrote called “The Zen of Python.”
Just as with every natural, human language, computer languages have some degree of interpretability. A programmer has a degree of freedom in their syntax, order of functions, naming conventions, etc. That last word is telling though: Convention. Just as when humans speak to one another with varying degrees of vagueness, depending on the person you’re talking to, depending on the amount of context the person you’re speaking to has, the same phrase can be structured many many different ways to successful ends.
Certain grammatical mistakes are non-starters like omitting objects or predicates from your sentence. But not always. The formal language your state-sponsored school taught you growing up is actually a gradient with textbook-perfect speech on one side and incoherent babbling on the other. It is incumbent upon the one who is interpreting the language to make various assumptions about what is being said or to request more information if the vagueness proves terminal to understanding. Programming languages can be similar.
To be easy to read, write, and learn, Python was designed to reflect human speech and thus has many of the vagueness of human speech. Just as with natural languages, conventions had to be developed and popularized for what makes a piece of code grammatically correct, henceforth referred to as “Pythonic.”
Here’s where we get Peters the poet. In an attempt to formalize many of the rote-learned conventions for Pythonic coding, Tim Peters wrote the following:
The Zen of Python by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
This is poetry. There’s no way around it. This is a good poem written by a computer programmer and what I’d like to do here today is go line by line through this poem and explore first, what it means in the realm of a generic piece of Python code, and then secondly, the greater meaning behind the line and the implications it has for all creative endeavors (of which programming should be considered).
You can follow along too! If you’re a complete novice, simply Google “How to use Python on a (insert your machine type here).” Once you’ve got a Python3 interpreter up and running, type the following:
import this
The Zen of Python ships with every copy of the Python programming language so you should now have it in its entirety.
Beautiful is better than ugly
Out of the gate, I have no choice but to invoke Philosophy. The nature of beauty, or aesthetics, has been a fiercely debated topic (one must assume) since humans first began making use of the concept. Something beautiful can be simple to some and complex to others. There can be beauty in conformity and there can be beauty in uniqueness. Beauty can be put upon us by the world and it can also be subjectively defined from within us.
Plato thought beauty was an ideal Form beyond the physical world. Aristotle thought it was order, symmetry, and purpose. Plotinus thought beauty came from unity and the divine. Aquinas linked beauty to harmony, proportion, and integrity. Burke distinguished beauty as delicate and pleasing, different from the awe-inspiring sublime. Hume said beauty was subjective and in the eye of the beholder. Kant believed beauty was a disinterested pleasure that claims universal agreement. Hegel viewed beauty as the sensuous expression of the divine. Nietzsche saw beauty as the interplay of order and chaos.
Unfortunately for us, they’re all right.
Beauty is hard to define, but it has one universal aspect: Beautiful is better than ugly. That aspect of beauty is built into its definition and so it is a bedrock we can build upon.
In his book Zen and The Art of Motorcycle Maintenance, Robert Pirsig redefined the search for beauty in the field of aesthetics as an innately biological seeking of Quality. I like this quite a lot. He posits when even a single-celled organism flees harsh sunlight for shade, what they are doing is seeking an environment with superior quality, one more suitable for them to carry out living in; one more beautiful.
That is the definition of Beauty I’d like to adopt here.
For a programmer, this means keeping code legible. One knows ugly code when one sees it, especially in a language like Python that really tries to steer users towards legibility.
Coding can be easily dismissed by creatives as non-creative, but one only thinks that way if one has never really tried programming. When you find an elegant and simple solution to a difficult logical problem in a coding language, it is a feeling of such sublime bliss, that it rivals the feeling one gets from a eureka moment when creating art.
Coding and creative endeavors each seek clarity and quality. Even if one tries to make something “ugly,” they attempt to do so in line with some reasoning and so can attain a level of “beautiful ugliness” if that creation’s form is such that it makes the interpretation of its meaning an enjoyable experience for human beings.
Ugly Python Code:
def greet(name):
if name: print("Hello, " + name + "!")
else: print("Hello!")
Beautiful Python Code:
def greet(name):
greeting = f"Hello, {name}!" if name else "Hello!"
print(greeting)
Explicit is better than implicit
This is where I think I might have the most trouble synthesizing a lesson that applies to both coders and creatives. In general, I believe marketing does best when it tries to convey messages implicitly. After all, that is the goal of all creative storytelling. It’s not enough to simply say “Pride can be dangerous to your work and your health.” It’s much more lasting to tell the story of Narcissus drowning due to falling in love with his reflection in the water or the slow and steady tortoise beating the quick and cocky hare.
Wrapping an explicit meaning in a story and leading the reader to arrive at a conclusion themselves is one of the oldest human endeavors. It’s also not what this part of the poem refers to.
What this line literally refers to is to state your purposes for particular parts of your code as opposed to relying on the reader to infer your intentions. This helps future-proof code. You might know what you’re doing at the moment, but someone (or even yourself ) reading the same code at a later date may have no idea what you’re trying to accomplish or how.
There are situations in which obscuring your intentions is a rhetorically powerful method to create a lasting impact on your reader. However, if you’re writing code and your reader is a programmer, the only lasting impact obscurity has is frustration.
When writing code, I like to consistently ask myself “If I was struck by an acute case of amnesia at this moment, how difficult would it be to figure out what I’m trying to accomplish here?” Once you’ve had to decipher some difficult-to-interpret code, you’ll annotate every line, use docstrings, and state your intentions right at the top of your document. Every. Single. Time.
A lesson here for traditional creatives is not to rely too heavily on the interpretive mood of your audience. For example, if a person is looking at your advertisement, then the hard part of capturing their attention is over! From that point on, you should be making their life easier. Many people will tell you that you should reduce clutter on an ad or remove details so as not to bore a reader. There is some truth in this, but there is a limit to this line of thinking.
If someone has been taken in by something you’ve created, you want to treat them as respectfully as you would talking with someone in person. Don’t fear the details. If someone is interested in your product or service and they have to scour your ad for more information that isn’t there, you may lose them when you already had them “on the hook” so to speak.
There are times when being implicit can have an impact, but more often than not, explicit is better than implicit.
Implicit Python code:
def calculate_area(r):
return 3.14159 * (r ** 2) if r > 0 else "Error: Radius must be greater than zero"
print(calculate_area(5))
Explicit Python code:
# Defining a function to calculate the area of a circle
def calculate_area(radius):
"""
Calculate the area of a circle.
This function takes a non-zero, non-negative integer or float as an argument for the radius, checks its validity, calculates the area of the circle, and returns the area as a float. The area is defined as a = pi * r^2.
Parameters:
radius (float or int): The radius of the circle, which must be greater than zero.
Returns:
float: The area of the circle.
str: An error message if the radius is not greater than zero.
"""
# Check if the radius is valid
if radius <= 0:
return "Error: Radius must be greater than zero"
# Calculate the area
area = 3.14159 * (radius ** 2)
# Return the result
return area
# Calling the function for a radius of 5
print(calculate_area(5))
Simple is better than complex
This is where the poem starts to become self-contradictory. It will make sense in time, but for now, it might seem like I’m going against what I’ve previously said. Peters does this as a rhetorical device; using contradictive dichotomies to emphasize deeper meanings.
There is a difference between complex and obscure. There is a difference between simple and vague. Our job as coders and creatives is to aim for that which improves the experience of our intended audience.
As a continuation of the last point, one should aim to give the reader as much information as they need to be familiar with what you’ve created for them. That said, the manner in which you provide that information should be to the point rather than needlessly verbose.
This may be the American Pragmatism in me speaking, but this is a complaint I’ve had with higher education for some time as well. When trying to change hearts and minds or educate the public, why on Earth would you coat your message or findings in five-dollar words that even most academics won’t fully understand? There’s little point in trying to be obscure on purpose besides maybe to mask a lack of substance or grasp. To paraphrase Einstein, if you can’t explain something simply, then you don’t understand it well enough.
When coding, think of your ideal end goal or result. Write out the steps one would need to follow to accomplish your end goal. Try writing in reverse order, then from where you think you should start. When new things occur to you, write them in the middle. Keep writing steps until you can see a path from A to Z. Once you’ve written out all of your steps, condense and combine. Write out the methods you would use to accomplish each step. Look for redundancies or ways of accomplishing multiple tasks at once. Python has many advanced methods that can achieve in one line of code what would take other languages several lines of code. Python has many many many easily accessible modules and libraries that can perform advanced functions for you. Other people have done the leg work and are kindly willing to share their methods with you! You might as well take them up on it!
I’m not going to argue that simple art is superior to complex art. Art should challenge you at times, it should make you think. But that isn’t to say that every movie needs to be an Inception or that every novel needs to be a Ulysses. A good rule of thumb no matter what you’re making is trying to accomplish exactly what you set out to, without compromise, in as few moving pieces as possible. This is not catering to a “lazy” audience, this is just having the courtesy to not require an advanced degree to enjoy what you’ve made.
Complex Python Code:
def is_prime_complex(n):
"""Check if a number is prime with complex logic."""
if n <= 1:
return False
if n <= 3:
return True
if n % 2 == 0 or n % 3 == 0:
return False
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
print(is_prime_complex(17)) # True
print(is_prime_complex(18)) # False
Simple Python Code:
from sympy import isprime
def check_prime_simple(n):
"""Check if a number is prime using sympy."""
return isprime(n)
print(check_prime_simple(17)) # True
print(check_prime_simple(18)) # False
Complex is better than complicated
One would not call a starry night sky simple, nor would they likely call it complicated. It is beautiful in its complexity. Art and code alike should strive for the same.
Your first order of thinking should be Simple > Complex, however, in many situations, you may not be able to avoid complexity and that’s okay! Complex things can be beautiful too!
As with the previous example, you should strive to make your creations as simple as is necessary for your audience to enjoy them. If keeping it simple leaves your audience confused or wanting more, then be more complex, but if you’re already going the way of adding more clarifying details, then they should be exactly that: Clarifying.
Sometimes when working in Data Analysis, an analyst is asked to describe advanced statistical findings for stakeholders who by all accounts have not been properly educated enough to fully grasp them. I always insist that this is not an excuse to treat the CEO with kid gloves. Working professionals can handle a formula or two, they just need to be presented in an attainable way.
When something you’re making for someone else needs to be complex, that’s okay. That’s when you need to go back to the previous lines in this poem. Complexity can be beautiful, but being so means not being confused. To me, complexity means many steps, but many steps on the same path. Complication is many different intertwining paths.
If your path has many steps, that’s okay, so long as your steps are clear and your path is direct.
Complicated Python Code:
def fibonacci_complicated(n):
def fib_helper(a, b, count):
return a if count == 0 else fib_helper(b, a + b, count - 1)
return 0 if n <= 0 else 1 if n == 1 else fib_helper(0, 1, n)
print(fibonacci_complicated(10)) # Output: 55
print(fibonacci_complicated(50)) # This will take a significantly long time due to inefficiency
Complex Python Code:
def fibonacci(n, memo={}):
if n <= 1:
return n
if n not in memo:
memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
return memo[n]
print(fibonacci(10)) # Output: 55
print(fibonacci(50)) # Output: 12586269025
Flat is better than nested
Just don’t tell Sir Mix-A-Lot *rimshot*
On the path to completing your code or creating your art, at times you may run into projects within projects. If building a birdhouse, you likely won’t have all of the parts and pieces ready-made sitting around you. You’ll need to make a plan, go to the store to buy the wood, cut the pieces, coat them in lacker, etc. Coding is exactly the same. You set out to accomplish one big task, but on the way you realize that there are smaller tasks that must be completed first.
However, if you were describing the process of crafting a birdhouse to a friend if you kept going down the rabbit hole of explaining every single subtask in detail before moving on to the next step, you would drive your friend crazy if you could even still call them that once you reached the end. What the typical person might do instead is mention each of the subtasks in sequence rather than delving into each of their steps. This isn’t exactly a 1:1 analogy, but I do think it demonstrates the point pretty well.
Python is a very forgiving language. For example, if you wanted to determine if 5 * 20 = 100, and you wanted to figure it out in the most annoying possible way, you could do something like this:
def dumb_calc(expression):
if expression == 0:
print("The answer is 0!")
elif expression:
if isinstance(expression, str):
parts = expression.split('*')
if len(parts) == 2:
try:
num1 = int(parts[0].strip())
num2 = int(parts[1].strip())
result = num1 * num2
if result == 100:
print("Yes, the answer is 100!")
else:
if result > 100:
print("No, the answer is greater than 100.")
else:
if result < 100:
print("No, the answer is less than 100.")
except ValueError:
print("Invalid input! Could not convert to integers.")
else:
print("Invalid format! Use 'a * b' format.")
else:
print("Invalid input! Expression should be a string.")
else:
print("Expression is None or False!")
dumb_calc("5 * 20") # “Yes, the answer is 100!”
This is “nesting” or having logical conditions within logical conditions, and is probably the worst possible way one could check to see if the expression “5 * 20” does in fact equal 100, but it’s totally valid code and runs without issue.
However, just because you can do something, doesn’t always mean that you should.
For the sake of the end-user or the audience, it’s usually best to avoid nesting when possible. Sometimes, it is unavoidable, and omitting nesting might actually infringe on one of the previous suggestions. So when possible, try to be “flat,” or to work out your logic on the same level.
This prevents the user from having to follow deeper and deeper levels of logic, reducing cognitive load.
In creative projects, this translates to how one should see moments of necessary complexity. If you’re shooting a how-to video, don’t get bogged down in details within details. It’s okay if a process has a lot of steps, just as long as those steps are clear. It’s always okay to make further how-to videos going into more detail on specific steps of the process, but if you try to cover everything in a single go, you’re going to lose people.
Nested Python Code:
def get_grade(score):
if score >= 90:
if score <= 100:
return 'A'
else:
if score >= 80:
return 'B'
else:
if score >= 70:
return 'C'
else:
if score >= 60:
return 'D'
else:
return 'F'
print(get_grade(85)) # Output: B
print(get_grade(72)) # Output: C
Flat Python Code:
def get_grade(score):
if 90 <= score <= 100:
return 'A'
if 80 <= score < 90:
return 'B'
if 70 <= score < 80:
return 'C'
if 60 <= score < 70:
return 'D'
return 'F'
print(get_grade(85)) # Output: B
print(get_grade(72)) # Output: C
Sparse is better than dense
If it needs time, let it take time! If it needs space, give it some space!
I’d wager that most astute readers are starting to get the point by now, but I’m going to continue anyway.
Towards the end of staying explicit and not fearing complexity, you may need to face the aesthetic challenge of how to arrange something that you’ve made that has a lot of moving parts.
There is a cancer infecting much of creative work nowadays and that cancer’s name is minimalism. Just because something is long does not necessarily mean that it has no audience. People make time for that which improves their lives. Don’t waste peoples’ time beating around the bush, but don’t also feel like you need to jam-pack every line of code or second of film with so much material that it overwhelms your audience.
When writing code, take your time. Use proper spacing and comment liberally even if it means your code gets a little long. When creating art, it’s okay to use empty space or to let a line of dialogue hang in the air for a moment so long as doing so accentuates a specific point or meaning. Some scenes in modern series are much longer than needed and it’s easy to tell this is simply to pad runtime. That’s not what I’m talking about here.
If you spend a ton of time creating something you’d like others to experience, it’s perfectly valid to linger on exceptional moments. Whether creating code or art, let your audience experience your creation for what it’s worth, don’t cheapen it for the sake of brevity.
So sparse is better than dense, but if I could add an addendum it would be that dense is better than vapid.
Dense Python Code:
def dense_function(x): return x*2+5 if x>10 else x/2-5
print(dense_function(15)) # Output: 35
print(dense_function(5)) # Output: -2.5
Sparse Python Code:
def sparse_function(x):
# Check if x is greater than 10
if x > 10:
# Double the value and add 5
result = x * 2 + 5
else:
# Halve the value and subtract 5
result = x / 2 - 5
return result
print(sparse_function(15)) # Output: 35
print(sparse_function(5)) # Output: -2.5
Readability counts
This might go without saying, yet in the general spirit of the poem, it should therefore still be said.
“Information wants to be free” is a famous truism attributed to Stewart Brand, co-founder of the Whole Earth Catalog. It’s something I’ve found to be generally correct. Information does seem to want to be free, but there are other forces beyond the scope of this article that prevent it from being so. Still, information certainly tries its damnedest.
Humans are social creatures. Art is created to be shared and appreciated, code is created to be used. Of course, there are exceptions, but these statements generally hold true as far as I can see.
Anything that you write, be it a novel or a Python script, should be written to be read. That is to say, you’re not writing it for yourself. Even in the case of personal diaries I’ve kept, a deep part of my psyche always keeps in mind a person who might be rifling through my things after I’ve passed.
In Python, I like to keep in mind that the functionality I depend on has all been painstakingly worked on by generations of programmers who donated their time to an open-source project. They’ve gone out of their way to make sure that the methods they wrote, the ones I’m using, were documented in such a way that I could more easily understand them.
In other creative endeavors, some of the absolute worst art that gets made gets made with only the director’s ego in mind. That’s what I think of whenever I’ve been forced to watch a Michael Bay film. They reek of someone doing it for themselves. I contrast this with George Miller’s films, which are bold and difficult to create because they don’t compromise vision for spectacle. They challenge the audience without hand-holding (Yes, even Babe and Happy Feet). His new Furiosa film is an absolute masterclass in respecting the intelligence of your audience without confounding them with density.
Bottom line, make what you make with others in mind.
Near-Illegible Python Code:
def calc_avg(nums):
if len(nums) == 0:
return None
return sum(nums) / len(nums)
print(calc_avg([10, 20, 30, 40, 50]))
print(calc_avg([]))
Readable Python Code:
def calculate_average(numbers):
"""
Calculate the average of a list of numbers.
Parameters:
numbers (list): A list of numeric values.
Returns:
float: The average of the numbers in the list. Returns None if the list is empty.
"""
if not numbers:
return None
total_sum = sum(numbers)
count = len(numbers)
average = total_sum / count
return average
if __name__ == "__main__":
sample_numbers = [10, 20, 30, 40, 50]
average_result = calculate_average(sample_numbers)
if average_result is not None:
print(f"The average of {sample_numbers} is {average_result:.2f}")
else:
print("The list is empty. Cannot calculate the average.")
Special cases aren’t special enough to break the rules
This is another one that is difficult, but not impossible, to translate to the traditional creative sphere.
The way I interpret it for coding is that methods are important. It helps whoever reads your code or whoever you give your code to parse it better. It means when teams of programmers get together, problems can be better solved using more or less the same mindsets. That means sticking to the conventions even when going off-script might be easier.
There have been times when I’ve done analysis work for someone and I need to, for whatever reason, start a secondary analysis in order to work out an ancillary problem. It is incredibly tempting in those moments, knowing this secondary project is only for me and shouldn’t come up again, to skip some of the above rules. To half-ass certain things, not be explicit, not to comment liberally, etc. I’d say 50% of the time I’ve done that, it has come back to bite me in one way or another.
Conventions are important for building a doctrine. This is as true of the arts as it is of the sciences. For my first undergraduate degree, I went to an art school. When most people think of art school, they think of handing in napkin drawings and getting sunflower stickers instead of grades. My experience couldn’t have been further from this. My art school experience was learning a lot of trade skills and a lot of methodology. Towards the end came the emphasis on learning the rules in order to know when to break the rules, but for the first three years, it was nothing but observing the masters and repeating.
Conventions allow one to build schools of thought and movements as opposed to personal styles. Every single case you encounter will technically be a “unique” or special case. No two moments in time are ever exactly the same. However, the mark of a good methodology is whether it is robust enough to handle fringe cases. Personally, I think that’s why “Pythonic” conventions function better as poems than they might as a strict set of rules.
Of course, you shouldn’t break the rules, but fortunately, the rules are structured in such a way as to allow for creative interpretation while staying safely within their bounds.
Use Case:
A developer needs to write a quick, one-off script to process a large list of numbers and find the sum of all numbers greater than a specific threshold. The script is intended to be used only once and run on a local machine, so performance and maintainability are less of a concern. The developer might be tempted to write very compact and less readable code to save time.
Non-Pythonic Solution: Compact but hard to read
threshold = 50
numbers = [12, 75, 34, 60, 23, 90, 45, 51]
result = sum(n for n in numbers if n > threshold);print(f"Sum of numbers greater than {threshold}: {result}")
Pythonic Solution: Readable and maintains conventions
def sum_above_threshold(numbers, threshold):
"""
Calculate the sum of numbers greater than a given threshold.
Parameters:
numbers (list): A list of numeric values.
threshold (int): The threshold value.
Returns:
int: The sum of numbers greater than the threshold.
"""
return sum(n for n in numbers if n > threshold)
if __name__ == "__main__":
threshold = 50
numbers = [12, 75, 34, 60, 23, 90, 45, 51]
result = sum_above_threshold(numbers, threshold)
print(f"Sum of numbers greater than {threshold}: {result}")
Although practicality beats purity
It’s function over form baby! This is a hill I will always die on.
If you need to deviate from the rules, make it count and do so in a way that creatively interprets the guiding conventions rather than outright breaking them.
In every new endeavor, you should always seek to learn its limits first. Starting down the road to studying a new science? Research first and foremost where it ends and its adjacent sciences begin. Learn its methods and its history. Find out what the best in the field do. Learn the general methodology that you “breakthrough” and see the problems the methodology was created to account for. Once you have an understanding of why the methodologies exist in the first place, only then can you experiment with new methodologies.
Rules should rarely be so rigid that they break. That is the purpose of judges. If all laws were eternal and literal, there’d rarely be a need for their interpretation! So if you must break the rules, do, but at the very least you should be able to explain precisely why you’re doing so.
Pythonic but Impractical Code Example:
import csv
def parse_csv(file_path):
"""
Parse a CSV file and extract specific columns.
Parameters:
file_path (str): The path to the CSV file.
Returns:
dict: A dictionary with extracted data.
"""
with open(file_path, newline='') as csvfile:
reader = csv.reader(csvfile)
header = next(reader)
data = {}
for row in reader:
if row:
key = row[0]
value = row[1]
data[key] = value
return data
if __name__ == "__main__":
file_path = 'data.csv'
parsed_data = parse_csv(file_path)
print(parsed_data)
Practical but Non-Pythonic Code Example:
import csv
with open('data.csv', newline='') as csvfile:
reader = csv.reader(csvfile)
header = next(reader)
data = {row[0]: row[1] for row in reader if row}
print(data)
Errors should never pass silently
Here’s a good one that I suspect you’ll know where I’m going with it.
In coding, you have various reasons why a code may fail to run. These are called runtime errors and they come in several forms. Your syntax can be even slightly off. Forgot a period? Your entire program won’t run. You might have relied too heavily on Python to assume something and it assumed differently than you expected. Tried to get the square root of the string “545”? Your program will crash. Maybe you’ve made an innocent mistake like attempting to divide by the number 0! Even if all of your datatypes and syntax are correct, your program will still throw up a big, red, embarrassing ZeroDivisionError.
This, contrary to what you might think if you don’t have much coding experience, is good! Many people love Python because it errors often and it errors specifically. Compare this with a programming language like C, which will rarely throw errors unless something is seriously wrong. You have to build in a lot of safety nets when programming in C whereas Python does a lot of the leg work for you. A lot, but not all.
The mark of a good programmer is error handling. You may have noticed the “Try” and “Except” statements in one of the previous examples. This is instructing the program to attempt something while knowing it may throw an error if something is wrong. Instead of crashing the entire program, you have contingencies built in which get put into place if a specific type of error occurs.
Some errors, like SyntaxErrors, you probably don’t want to make exceptions for. If they’re showing up, that’s the programmer’s fault and they should be fixed rather than exempt. However, a ZeroDivisionError in a calculator program may have come from a well-meaning user! We can think ahead and program a helpful message that informs the user of this mistake without crashing their device.
The more errors we can plan ahead and write exceptions for, the better. At the very least, when our programs do throw errors, we’ll better understand exactly where and why in the program the errors are occurring.
The lesson here is a universal one: Mistakes are not the enemy, mistakes are arguably the most crucial part of learning anything.
In traditional creative roles, I’ve been tempted in the past to cover up or hide mistakes that I’ve made. Perhaps in part due to my religious upbringing, my guilt usually overwhelmed me to the point of confession in those cases. I cannot recall a single time that a mistake or error on my part was as catastrophic as it seemed in my head at first. They all became teaching moments and in many cases, that was the last time I or anyone on my teams made the same mistake.
If you make a mistake or if life throws you an error, smile! You just learned something. If you’re clever, you’ll build new ways of handling that situation in the future. That is how bugs become features.
Silent Error Code:
def read_file(file_path):
with open(file_path, 'r') as file:
return file.read()
content = read_file('non_existent_file.txt')
if content:
print(content)
else:
print("File could not be read, but we don't know why.") # This part won't execute, as an exception will stop the program.
Verbose Error Handling Code:
def read_file(file_path):
try:
with open(file_path, 'r') as file:
return file.read()
except FileNotFoundError:
print(f"Error: The file at '{file_path}' was not found.")
except PermissionError:
print(f"Error: Permission denied when trying to read '{file_path}'.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
content = read_file('non_existent_file.txt')
if content:
print(content)
else:
print("File could not be read due to an error.")
… Unless explicitly silenced
Okay, not all errors are teaching opportunities. Every engineer knows that there are recurring issues that are better ignored than fixed. The trick is to be creative with your ignorance.
There are some warning messages that do more harm than good when it comes to legibility. There will be some errors in longer programs that for the life of you, you will not be able to understand why they appear, and stranger still, why the program still runs if you suppress them.
Sometimes in the name of practicality and realistic deadlines, you need Python to just shut up and trust you. You need to be REALLY sure if you’re going to do this, but you should know it’s something you can do. Many functions have a “silence_error” parameter you can enable. Just remember: if you run into problems, you didn’t hear it from me.
In creative roles, sometimes the errors come from within. Sometimes you will have internal mistakes. This should be passed over in silence or better yet, handled. Doubt, distraction, and dubious coworkers are all part of the process. Plan ahead for them, but if they tend to recur, you should know that simply ignoring them is often the best course of action.
In the face of ambiguity, refuse the temptation to guess
I’d like to wax philosophical here about method for a bit.
Going out in the woods and writing down all your observations about the bugs you encounter does not make you a biologist. Why? Because Biology is a discipline with a doctrine. It is a school of study with acolytes who perform its rituals. To become a Biologist, one must learn these precise methods so that your observations play nicely with others.
We then come to a problem: How do various kinds of “Ologists” account for new kinds of observations that are unlike that which has come before? This is where the scientific method comes in. You know the one. Hypothesis, experiment, theory, experiment, theory, etc.
Here’s the million-dollar question: Where do hypotheses come from? What method is there for coming up with them? This question has puzzled philosophers of science for millennia. Hypotheses seem to come from instinctual understandings of the subject matter. Guesses in other words.
That’s why this rule says guesses are a temptation. It’s easy to whip up a passable theory in one’s mind and carry on with it as if it were the God-given truth. The stars of reality TV shows do it all the time.
However, this is not a scientific way of carrying on. When one is faced with something that one has never encountered before, one should hope that they have the experience to have honed their instincts, which should help them in the creation of a hypothesis, which should lead them back to the method and the conducting of experiments.
You should always plan for the unknown in any field be it a creative, coding, or scientific one. Part of moving forward toward understanding will be the putting forward of educated guesses, but your process should never stop there. Ask yourself: “If my assumption were true, what would I expect to see as a result? What might be its catalysts? What would need to change to make my assumption untrue?” and then, crucially, you need to change those things to see if your assumption still holds.
The scientific way of doing this is called Hypothesis Testing, which I have my own metaphysical gripes with, but I’ll save those for another day.
There should be one — and preferably only one — obvious way to do it
This one confused me when I first started. It wasn’t until I had built a couple of programs from scratch that it started to click.
It’s one thing, in a classroom setting, to be given a specific problem and then taught a specific tool for solving that specific problem. That’s great for learning the ins and outs of various parts of the language, but it doesn’t teach you one of the most crucial aspects of programming: Knowing which of the thousands of tools at your disposal to use at any given time, without instruction.
If I wanted to write a script that once a week grabs all the top news headlines and then mails them to a list of addresses that I store on my hard drive and update occasionally, I can, off the top of my head, think of about 20 ways of doing exactly that. That is incredibly daunting at first. However, once you have a little experience under your belt and you’ve seen the kinds of things that really good programmers do, you’ll start to see that certain tools are tailor-made for certain problems.
If you are building something and you start to get the sense that there has to be an easier way, there almost certainly is. Stack Overflow is your friend here. Someone has had the same problem, someone has found some workaround, and someone has felt the white-hot shame of realizing the answer was staring them in the face all along. That is all part of it.
I have found that this extends well beyond the field of programming. Even of creative traditional endeavors. The human mind is much better at identifying “What should have been done” than it is at “What should be done.” Retrospect is a human superpower, don’t discount it.
If you do something and think, “Ah damn, I really should’ve done this a different way,” that is your brain highlighting a pattern for your future benefit. Sometimes the obvious path is only obvious in retrospect, but is still informative nonetheless. At least in programming, one has the benefit of rewriting and running again.
Keep at it, no matter what it is, and eventually, the obvious path will become clearer and clearer until it is the only one that could’ve ever been.
Although that way may not be obvious at first unless you’re Dutch
I don’t speak Dutch, but still… lol such a great line.
This line is a reference to the guy who invented Python, Guido van Rossum, who is Dutch. This means that each method within Python was made with a specific problem in mind. If the proper technique doesn’t occur to you at first, it just means you need more time to familiarize yourself with the possibilities within Python.
Since Python is open source, it means that every day new libraries and modules get created and disseminated by nobel users solving novel problems. You’re not going to ever be familiar with 100% of them, but the odds are always that no matter the problem you are facing, someone else has faced the same and, out of the kindness of their heart, published the solution for free online to make your life easier.
As an English speaker, the best clarity I can give here is to echo the previous sentiment. Just keep at it until the ambiguous becomes obvious.
Or hire a Dutch tutor.
Now is better than never
Time is a capricious B-word. All perception and reason are due to the phenomenon of time that prevents all moments from occurring in the same instant. Yet, as the giver of all, time is a precious commodity of which there is a finite supply.
Okay, now that the existential considerations are out of the way, consider the phrase “Time is money.” The trueness of that statement will vary depending on your position in your company’s org chart, but if you’re working within a goal-oriented team then to some degree it is true for you.
Most problems don’t get better with time (although there are rare exceptions). Speaking only of my own experience, I’ve found that procrastination is often a coping mechanism for fear or indifference. If I am scared of failure, I will unconsciously put something off until it becomes such a big problem that I am forced to deal with it. Literally the worst possible option. If I don’t think too highly of a problem, it will slip my mind until it becomes such a big problem that I am forced to deal with it. Literally the second-worst possible option.
The lesson here is to understand that “never” doesn’t really exist. If you are actively ignoring a problem, then it is continuing to be a problem at the very least for your wellbeing. You owe it to yourself to tackle problems early.
As a reformed procrastinator, I won’t lie to you, the road to recovery is tough and takes a lot of practice. You need to find your own ways of dealing healthily with fear or indifference or any other catalyst for your procrastination. Your solution will likely differ, but let me try to entice you to begin your journey with a major benefit I’ve discovered.
In recent years, addressing problems or tasks as soon as I possibly can has become almost like a game for me. In the early hours of encountering a new problem or being assigned a new task, you’re in the Wild West baby! No wrong answers! Go absolutely buck wild. Poke and prod. Experiment! Let the creative juices flow. Have a good time because you’ve still got all the time in the world! This kind of early exploration of a problem is fun because the stakes are still relatively low, the problem isn’t urgent yet. An added bonus is that this kind of unstructured play is the foundation of human creativity.
When you start early, you have time to play. Time to play means time to find new, creative solutions to problems. Solving problems creatively will make you feel good and help you fight against fear or indifference.
The earliest you can start is right now! If the tasks seem daunting, divide them into smaller tasks. Do something easy, then do something hard, save the medium stuff for when you’re tired later.
My dad always told me when I was growing up that the future and past are illusions. There is only right now and there will always only be right now. It took about 25 years to sink in, but I can hardly describe how much my life improved when it finally did.
Although never is often better than *right* now
I should’ve really read ahead before trying to write these tips in real-time. But this is what I mean by Peters being purposefully contradictory. He’s prodding the reader into thinking like a programmer. You need to be very methodical in an environment overrun by fringe cases. This is how you do so.
This line of the poem isn’t saying that it’s often better to never do something rather than start immediately. It’s not saying “never” has a lot of merit. It’s saying that “*right* now” often doesn’t have much merit.
It’s obviously better to start something right now as opposed to later when you can. However, that is not a universal rule. If starting something as fast as possible is going to mess up the process, then wait! It’s often better to never do something than to rush into it and mess it up.
It’s okay to take a little bit of prep time before jumping head-first into a project. If in your research you find that it would be beneficial to drop the task entirely and devote your time to something else, do! Both methods still involve starting something immediately even if that thing isn’t the main task.
In coding, this can mean reading a book exploring the kind of work you’re dealing with or searching GitHub or Stack Overflow for similar projects or problems someone else may have encountered.
When I’ve worked in traditional creative roles, if I had some lead-up time on a project, I would ask my manager for research time. It’s exceptionally hard to make something you’ve never encountered before. If you’re making a podcast, you need to listen to a lot of podcasts. Making a vlog? Watch a lot of vlogs. You get the idea.
There’s merit in jumping in head-first and playing around when it comes to projects that you are personally overseeing. However, if you’re working on a project that others have a vested interest in, it’s often best to take a breath, do some research, and jump in slightly later than *right* now with a game plan.
If the implementation is hard to explain, it’s a bad idea
I love this one. It’s applicable to so many things.
If working as a Data Analyst, one thing you’ll have to do a surprising amount of is standup meetings. Multiple times a week, you’ll have to stand up and walk someone through the logic of your analysis including your methodologies, your sources, your theories, your confirmations, etc. If you find yourself getting tripped up, it can mean a few things: You missed a more obvious solution or the entire operation was doomed from the start.
Python is built so as to incentivize clever, simple solutions to complex problems. If you can’t walk a novice through your code, I’ve gotta bring back Einstein when I say, you probably don’t understand it as well as you think you do.
Coding and traditional creative roles have in common the task of pitching managers on creative ideas. When I’ve worked in both, my day-to-day was typically being presented with a challenge or an opportunity, given a little time to come up with ideas, and then pitching those ideas to a team.
If an idea was chosen, I was expected to carry it out. Once completed, I again had to present the project to the stakeholders. Stakeholders 99.999% of the time will have MBAs and specialize in professional handshaking. They shouldn’t be expected to know what a Gaussian distribution is or be able to intuit why you opted to write your own personalized function as opposed to importing one, but if you’ve followed the above guidelines, that shouldn’t matter.
Let’s consider the inverse and following line,
If the implementation is easy to explain, it may be a good idea
If in walking someone else through your thought processes, the steps seem obvious and clear, then Python, modeled after the English language, should be able to translate those ideas to code with similar clarity.
When you’ve made something, be it a program or a video or a song or a painting, you should be able to explain in relatively simple terms why you made the decisions you did. As mentioned in the last newsletter, don’t treat your audience like morons, but don’t treat them like PhD candidates either.
One of the best ways of working an idea out for yourself is to explain it to a novice. Give it a try! If you can’t, then perhaps rethink your approach.
Just note the caveat in the second statement! It may be a good idea. If you explain something and every single person in the room nods in agreement with no follow-up questions, you may need to either aim higher or consider the idea that you might not understand the problem as well as you thought you did.
Namespaces are one honking great idea -- let's do more of those!
My one complaint is that Peters ends this a little anticlimacticly, but I think he does so because it’s a little funny so I won’t hold it against him.
We were on a thematic roll! It’s gonna kill me to end this on a technical note, so let’s see if I can really spin this one into a universal lesson one last time.
In programming, a namespace is a set of reserved identifiers or keywords that help to avoid naming conflicts. For instance, a pretty important statement in Python is the “if” statement. If I name a random variable “if” then I’ve stopped myself from being able to use conditional statements in my program completely. The built-in Python namespace reserves this keyword. When I try to run if = 123, Python stops me, throws an error, and rightfully calls me an idiot before I can do any serious damage. Thanks, namespaces.
Namespaces also help keep programs organized by separating code into logical sections and levels. Understanding namespaces means understanding how to use them to your advantage such as when they do and don’t apply.
They really are a honking good idea and Python should continue doing more of them!
Now, how I think this applies to creative roles at large is in the nomenclature of one’s field. I have worked with people from both the coding and media production disciplines who did not use precise industry terms for things they were describing. That little bit of linguistic vagueness occasionally led to crucial details getting lost in translation.
The older I get, the more I realize how much of an asset precise speech can be in any endeavor. There will always be a bit of vagueness in human language, that’s the name of the game. But minimizing it as much as possible can save you a lot of trouble.
An audio editor once told me that he had already compressed a podcast episode when he had actually equalized it. A PA once told me that they packed the C-Stands when they had actually packed the tripods. An analyst once told me that a particular dataset feature had been normalized when it had actually been standardized.
In day-to-day speech, these little differences can usually be inferred around thanks to context and the power of the human capacity for language. However, in a professional environment, misunderstanding the namespace that you are in can lead to a lot of headaches at best and unemployment at worst.
In my art school days, I noticed that a lot of my peers had a kind of phobia when it came to details so the details became my personal style! That’s why my unofficial motto has become “Don’t fear the details.” Most people give up after a couple of layers. If you can keep your focus and dig a little deeper, you will be rewarded for your understanding every time you successfully delegate an assignment or complete a team project.
Once, when giving a workshop on audio editing techniques, I decided to begin my lecture with electromagnetism and wave physics. My thought process was that in order to fully understand the abstracted environment you’re in, you have to understand the medium’s most atomic pieces which are electrons in the case of audio editing.
The purpose of The Zen of Python is to acquaint you with a poetic interpretation of the Python namespace and conventions. Programmers who adopt Pythonic programming operate like dancers who are students of the same genre. They may not always move in unison, but because they all subscribe to a similar set of defining characteristics and artistic assumptions, can be a part of a cohesive whole while still thinking independently.
I love The Zen of Python because it itself takes a unique approach to solving a decently serious problem. As mentioned at the top, having many people operating independently in a field that demands collaboration will only lead to disaster. Programming is uniquely challenging as I mentioned earlier because it is highly methodical in theory, and highly volatile in practice. This situation gets to the heart of what poetry does.
Poetry is not meant to give definite meaning. It is meant to point towards subjective truths. If poetry’s medium was objective truth, then someone would eventually write the final poem that encapsulates them all. Poetry is beautiful in its subjective incompleteness. A single poem can get close, but never capture the wondrous phenomenon of human subjectivity and thus leaves open the opportunity for future poets.
That is why I consider The Zen of Python a good poem. You have now been inducted into the cult of Python. If you obey its tenets, you should have no problems when interacting with other believers. And when the explicit rules prove to be inadequate, you will know exactly how to proceed in defining your own version of Pythonic Zen.
Recommended Book for Learning Python
I usually tell people I learned Python thrice. Once in a graduate program that expected me to already know it, once on my own, and once in an official programming class for my second undergraduate degree. The first attempt was a crash and burn, but the second was so successful that I could’ve taught the third.
The difference was the following book. It was one of many, but I’m saving the rest for a future article describing all my favorite books on Python, of which “Think Python” by Allen B. Downey is very much one.
Until next time, stay fresh.
- Casey