Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中的泛型/模板?_Python_Templates_Generic Programming - Fatal编程技术网

python中的泛型/模板?

python中的泛型/模板?,python,templates,generic-programming,Python,Templates,Generic Programming,python如何处理泛型/模板类型的场景?假设我想创建一个外部文件“BinaryTree.py”,并让它处理二叉树,但不针对任何数据类型 因此,我可以将自定义对象的类型传递给它,并拥有该对象的二叉树。这在python中是如何做到的?看看内置容器是如何做到的dict和list等包含任意类型的异构元素。例如,如果为树定义一个insert(val)函数,它将在某个时候执行类似node.value=val的操作,而Python将处理其余部分。因为Python是动态类型的,所以对象的类型在很多情况下并不重

python如何处理泛型/模板类型的场景?假设我想创建一个外部文件“BinaryTree.py”,并让它处理二叉树,但不针对任何数据类型


因此,我可以将自定义对象的类型传递给它,并拥有该对象的二叉树。这在python中是如何做到的?

看看内置容器是如何做到的
dict
list
等包含任意类型的异构元素。例如,如果为树定义一个
insert(val)
函数,它将在某个时候执行类似
node.value=val
的操作,而Python将处理其余部分。

因为Python是动态类型的,所以对象的类型在很多情况下并不重要。接受任何东西都是个好主意

为了说明我的意思,这个树类将接受其两个分支的任何内容:

class BinaryTree:
    def __init__(self, left, right):
        self.left, self.right = left, right
它可以这样使用:

branch1 = BinaryTree(1,2)
myitem = MyClass()
branch2 = BinaryTree(myitem, None)
tree = BinaryTree(branch1, branch2)

因为python是动态类型的,所以这非常简单。事实上,为了使BinaryTree类不使用任何数据类型,您必须做额外的工作

例如,如果希望通过
key()
等方法获得用于将对象放置在树中的键值,则只需对对象调用
key()
。例如:

class BinaryTree(object):

    def insert(self, object_to_insert):
        key = object_to_insert.key()
请注意,您永远不需要定义要插入的类对象的类型。只要它有一个
key()
方法,它就可以工作

例外情况是,如果您希望它处理基本数据类型,如字符串或整数。您必须将它们封装在一个类中,才能让它们与通用二进制树一起工作。如果这听起来太重了,并且您想要实际存储字符串的额外效率,那么很抱歉,这不是Python所擅长的。

Python使用的,因此它不需要特殊语法来处理多个类型

如果您来自C++背景,您会记得,只要模板函数/类中使用的操作在某个类型“代码> t>代码>(语法级别)上定义,就可以在模板中使用该类型<代码> t>代码> 所以,基本上,它的工作原理是一样的:

  • 为要插入到二叉树中的项目类型定义合同
  • 记录本合同(即在课堂文件中)
  • 仅使用合同中指定的操作实现二叉树
  • 享受

  • 但是,您会注意到,除非编写显式类型检查(通常不鼓励这样做),否则无法强制二叉树只包含所选类型的元素。

    幸运的是,python中的泛型编程已经做出了一些努力。 有一个图书馆:

    以下是它的文档:

    这几年来没有进展,但你可以大致了解如何使用和制作自己的图书馆


    干杯

    实际上,现在您可以在Python 3.5+中使用泛型了。 见和


    根据我的实践,它不是非常无缝和清晰,特别是对于那些熟悉Java泛型但仍然可用的人来说。

    在提出了一些用python创建泛型类型的好想法后,我开始寻找其他有相同想法的人,但我找不到任何人。所以,在这里。我试过了,效果很好。它允许我们在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 
    
    现在可以从该泛型类型派生类型

    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
    

    这种解决方案过于简单,而且确实有其局限性。每次创建泛型类型时,它都会创建一个新类型。因此,作为父类继承
    List(str)
    的多个类将从两个单独的类继承。为了克服这个问题,您需要创建一个dict来存储内部类的各种形式,并返回以前创建的内部类,而不是创建一个新的内部类。这将防止创建具有相同参数的重复类型。如果感兴趣,可以使用装饰器和/或元类来创建更优雅的解决方案

    如果您使用Python 2或想要重写java代码。他们并不是解决这个问题的真正办法。这是我一个晚上的工作:我仍然没有编译器,所以你现在就这样使用它:

    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)
    
    待办事项

    • 编译程序
    • 让泛型类和类型正常工作(对于
      之类的事情,这里有一个变体,它使用元类来避免混乱的语法,并使用
      类型
      -style
      列表[int]
      语法:

      类模板(类型):
      定义新(元,f):
      cls=类型.uuu新的uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu{
      "f":f,,
      “资格名称”:f.“资格名称”,
      “模块”:f.“模块”,
      “uuu doc”:f.uu doc__
      })
      cls._实例={}
      返回cls
      定义初始值(cls,f):#仅在3.5及以下版本中需要
      通过
      定义获取项目(cls,项目):
      如果不是isinstance(项,元组):
      项目=(项目,)
      尝试:
      返回cls.\u实例[项目]
      除KeyError外:
      cls.\u实例[项目]=c=cls.\u f(*项目)
      item_repr='['+','.连接(repr(i)表示item中的i)+']'
      c、 \uuuuu名称\uuuuuu=cls.\uuuuuuuu名称\uuuuuuuuu+项目报告
      c、 质量名称=cls.\uuuuu质量名称+项目报告
      c、 \uuuuu模板\uuuuu=cls
      返回c
      定义子类检查(cls,子类):
      对于子类.mro()中的c:
      如果getattr(c,'.'模板'.'无)=cls:
      返回真值
      返回错误
      定义实例检查(cls,实例):
      返回cls.\uuuu子项检查\uuuuu(类型(实例))
      定义报告(cls):
      进口检验
      返回“”。格式(“{}.{}[{}]”。格式(
      cls.模块cls.质量名称str(检查签名cls.\f))[1:-1]
      ))
      
      有了这个新的元类,我们可以将我链接到的答案中的示例重写为:

      @template
      def List(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
      
      l = List[int]()
      l.append(1)  # ok
      l.append("one")  # error
      
      这种方法有一些好处

      打印(列表)#
      打印(列表[int])#
      断言列表[int]是列表[int]
      断言issubclass(列表[int],L
      
      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
      
      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.
      
      python3 -m pip install mypy
      
      mypy foo.py
      
      mypy some_directory
      
      foo.py:23: error: Argument 1 to "push" of "Stack" has incompatible type "str"; expected "int"