Python Tutorial: Duck Typing and Asking Forgiveness, Not Permission (EAFP)
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Duck typing focuses on whether an object can perform required methods, not on whether it matches a specific class.
Briefing
Pythonic code in this lesson comes down to two closely linked habits: treat objects by what they can do (duck typing) and prefer “try it and handle failure” over “check first” (EAFP: easier to ask forgiveness than permission). Together, these approaches make code cleaner and often more robust, because they focus on behavior rather than rigid type checks.
Duck typing is introduced with a simple contrast. A “non-Pythonic” function first checks whether an incoming object is an instance of a specific class (a “duck”). If the check fails, it refuses to run. That means a “person” object—despite having the same methods—gets rejected purely because it isn’t the expected type. The Pythonic rewrite removes the type check entirely. Instead, the function directly calls the required methods (quack and fly). If the object supports those methods, the calls succeed; if not, an error occurs. The key idea is summarized as: if it walks like a duck and quacks like a duck, treat it like a duck—because the code only cares whether the object can perform the requested actions.
That leads into EAFP. The “look before you leap” style is shown as a step-by-step permission-granting approach: check whether an attribute exists, verify it’s callable, then call it—repeated for every method. The alternative is to attempt the operation immediately and catch the exception if it fails. In the example, the code tries to call quack and fly, and when a third method (bark) doesn’t exist, Python raises an AttributeError. The error is handled, and the program continues with a clear message. The same pattern is then demonstrated with dictionaries: instead of checking for each key (name, age, job), the code tries to access them and catches a KeyError when a key like job is missing.
A list example reinforces the pattern with IndexError. Rather than checking list length before accessing a specific index, the code attempts the index lookup and catches IndexError if the index doesn’t exist. The lesson also cautions that EAFP isn’t a universal rule—there are cases where targeted checks can be appropriate.
Why EAFP is often preferred: it can be faster when exceptions are rare because it avoids repeated object lookups, and it can be more readable because the “happy path” stays uncluttered by preconditions. The lesson also highlights a practical correctness issue—race conditions. A file-access example from Python documentation shows the danger of checking “can I access the file?” and then opening it later: the file’s availability can change between the check and the open. The safer approach is to try opening immediately and catch the resulting IO error if access fails.
Overall, the takeaway is pragmatic: write code that assumes the needed behavior is present, attempt the operation, and handle failures with exceptions—while using duck typing to keep interfaces flexible around capabilities instead of explicit types.
Cornell Notes
Duck typing treats objects based on behavior: if an object supports the methods a function needs, it works, regardless of its class. The lesson contrasts this with rigid type checks that reject compatible objects. EAFP (easier to ask forgiveness than permission) pairs naturally with duck typing by encouraging “try the operation, catch exceptions” instead of “check everything first.” Examples with methods, dictionaries, and lists show how AttributeError, KeyError, and IndexError can be handled cleanly. The approach is often faster and more readable, and it helps avoid race conditions by removing time gaps between checks and actions.
What does duck typing mean in practice, and how does it differ from checking an object’s type?
Why is “asking forgiveness” (EAFP) often preferred over “asking permission” (look before you leap)?
How do the dictionary and list examples demonstrate the same EAFP principle?
What performance and readability reasons are given for EAFP?
How does EAFP help avoid race conditions in the file-access example?
Review Questions
- In the duck typing example, what changes when the instance-of check is removed, and what determines whether the function succeeds?
- Compare the permission-based approach and EAFP for calling methods: what kinds of checks are eliminated, and what replaces them?
- Why can a pre-check for file access lead to a race condition, and how does the EAFP approach change the timing?
Key Points
- 1
Duck typing focuses on whether an object can perform required methods, not on whether it matches a specific class.
- 2
Removing rigid type checks can make functions work with any object that provides the needed behavior (e.g., quack and fly).
- 3
EAFP (try first, handle exceptions) replaces verbose “look before you leap” attribute/key/index checks.
- 4
AttributeError, KeyError, and IndexError become the natural signals for missing methods, missing dictionary keys, and out-of-range list indices.
- 5
EAFP can be faster when failures are rare because it avoids repeated lookups during permission checks.
- 6
EAFP often improves readability by keeping the main logic uncluttered and handling failures in exception blocks.
- 7
Pre-checks can introduce race conditions when the world changes between the check and the action; direct attempts with exception handling avoid that gap.