Two Python ‘features’ I learned today

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.




No Comments


You can leave the first : )



Leave a Reply

Your email address will not be published. Required fields are marked *