Implementing View Types in Python
Tags: python, coding, programming, patterns
Published: 2020-01-12 03:54:50

---
title: Implementing View Types in Python
published: true
description: A pattern to implement view types that truly hide implementation details in Python
tags: Python, Coding, Programming, Patterns
cover_image: https://miro.medium.com/max/1920/0*fNBo-jVoO-eSl23r.jpg 
---

In object-oriented languages like Java, C#, or Kotlin, given a type `T`, an associated *view type* `TView` is used to expose a specific view (parts) of an object of type `T`. This helps hide implementation details.

For example, in the following [Kotlin](https://kotlinlang.org/) example, `Ledger` interface is used to provide access to a ledger while hiding the underlying implementation details, i.e., `LedgerImpl` provides the functionalities of a ledger and it has a `process` and `container` members.

```kotlin
interface Ledger {
    fun getValue(i: Int): Int?
}

class LedgerImpl: Ledger {
    val container = HashMap<Int, Int>()

    override fun getValue(i: Int) = container.get(i)

    fun process() {
        // processing
    }
}

fun getLedger(): Ledger {
    val c = LedgerImpl()
    c.process()
    return c as Ledger
}
```

# Can we achieve the same in Python?

Yes, we can mimic the above code structure in Python as follows.

```python
from abc import ABC
from collections import defaultdictclass Ledger(ABC):
    def get_value(self, i: int) -> int:
        passclass _LedgerImpl(Ledger):

    def __init__(self):
        self._container = defaultdict(int)

    def get_value(self, i: int) -> int:
        return self._container[i]    def process(self) -> None:
        ...

def facade() -> Ledger:
    l = _LedgerImpl()
    l.process()
    return l
```

While `_container` is marked as private by convention (i.e., the name is prefixed with an underscore), callers of `facade` can still access `_container` in the returned value as Python does not enforce access restrictions at runtime. So, the implementation details are not truly hidden.

# Can we do better?

(Accidentally) Yes, we can do better. We can use `namedtuple` support in Python to realize the view type.

```python
from abc import ABC
from collections import defaultdict
from typing import Callable, NamedTuple

class Ledger(NamedTuple):
    get_value: Callable[[int], int]

class _LedgerImpl():
    def __init__(self):
        self._container = defaultdict(int)

    def process(self) -> None:
        ...

    def get_view(self) -> Ledger:
        return Ledger(lambda x: self._container[x])

def facade() -> Ledger:
    l = _LedgerImpl()
    l.process()
    return l.get_view()
```

With this implementation, unless we thread our way thru the lambda function created in `get_view`, the implementation details stay truly hidden when compared to the previous Python implementation.

Also, this implementation pattern relies on composition instead of inheritance. While the earlier implementation pattern can be changed to use composition, it still does not truly hide implementation details.

# When should we use this pattern?

This pattern is ideal to use when implementation details need to be truly hidden.

And, here’s my yardstick for when should implementation details be truly hidden.

If the client programs of a library/program will respect the access restrictions communicated via conventions, then this pattern is not helpful/required. This is most likely the case when modules within a library or program act as clients of other modules in a library or program. In these situation, simpler realizations of view types (e.g., the first python example) will suffice.

On the other hand, if client programs may take dependence on the implementation of a library/program (e.g., for performance reasons) when the current version of the library/program does not support the capabilities need by the client programs, then this pattern can be helpful to truly hide the implementation.

# Note
I stumbled on this pattern during my coding sessions. Since I found it to be interesting and useful, I blogged about it. That said, as with all patterns, use them only when they are required.

(Originally posted [here.](https://medium.com/@rvprasad/implementing-view-types-in-python-7bed2d2c2a1c))