# Need a way to type-hint attributes that is compatible with duck-typing

**URL:** <https://discuss.python.org/t/need-a-way-to-type-hint-attributes-that-is-compatible-with-duck-typing/41137>\
**Category:** Ideas\
**Tags:** typing\
**Created:** [December 14, 2023, 8:49pm UTC](https://discuss.python.org/t/need-a-way-to-type-hint-attributes-that-is-compatible-with-duck-typing/41137 "2023-12-14T20:49:02Z")\
**Posts on this page:** 1\
**Showing post:** 19

<div class="post-metadata">

**Author:** ![randolf-scholz](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/randolf-scholz/32/11123_2.png) [@randolf-scholz](https://discuss.python.org/u/randolf-scholz)\
**Post date:** [December 20, 2023, 10:25am UTC](https://discuss.python.org/t/need-a-way-to-type-hint-attributes-that-is-compatible-with-duck-typing/41137/19 "2023-12-20T10:25:13Z")

</div>

One way to think about it is that these modifiers can be translated into knowledge about the classes ` __getattr__ ` and ` __setattr__ ` methods (\*):

**Note:** I abbreviate `Literal["foo"]` → `"foo"`, otherwise the table gets too wide.

| Modifier | `self. __getattr__ ` | `self. __setattr__ ` |
| --- | --- | --- |
| `foo: Readable[T]` | `(name: "foo") -> T` | — |
| `foo: ReadOnly[T]` | `(name: "foo") -> T` | `(name: "foo", val: Never) -> None` |
| `foo: Writeable[T]` | — | `(name: "foo", val: T) -> None` |
| `foo: WriteOnly[T]` | `(name: "foo") -> Never` | `(name: "foo", val: T) -> None` |
| `foo: Mutable[T]` | `(name: "foo") -> T` | `(name: "foo", val: T) -> None` |

(\*) If `Never` is interpreted as the true, uninhabitable bottom type (uninhabitable means that no instances can exist, i.e. calling ` __setattr__ ` with `Literal["foo"]` and `T` is equivalent to raising an exception). It has come to my knowledge that unfortunately `Never` is not considered uninhabitable by python’s type-checkers, so possibly there needs to be another PEP to introduce a true bottom type that is uninhabitable.

> **Example of applying these principles**
>
> ```python
> class A:
> foo: Readable[int]
> bar: ReadOnly[bool]
> baz: Mutable[str]
> 
> ```
> 
> From a type-theory POV, this should be translatable to
> 
> ```python
> class A:
> @overload
> def __getattr__ (self, name: Literal["foo"]) -> int: ...
> @overload
> def __getattr__ (self, name: Literal["bar"]) -> bool: ...
> @overload
> def __getattr__ (self, name: Literal["baz"]) -> str: ...
> 
> @overload
> def __setattr__ (self, name: Literal["bar"], value: bool) -> Never: ...
> @overload
> def __setattr__ (self, name: Literal["baz"], value: str) -> None: ...
> 
> ```

**EDIT:** For `ReadOnly`, the ` __setattr__ ` might actually be better represented by `(name: "foo", val: Never) -> None` than `(name: "foo", val: T) -> Never`. This still prevents calling `obj.foo = ...`, but at the same time allows contravariant overriding, so that a subclass could replace a `ReadOnly` variable with a `Mutable` variable.

---

_[View the full topic](https://discuss.python.org/t/need-a-way-to-type-hint-attributes-that-is-compatible-with-duck-typing/41137)._
