Every programming language has its own funny, unusual, and good-to-know language constructs. Today, I came to learn two such language constructs in Python.
Finding a needle in a haystack
Consider the following way to check if a needle exists in a haystack:
print("Needle" in "Haystack")
When run, this will print False, as one would expect, since “Haystack” doesn’t contain a substring “Needle”. Python can also check if the “Needle” in a list or tuple, like this:
print("Needle" in ["Needless"]) print("Needle" in ("Needless"))
The first would print False, since “Needle” as a whole word is not an element in the list. The second however would print True, because the 1-tuple is not defined correctly. Consequently, the parenthesis are ignored and “Needle” is found a substring of “Needless”. When the 1-tuple is defined the right way (note the trailing comma) False will be printed:
print("Needle" in ("Needless",))
Something to be aware of!
Using a default value for a function argument
It is very convenient to be able to specify some default value for function arguments. For example like this:
def print_message(message, log_level="INFO"): if log_level is "INFO": print("INFO: ", message) elif log_level is "WARNING": print("WARNING:", message) elif log_level is "ERROR": print("ERROR ", message)
If we would call the function with print_message(“Smells like teen spirit”), the “INFO: Smells like teen spirit” would be printed. Note here that the default value for log_level is immutable; it is a string constant, not an object. Now consider the following:
def add_to_basket(item, basket=): basket.append(item) return basket if __name__ in "__main__": print add_to_basket("Bananas") print add_to_basket("Apple") print add_to_basket("Pear")
Since basket a function argument, I would expect it to have a scope local to the function. In reality however, the three print statements would subsequently output:
['Bananas'] ['Bananas', 'Apple'] # and ['Bananas', 'Apple', 'Pear']
In other words, basket behaves like a static variable in C would. It appears that Python treats functions just like classes, and that default function arguments are a kind of member data. As long as the default value is immutable you won’t experience this behavior, but when it is a mutable value (a list, dictionary, or other object) the function argument will behave this way.
Good to keep in mind that if I need to use an mutable object as default argument value, I should use the value None and check for this value inside the function in order to set it to its actual default value, e.g.:
def add_to_basket(item, basket=None): if basket is None: basket= basket.append(item) return basket
In case basket equals None, the above example would return a list with only the given item in it.