This article discusses the concept of duck typing in Python, a feature of dynamically typed languages, and provides practical examples of its usage in iterators, callables, and sorting with len().
Abstract
Duck typing is a concept in programming that emphasizes the implementation of related functionalities rather than the specific data types. In Python, a dynamically typed language, duck typing allows for flexibility in working with different data types as long as they implement the required methods. The article provides practical examples of using duck typing in iterators, callables, and sorting with len(), demonstrating its usefulness in Python projects.
Opinions
Duck typing is a feature of dynamically typed languages like Python and JavaScript, which allows for flexibility in working with different data types.
In Python, duck typing can be applied to custom data types by implementing the required methods, as demonstrated in the conceptual example.
The article provides practical examples of using duck typing in iterators, callables, and sorting with len(), showcasing its usefulness in Python projects.
Duck typing emphasizes the implementation of related functionalities rather than the specific data types, making it a powerful tool for working with mixed lists of elements of different data types.
The broader implication of using duck typing is that as long as each data type implements the same functions, the elements will pass the duck testing and be applied with the proper operations.
The article highlights the importance of understanding duck typing in Python and provides examples of its usage in practical scenarios.
The takeaway from the article is that duck typing is a powerful tool for working with different data types in Python, emphasizing the implementation of related functionalities rather than the specific data types.
Duck typing shouldn’t be an unfamiliar concept to seasoned programmers. For new learners, it may sound to be an interesting phrase. What do ducks have anything to do with programming?
From a retrospective perspective, this concept is adapted from the following expression as a form of abductive reasoning, as you can find on Wikipedia.
If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.
We don’t need to relate this expression to programming for now, but we should’ve already noticed that this expression pertains to how we can identify a duck. In essence, we don’t need to have a genomic sequencing of the animal of interest to know its identity. Instead of approaching the internal factors, we draw our conclusion based on its external appearance and behaviours.
If I encounter a duck-like bird that swims and quacks just like a duck in real life, I will call it a duck, so will my 8-year-old daughter. There’s no rocket science, but just simple life experience that leads to the possibly best-educated guess.
All kidding aside, what’s the relevance of duck typing to programming, particularly to Python — the language of interest for the present article?
Dynamic vs. Static Typing
The concept of duck typing has been mostly adopted in programming languages that support dynamic typing, such as Python and JavaScript. In these languages, a common feature is that we declare variables without the need to specify their types. Later in the code, if we wish, we can assign other data types to these variables. Some examples in Python are given below.
As you can see from the above code snippet, we initially assigned an integer to the variable a, making it of the int type. Later, we assigned a string and a list of numbers to the same variable, and the type became str and list, respectively. The interpreter didn’t complain about the change of data types of the same variable.
By contrast, many other kinds of programming languages feature static typing, such as Java and Swift. When we declare variables, we need to be specific about the data types of these variables. Later, if we wish to change the data type, the compiler won’t allow us to do that, as it’s inconsistent with the initial declaration. The following figure shows you what happened when I was trying to do the same things using Swift instead of Python.
Static Typing in Swift
As you can see, the code couldn’t be compiled, because we couldn’t assign a string or an array to a, which was initially declared as an integer.
Conceptual Example
In the above section, we’ve mentioned that Python is a dynamically typed language, as shown with the most basic example involving built-in data types. However, we can further apply dynamic typing to custom data types. Let’s see a conceptual example below.
In the code snippet above, we can see that an instance of the Duck class can certainly swim and quack as reflected by the success of calling the duck_testing function. It is also true for the RoboticBird class, which also implements the needed swim_quack function. However, the Fish class doesn’t implement the swim_quack function, resulting in its instance to fail the duck testing evaluation.
Taking these observations, we should understand an essential notation for duck typing here. When we use custom types for particular purposes, the implementation of related functionalities is more important than the exact types of data. In our example, even though a robotic bird isn’t a real duck, but its implementation of the swim_quack function “makes” it a duck — an animal that swims and quacks.
Practical Examples
Iterators
In Python, iteration allows us to go over a list of items to perform particular operations. One common way to create an iteration is to use the for loops, which have the following general format.
for i in iterable:
expression
As discussed in my previous article, we can create our custom iterators that can be used as iterables in the for loops. To satisfy the “duck testing” for iterators, the custom class needs to implement the __iter__() and __next__() methods. A specific example is given below.
In the above code snippet, we implemented both __iter__() and __next__() methods that make the instances of the custom class Cubes iterators, such that the instance was able to be used in a for loop.
Callables
Besides the built-in dict data type, another important dictionary type is defaultdict, available in the collections module. This dictionary-like data type has the following constructor: defaultdict([default_factory[, ...]]). Specifically, the default_factory argument is a type of callable, such as a function or lambda function.
In my previous article, I showed that we could utilize the defaultdict by passing a lambda function. Here’s the example of its usage.
Notably, we can have better flexibility to use the defaultdict data type if we create our own default factory. With the “duck typing” philosophy, the custom class needs to implement the __call__() method, which is to make something callable. Let’s see how it works.
As shown in the above code, we create the DucklingFactory class, whose __call__() function returns a list of one Duckling instance. Using this factory function, we’ll be able to make the desired number of ducklings by multiplying the default duckling list.
Sorting With Len()
Another possible usage of duck typing is to implement the custom len() function, which can be used in sorting a list using the sort() function. As a side note, some people refer to the len() function as a magic function, because it’s implemented by calling the __len__() function behind the scene (those functions with double underscores as prefix and suffix are called magic functions).
Suppose that we want to sort a list of ducks based on the length of the name of each duck. Here’s how we can apply the duck typing in this case.
In the above code snippet, the custom NamedDuck class implements the __str__() and __len__() functions, which enable us to use the str() and len() functions on its instances in Lines 10 and 12, respectively. Importantly, as you can see, although the list is mixed with named ducks and strings, all elements can call the str() and len() functions, such that the list can be sorted using the len() as the key and used in the list comprehension when we want to print out the sorted result.
Thus, the broader implication of this usage is that when we have a mixed list of elements of different data types, as long as each data type implements the same functions, the elements will pass the duck testing and be applied with the proper operations. Here’s a general use case example using the len() function on a mixed list of data types of str, tuple, and list.
In this article, we reviewed what duck typing is and its general background related to the dynamic typing feature of Python and other programming languages. In the conceptual example, you saw what duck typing meant in Python. Notably, I presented three specific examples that you could apply to your Python projects.
The most crucial takeaway is that duck typing emphasizes the implementation of related functionalities, and the specific data types are less important.