2010-09-20 11 views
22

he definido una clase Vector que tiene tres variables de las propiedades: x, y y z. Coordenadas tienen que ser números reales, pero no hay nada que impida que uno haga lo siguiente:Seguridad de tipos en Python

>>> v = Vector(8, 7.3, -1) 
>>> v.x = "foo" 
>>> v.x 
"foo" 

pude poner en práctica "la seguridad de tipos" de esta manera:

import numbers 

class Vector: 
    def __init__(self, x, y, z): 
     self.setposition(x, y, z) 

    def setposition(self, x, y, z): 
     for i in (x, y, z): 
      if not isinstance(i, numbers.Real): 
       raise TypeError("Real coordinates only") 

     self.__x = x 
     self.__y = y 
     self.__z = z 

    @property 
    def x(self): 
     return self.__x 

    @property 
    def y(self): 
     return self.__y 

    @property 
    def z(self): 
     return self.__z 

... pero que parece in- Pythonic.

Sugerencias?

+0

¿Pero por qué? Los enteros funcionan totalmente. –

+0

Entiendo que este tipo de inquietudes suelen venir con grandes proyectos/equipo. Si la seguridad de tipo es algo que te atrae mucho, te sugiero que eches un vistazo a Scala. – BlueSky

Respuesta

17

Debe preguntarse por qué quiere probar el tipo al establecer estos valores. Simplemente levante un TypeError en cualquier cálculo que se encuentre con el tipo de valor incorrecto. Bonificación: las operaciones estándar ya lo hacen.

>>> 3.0/'abc' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
TypeError: unsupported operand type(s) for /: 'float' and 'str' 
+2

Y luego escriba un conjunto completo de pruebas unitarias que ejerzan todas las ramas de su código, para captar sus TypeErrors antes que sus usuarios. ¿Derecha? De todos modos, con respecto a cuándo debe lanzarse el error: si usted sabe que una determinada combinación no es válida y causará problemas, ¿no sería mejor/más claro fallar lo antes posible? ¿Fallar al principio hace que encontrar el problema de raíz sea mucho más fácil? (Supongo que el "por qué es inválido" es menos claro, sin embargo). –

+1

Creo que la pregunta era sobre LBYL vs. EAFP, por lo que de manera "pitonica" tiene sentido no solo "permitir" los tipos que originalmente se pretendía . Para un resultado "mal conocido", tiene mucho sentido cortar su camino de ejecución (subir). – knitti

4

Pero no hay nada que impida que uno haga lo siguiente:

Creo que tratar de detener a alguien de hacer algo como esto es un-Pythonic. Si es necesario, entonces debe verificar el tipo de seguridad durante las operaciones que pueda hacer usando Vector, en mi opinión.

Para citar G.V.R:

todos somos adultos.

después de todo. Consulte esto question y sus respuestas para obtener más información.

Estoy seguro de que los Pythonistas más experimentados aquí pueden darle mejores respuestas.

12

Duck Typing es la forma habitual en Python. Debería funcionar con cualquier cosa que se comporte como un número, pero no necesariamente es un número real.

En la mayoría de los casos en Python uno no debe verificar explícitamente los tipos. Obtiene flexibilidad porque su código se puede usar con tipos de datos personalizados, siempre que se comporten correctamente.

4

Las otras respuestas ya indicaron que no tiene mucho sentido comprobar el tipo aquí. Además, tu clase no será muy rápida si está escrita en Python puro.

Si desea una solución más Pythonic - se puede utilizar como definidores de propiedad:

@x.setter 
def x(self, value): 
    assert isinstance(value, numbers.Real) 
    self.__x = value 

La sentencia assert se eliminará cuando se deshabilita la depuración o activar el modo de optimización.

Como alternativa, podría forzar value a punto flotante en el colocador.Eso generará una excepción si el tipo/valor no es convertible:

@x.setter 
def x(self, value): 
    self.__x = float(value) 
2

Se supone que no debe proporcionar seguridad de tipo de esta manera. Sí, alguien puede romper su código de forma deliberada mediante el suministro de valores para los cuales su contenedor no funcionará, pero esto es exactamente lo mismo con otros idiomas. E incluso si alguien pone el valor correcto para un parámetro en un método o función de miembro no necesariamente significa que no está roto: si un programa espera una dirección IP, pero usted pasa un nombre de host, todavía no funcionará, aunque ambos pueden estar instrumentos de cuerda.

Lo que estoy diciendo es: La mentalidad de Python es inherentemente diferente. Duck typing básicamente dice: hey, no estoy limitado a ciertos tipos, sino a la interfaz, o el comportamiento de los objetos. Si un objeto actúa como si fuera el tipo de objeto que yo esperaría, no me importa, solo hazlo.

Si intenta introducir la verificación de tipos, básicamente limitará una de las características más útiles del idioma.

Dicho esto, realmente necesita entrar en un desarrollo impulsado por pruebas o, al menos, pruebas unitarias. Realmente no hay excusa para no hacerlo con lenguajes dinámicos: simplemente se está moviendo en la forma en que los errores se detectan en otro paso del proceso de compilación, desde el tiempo de compilación hasta la ejecución de un conjunto de pruebas varias veces al día. Si bien esto parece un esfuerzo adicional, en realidad reducirá el tiempo dedicado a la depuración y corrección de código, ya que es una forma inherentemente más poderosa para detectar errores en su código.

Pero ya basta de eso, ya estoy divagando.

+0

Aunque "interfaz" es un nombre poco apropiado aquí, porque nunca se define explícitamente ninguna interfaz (excepto con suerte en los comentarios). Duck typing significa que realmente has examinado o ejecutado el código para ver qué es la "interfaz". En mi experiencia (limitada) en Python, este es el mayor inconveniente para escribir patos. Escribir mi propio código es más rápido, pero hacer uso de la API no documentada de otra persona (por ejemplo, escribir un complemento) es mucho más difícil, por lo que los comentarios se vuelven más cruciales. –

+1

Las pruebas de unidades son geniales, pero pasar las pruebas en un depurador no es la forma más óptima de aprender qué tipo de patos espera obtener cada método, es decir, cómo usar la API correctamente. Y es difícil garantizar que su prueba de unidad siempre cubra todos los casos extremos. –

Cuestiones relacionadas