Practical Python - Duck-typing to the rescue!
Tags: python, ducktyping
Published: 2018-10-04 14:46:07

---
title: Practical Python - Duck-typing to the rescue!
published: true
description: Ever heard about duck-typing? Ever used it? Lemme show you how
tags: python, duck-typing
---

# Duck-typing?

If it walks like a duck, quacks like a duck and swims like a duck: it's a duck.

That above is the simple definition of [duck-typing](https://en.wikipedia.org/wiki/Duck_typing), which is a great side-effect feature of non-static typed languages, like Python.

# Alright, how can I use it?

Let's consider the following object, a [Django model] (https://docs.djangoproject.com/en/2.1/topics/db/models/) (simplified for this example):

```python
class User(models.Model):
    username = models.CharField()
    full_name = models.CharField()
    address_street = models.CharField()
    address_zip = models.CharField()
    subscription = models.ForeignKey()
    pets = ArrayField(Pet())  # Consider a one-to-many relationship
```

Now, you are tasked with creating a change tracker for the user, but that change should only care about the `username` and `pets` collection (because reasons). You then create a new model similar to this:

```python
class UserChange(models.Model):
    before_username = models.CharField()
    before_pets = ArrayField(Pet())
    after_username = models.CharField()
    after_pets = ArrayField(Pet())
```

All is well, you have implemented almost every scenario, until you get to the removal of a single `Pet` from a `User`. The issue is, since the collection is loaded from the database, and you should only track the change once it is completed, it gets tricky to load the previous state. Well, you can grab the initial collection before it gets modified, that's fine, but where to store it? You can also do a [`copy.deepcopy`](https://docs.python.org/2/library/copy.html) of it, but that might sound like using a cannon to kill an ant. Then again, you only need to store the `username` and `pets` collection.

# Duck-typing to the rescue!

You can use a light-weighted and elegant solution as:

```python
class Duck:
    def __init__(self, **kwds):
        self.__dict__.update(kwds)
```

The above class takes whatever [keyword arguments](https://stackoverflow.com/questions/1769403/understanding-kwargs-in-python) you pass in and adds them as proprieties to the class and can be used as simple as:

```python
user_duck_before = Duck(username="foo", pets=["dog", "cat"])
user_duck_after = Duck(username="bar", pets=["cat"])
```

That's it. Now you can use these "ducks" on the deletion flow without much memory overhead.

This approach is similar to using [`unites.mock`](https://docs.python.org/3/library/unittest.mock.html) but with production code instead of testing code.

And to be fair, even though I already had the idea in my mind, I didn't came up with the code, I found it on [this SO post](https://stackoverflow.com/questions/2827623/how-can-i-create-an-object-and-add-attributes-to-it) which pointed me to the [code recipe](https://code.activestate.com/recipes/52308-the-simple-but-handy-collector-of-a-bunch-of-named/?in=user-97991) by [Alex Martelli](https://code.activestate.com/recipes/users/97991/). Thanks, Alex!

## Edit

I realized that something was not clear, but I didn't want to modify it in place, thus this section. What really motivated me in searching for a duck-type approach was the one-to-many collection. In my real world scenario this collection was a [`RelatedManager`](https://docs.djangoproject.com/pt-br/2.1/ref/models/relations/), which prevented me from loading the previous state after the item have been removed, thus I needed to store that info in a way that I would neither break my contract nor implement an almost identical method just for this new data structure.