Generics/templates in python?

前端 未结 10 1427
深忆病人
深忆病人 2020-12-22 19:16

How does python handle generic/template type scenarios? Say I want to create an external file \"BinaryTree.py\" and have it handle binary trees, but for any data type.

相关标签:
10条回答
  • 2020-12-22 19:30

    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.

    0 讨论(0)
  • 2020-12-22 19:33

    If you using Python 2 or want to rewrite java code. Their is not real solution for this. Here is what I get working in a night: https://github.com/FlorianSteenbuck/python-generics I still get no compiler so you currently using it like that:

    class A(GenericObject):
        def __init__(self, *args, **kwargs):
            GenericObject.__init__(self, [
                ['b',extends,int],
                ['a',extends,str],
                [0,extends,bool],
                ['T',extends,float]
            ], *args, **kwargs)
    
        def _init(self, c, a, b):
            print "success c="+str(c)+" a="+str(a)+" b="+str(b)
    

    TODOs

    • Compiler
    • Get Generic Classes and Types working (For things like <? extends List<Number>>)
    • Add super support
    • Add ? support
    • Code Clean Up
    0 讨论(0)
  • 2020-12-22 19:34

    Fortunately there has been some efforts for the generic programming in python . There is a library : generic

    Here is the documentation for it: http://generic.readthedocs.org/en/latest/

    It hasn't progress over years , but you can have a rough idea how to use & make your own library.

    Cheers

    0 讨论(0)
  • 2020-12-22 19:44

    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
    
    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.
    

    Reference: mypy documentation about generics.

    0 讨论(0)
  • 2020-12-22 19:45

    Because Python is dynamically typed, the types of the objects don't matter in many cases. It's a better idea to accept anything.

    To demonstrate what I mean, this tree class will accept anything for its two branches:

    class BinaryTree:
        def __init__(self, left, right):
            self.left, self.right = left, right
    

    And it could be used like this:

    branch1 = BinaryTree(1,2)
    myitem = MyClass()
    branch2 = BinaryTree(myitem, None)
    tree = BinaryTree(branch1, branch2)
    
    0 讨论(0)
  • 2020-12-22 19:46

    Since python is dynamically typed, this is super easy. In fact, you'd have to do extra work for your BinaryTree class not to work with any data type.

    For example, if you want the key values which are used to place the object in the tree available within the object from a method like key() you just call key() on the objects. For example:

    class BinaryTree(object):
    
        def insert(self, object_to_insert):
            key = object_to_insert.key()
    

    Note that you never need to define what kind of class object_to_insert is. So long as it has a key() method, it will work.

    The exception is if you want it to work with basic data types like strings or integers. You'll have to wrap them in a class to get them to work with your generic BinaryTree. If that sounds too heavy weight and you want the extra efficiency of actually just storing strings, sorry, that's not what Python is good at.

    0 讨论(0)
提交回复
热议问题