Genéricos / plantillas en python?


¿Cómo maneja python los escenarios de tipo genérico/plantilla? Digamos que quiero crear un archivo externo "BinaryTree.py" y que maneje árboles binarios, pero para cualquier tipo de datos.

Así que podría pasarle el tipo de un objeto personalizado y tener un árbol binario de ese objeto. ¿Cómo se hace esto en python?

Author: igaurav, 2011-07-17

8 answers

Python usa duck typing, por lo que no necesita una sintaxis especial para manejar varios tipos.

Si viene de un fondo de C++, recordará que, siempre y cuando las operaciones utilizadas en la función/clase de la plantilla estén definidas en algún tipo T (a nivel de sintaxis), puede usar ese tipo T en la plantilla.

Así que, básicamente, funciona de la misma manera:

  1. defina un contrato para el tipo de elementos que desea insertar en el árbol binario.
  2. documento este contrato (es decir, en la documentación de la clase)
  3. implementar el árbol binario utilizando solo las operaciones especificadas en el contrato
  4. disfrute

Sin embargo, notará que a menos que escriba una comprobación de tipos explícita (que generalmente se desaconseja), no podrá imponer que un árbol binario contenga solo elementos del tipo elegido.

 47
Author: André Caron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-17 18:38:34

En realidad ahora puede usar genéricos en Python 3.5+. Véase PEP-484 y documentación de la biblioteca de mecanografía.

Según mi práctica, no es muy transparente y claro, especialmente para aquellos que están familiarizados con los genéricos de Java, pero aún se pueden usar.

 13
Author: 8bitjoey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-17 14:12:44

Dado que python se escribe dinámicamente, esto es súper fácil. De hecho, tendrías que hacer trabajo extra para que tu clase BinaryTree no funcione con ningún tipo de datos.

Por ejemplo, si desea que los valores clave que se utilizan para colocar el objeto en el árbol estén disponibles dentro del objeto desde un método como key(), simplemente llame a key() sobre los objetos. Por ejemplo:

class BinaryTree(object):

    def insert(self, object_to_insert):
        key = object_to_insert.key()

Tenga en cuenta que nunca necesita definir qué tipo de clase es object_to_insert. Mientras tenga un método key(), lo hará trabajo.

La excepción es si desea que funcione con tipos de datos básicos como cadenas o enteros. Tendrás que envolverlos en una clase para que funcionen con tu BinaryTree genérico. Si eso suena demasiado pesado y quieres la eficiencia extra de almacenar cadenas, lo siento, Python no es bueno para eso.

 3
Author: Leopd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-17 18:36:13

Debido a que Python se escribe dinámicamente, los tipos de los objetos no importan en muchos casos. Es mejor aceptar cualquier cosa.

Para demostrar lo que quiero decir, esta clase de árbol aceptará cualquier cosa por sus dos ramas:

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

Y podría usarse así:

branch1 = BinaryTree(1,2)
myitem = MyClass()
branch2 = BinaryTree(myitem, None)
tree = BinaryTree(branch1, branch2)
 3
Author: Andrea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-13 20:38:46

Después de tener algunas buenas ideas sobre hacer tipos genéricos en python, empecé a buscar a otros que tuvieran la misma idea, pero no pude encontrar ninguna. Así que, aquí está. Probé esto y funciona bien. Nos permite parametrizar nuestros tipos en 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 

Ahora puede derivar tipos de este tipo genérico.

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

Esta solución es simplista, y tiene sus limitaciones. Cada vez que cree un tipo genérico, creará un nuevo tipo. Por lo tanto, múltiples las clases que heredan List( str ) como padre serían heredar de dos clases separadas. Para superar esto, necesita crear un dict para almacenar las diversas formas de la clase interna y devolver la clase interna creada anteriormente, en lugar de crear una nueva. Esto evitaría que se crearan tipos duplicados con los mismos parámetros. Si está interesado, se puede hacer una solución más elegante con decoradores y / o metaclases.

 3
Author: Ché on The Scene,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-28 13:32:47

Afortunadamente ha habido algunos esfuerzos para la programación genérica en python . Hay una biblioteca: generic

Aquí está la documentación para ello: http://generic.readthedocs.org/en/latest /

No ha progresado durante años , pero puede tener una idea aproximada de cómo usar y hacer su propia biblioteca.

Salud

 1
Author: igaurav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-25 06:02:27

Mira cómo lo hacen los contenedores incorporados. dict y list y así sucesivamente contienen elementos heterogéneos de cualquier tipo que desee. Si defines, digamos, una función insert(val) para tu árbol, en algún momento hará algo como node.value = val y Python se encargará del resto.

 0
Author: John Zwinck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-17 18:35:22

Si utiliza Python 2 o desea reescribir el código java. Su no es la solución real para esto. Esto es lo que consigo trabajando en una noche: https://github.com/FlorianSteenbuck/python-generics Todavía no tengo compilador, por lo que actualmente lo usas así:

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

  • Compilador
  • Obtener Clases Genéricas y Tipos de trabajo (Para cosas como <? extends List<Number>>)
  • Add super support
  • Add ? support
  • Código de limpieza
 0
Author: Florian Steenbuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-18 11:29:09