1

I derive from str to get strongly typed string references. They look like below, which are redundant, and I'd like to avoid the redundancy:

class VarRef(str):
    def __new__(cls, *args, **kw):
        return str.__new__(cls, *args, **kw)

class SceneRef(str):
    def __new__(cls, *args, **kw):
        return str.__new__(cls, *args, **kw)

class AmbienceRef(str):
    def __new__(cls, *args, **kw):
        return str.__new__(cls, *args, **kw)

This ensures, for example, that I need an explicit cast to get a VarRef but that otherwise it functions like a string.

I have many more and hoping there's a way to copying the same __new__ constructor for each one.

I use these only for MyPy type checking, so at runtime it'd be fine if they were normal strings. If there is a mechanism to tag them only for type checking I'd be happy to use that approach.

edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267

2 Answers2

1

Use NewType to declare a type that is functionally identical but nominal different from the base type.

from typing import NewType

URL = NewType("URL", str)
fail: URL = "Hello World"  #  Incompatible types in assignment (expression has type "str", variable has type "URL")
docs: URL = URL("https://docs.python.org/3/library/typing.html")

Keep in mind that operations on the value are still defined as usual, including their types. For example, docs + '#newtype' will still produce a str instead of a URL.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
1

You, you are looking for typing.NewType, so here:

VarRef = typing.NewType("VarRef", str)
SceneRef = typing.NewType("SceneRef", str)
AmbienceRef = typing.NewType("AmbienceRef", str)

Note, at runtime, this simply returns its argument, i.e. str, it's only for static type checking.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • Yes, at runtime I don't want a distinct type. I have other places where I do, but in those cases I'll continue to use the pattern I pasted (there are only a tiny few of those). – edA-qa mort-ora-y Feb 13 '21 at 09:53
  • 1
    @edA-qamort-ora-y yeah, I was adding that for people reading this question later, just to be clear. – juanpa.arrivillaga Feb 13 '21 at 19:44