Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics/templates in python?

People also ask

What are generic templates?

The generic template is a simple structured message that includes a title, subtitle, image, and up to three buttons. You may also specify a default_action object that sets a URL that will be opened in the Messenger webview when the template is tapped.

What are generics in Python?

Generic is a programming library for Python that provides tools for generic programming. By now, there is only one feature – multiple dispatch.

What is the difference between generics and templates?

Generics are generic until the types are substituted for them at runtime. Templates are specialized at compile time so they are not still parameterized types at runtime. The common language runtime specifically supports generics in MSIL.

What are templates in Python?

Templating in Python. Templating, and in particular web templating is a way to represent data in different forms. These forms often (but not always) intended to be readable, even attractive, to a human audience. Frequently, templating solutions involve a document (the template) and data.


The other answers are totally fine:

  • One does not need a special syntax to support generics in Python
  • Python uses duck typing as pointed out by André.

However, if you still want a typed variant, there is a built-in solution since Python 3.5.


Generic classes:

from typing import TypeVar, Generic, List

T = TypeVar('T')

class Stack(Generic[T]):
    def __init__(self) -> None:
        # Create an empty list with items of type T
        self.items: List[T] = []

    def push(self, item: T) -> None:
        self.items.append(item)

    def pop(self) -> T:
        return self.items.pop()

    def empty(self) -> bool:
        return not self.items
# Construct an empty Stack[int] instance
stack = Stack[int]()
stack.push(2)
stack.pop()
stack.push('x')        # Type error

Generic functions:

from typing import TypeVar, Sequence

T = TypeVar('T')      # Declare type variable

def first(seq: Sequence[T]) -> T:
    return seq[0]

def last(seq: Sequence[T]) -> T:
    return seq[-1]


n = first([1, 2, 3])  # n has type int.

Static type checking:

You must use a static type checker such as mypy or Pyre to analyze your source code.

Install mypy:

python3 -m pip install mypy

Analyze your source code, for example a certain file:

mypy foo.py

or directory:

mypy some_directory

mypy will detect and print type errors. A concrete output for the Stack example provided above:

foo.py:23: error: Argument 1 to "push" of "Stack" has incompatible type "str"; expected "int"

References: mypy documentation about generics and running mypy


Python uses duck typing, so it doesn't need special syntax to handle multiple types.

If you're from a C++ background, you'll remember that, as long as the operations used in the template function/class are defined on some type T (at the syntax level), you can use that type T in the template.

So, basically, it works the same way:

  1. define a contract for the type of items you want to insert in the binary tree.
  2. document this contract (i.e. in the class documentation)
  3. implement the binary tree using only operations specified in the contract
  4. enjoy

You'll note however, that unless you write explicit type checking (which is usually discouraged), you won't be able to enforce that a binary tree contains only elements of the chosen type.


Actually now you can use generics in Python 3.5+. See PEP-484 and typing module documentation.

According to my practice it is not very seamless and clear especially for those who are familiar with Java Generics, but still usable.


After coming up with some good thoughts on making generic types in python, I started looking for others who had the same idea, but I couldn't find any. So, here it is. I tried this out and it works well. It allows us to parameterize our types in python.

class List( type ):

    def __new__(type_ref, member_type):

        class List(list):

            def append(self, member):
                if not isinstance(member, member_type):
                    raise TypeError('Attempted to append a "{0}" to a "{1}" which only takes a "{2}"'.format(
                        type(member).__name__,
                        type(self).__name__,
                        member_type.__name__ 
                    ))

                    list.append(self, member)

        return List 

You can now derive types from this generic type.

class TestMember:
        pass

class TestList(List(TestMember)):

    def __init__(self):
        super().__init__()


test_list = TestList()
test_list.append(TestMember())
test_list.append('test') # This line will raise an exception

This solution is simplistic, and it does have it's limitations. Each time you create a generic type, it will create a new type. Thus, multiple classes inheriting List( str ) as a parent would be inheriting from two separate classes. To overcome this, you need to create a dict to store the various forms of the inner class and return the previous created inner class, rather than creating a new one. This would prevent duplicate types with the same parameters from being created. If interested, a more elegant solution can be made with decorators and/or metaclasses.