Python parece estar de moda en estos días, y no sin mérito, ya que es realmente un lenguaje con el que casi disfruta que se le dé un nuevo problema para resolver. Pero, como dijo un sabio una vez (llamándolo sabio solo porque no tengo idea de quién lo dijo realmente; no estoy seguro de si era tan sabio), saber realmente un idioma no solo sabe ventajas de sintaxis, diseño, etc., pero también sus inconvenientes. Ningún idioma es perfecto, algunos son mejores que otros.
Entonces, ¿cuáles serían, en su opinión, inconvenientes objetivos de Python?
Nota: No estoy pidiendo una comparación de idioma aquí (es decir, C # es mejor que Python porque ... yadda yadda yadda), más que una opinión objetiva (hasta cierto nivel) qué características del lenguaje están mal diseñadas, si, cuáles son algunos te faltan, etc. Debe usar otro idioma como comparación, pero solo para ilustrar un punto que sería difícil de explicar de otra manera (es decir, para facilitar la comprensión)
Respuestas:
Utilizo Python de forma regular y, en general, considero que es un lenguaje muy bueno. Sin embargo, ningún idioma es perfecto. Aquí están los inconvenientes en orden de importancia para mí personalmente:
Es lento. Quiero decir muy, muy lento. Muchas veces esto no importa, pero definitivamente significa que necesitará otro idioma para esos bits críticos de rendimiento.
Las funciones anidadas son un asco porque no se pueden modificar las variables en el ámbito externo. Editar: todavía uso Python 2 debido al soporte de la biblioteca, y este error de diseño me irrita muchísimo, pero aparentemente se solucionó en Python 3 debido a la declaración no local . No puedo esperar a que las bibliotecas que utilizo sean portadas para que esta falla pueda enviarse al montón de la historia para siempre.
Faltan algunas características que pueden ser útiles para la biblioteca / código genérico y, en mi humilde opinión, la simplicidad se lleva a extremos insalubres. Los más importantes en los que puedo pensar son los tipos de valores definidos por el usuario (supongo que se pueden crear con magia de metaclase, pero nunca lo he intentado) y el parámetro de función ref.
Está lejos del metal. ¿Necesita escribir primitivas de subprocesamiento o código de kernel o algo así? Buena suerte.
Si bien no me importa la falta de capacidad para detectar errores semánticos por adelantado como una compensación por el dinamismo que ofrece Python, desearía que hubiera una forma de detectar errores sintácticos y cosas tontas como escribir nombres de variables sin tener que ejecutar el código.
La documentación no es tan buena como los lenguajes como PHP y Java que tienen fuertes respaldos corporativos.
fuente
with
declaración o los métodos en alist
. Todo lo cubierto en el tutorial es básicamente inescrutable. Tengo mucha mejor suerte con la documentación de Microsoft para C ++.Odio que Python no pueda distinguir entre declaración y uso de una variable. No necesita escribir estática para que eso suceda. Sería bueno tener una manera de decir "esta es una variable que declaro deliberadamente, y tengo la intención de introducir un nuevo nombre, esto no es un error tipográfico".
Además, generalmente uso las variables de Python en un estilo de escritura única, es decir, trato las variables como inmutables y no las modifico después de su primera asignación. Gracias a características como la comprensión de la lista, esto es realmente increíblemente fácil y hace que el código fluya más fácilmente.
Sin embargo, no puedo documentar ese hecho. Nada en Python me impide sobrescribir o reutilizar variables.
En resumen, me gustaría tener dos palabras clave en el idioma:
var
ylet
. Si escribo en una variable no declarada por ninguno de esos, Python debería generar un error. Además,let
declara las variables como de solo lectura, mientras que lasvar
variables son "normales".Considere este ejemplo:
Tenga en cuenta que los tipos siguen siendo implícitos (pero las
let
variables son para todos los propósitos y tipos estánticamente tipados, ya que no pueden volver a un nuevo valor, mientras que lasvar
variables aún pueden tipearse dinámicamente).Finalmente, todos los argumentos del método deberían ser automáticamente
let
, es decir, deberían ser de solo lectura. En general, no hay una buena razón para modificar un parámetro, excepto por el siguiente modismo:Esto podría ser reemplazado por un idioma ligeramente diferente:
fuente
use strict;
yuse warnings;
en perl en un guión de cualquier tamaño. Python ha despojado al desarrollador de demasiadas ayudas de depuración.var
ylet
(o un mecanismo similar) es un inconveniente. Dicho de otra manera: si hubiera sido el diseñador de Python, habría hecho algo como esto. Dicho esto , las versiones futuras podrían incluir esto cuando cargue un paquete especial (similar a__future__
). Decirimport strict
. Sin embargo, esto no sucederá, ya que requiere hacks sintácticos ...Mi queja principal es el enhebrado, que no es tan eficaz en muchas circunstancias (en comparación con Java, C y otros) debido al bloqueo global del intérprete (consulte la charla "Inside the Python GIL" (enlace PDF) )
Sin embargo, hay una interfaz multiproceso que es muy fácil de usar, sin embargo, será más pesado en el uso de memoria para el mismo número de procesos frente a subprocesos, o difícil si tiene muchos datos compartidos. Sin embargo, el beneficio es que una vez que tiene un programa trabajando con múltiples procesos, puede escalar en múltiples máquinas, algo que un programa de subprocesos no puede hacer.
Realmente no estoy de acuerdo con la crítica de la documentación, creo que es excelente y mejor que la mayoría, si no todos los idiomas principales.
También puede detectar muchos de los errores de tiempo de ejecución que ejecutan pylint .
fuente
Podría decirse que la falta de tipeo estático, que puede introducir ciertas clases de errores de tiempo de ejecución , no vale la flexibilidad adicional que brinda el tipeo de pato.
fuente
int foo = 4; Console.Write(foo.Length);
no se compila, por lo que el error "Int32 no tiene una propiedad Longitud" no puede aparecer accidentalmente en el software publicado. En python, a menos que ejecute herramientas secundarias opcionales para buscar errores como ese, el código que accede a miembros de objetos no existentes puede pasar desapercibido hasta que termine causando errores de tiempo de ejecución.Creo que las partes orientadas a objetos de Python se sienten "atornilladas". Toda la necesidad de pasar explícitamente "self" a cada método es un síntoma de que su componente OOP no se planificó expresamente , se podría decir; también muestra las reglas de alcance a veces vergonzosas de Python que fueron criticadas en otra respuesta.
Editar:
Cuando digo que las partes orientadas a objetos de Python se sienten "atornilladas", quiero decir que a veces, el lado de la POO se siente bastante inconsistente. Tomemos Ruby, por ejemplo: en Ruby, todo es un objeto, y se llama a un método usando la
obj.method
sintaxis familiar (con la excepción de los operadores sobrecargados, por supuesto); en Python, todo es también un objeto, pero algunos métodos se llaman como una función; es decir, se sobrecarga__len__
para devolver una longitud, pero se llama utilizando enlen(obj)
lugar del másobj.length
común (y consistente) común en otros idiomas. Sé que hay razones detrás de esta decisión de diseño, pero no me gustan.Además, el modelo OOP de Python no tiene ningún tipo de protección de datos, es decir, no hay miembros privados, protegidos y públicos; puedes imitarlos usando
_
y__
frente a métodos, pero es un poco feo. Del mismo modo, Python tampoco entiende bien el aspecto de paso de mensajes de OOP.fuente
Cosas que no me gustan de Python:
lambda
solo puede contener una expresión).cin
oscanf
en C ++ y C oScanner
en Java).fuente
raw_input
y 'sys.stdin' son bastante simples. No admiten la entrada formateada (por ejemplo, algo como "% d:% d:% d"% (hora, minuto, segundo) para leer a tiempo). Hasta ahora, Python no tiene nada parecido a la funcionalidad de scanf (en C) o Scanner (Java).Argumentos predeterminados con tipos de datos mutables.
Suele ser el resultado de algunos errores sutiles. Creo que sería mejor si creara un nuevo objeto de lista siempre que se requiriera un argumento predeterminado (en lugar de crear un solo objeto para usar en cada llamada a la función).
Editar: no es un gran problema, pero cuando algo necesita ser referido en los documentos, generalmente significa que es un problema. Esto no debería ser obligatorio.
Especialmente cuando eso debería haber sido el valor predeterminado. Es solo un comportamiento extraño que no coincide con lo que cabría esperar y no es útil para una gran cantidad de circunstancias.
fuente
Algunas de las características de Python que lo hacen tan flexible como un lenguaje de desarrollo también son vistas como inconvenientes importantes por aquellos utilizados para el análisis estático de "todo el programa" realizado por el proceso de compilación y enlace en lenguajes como C ++ y Java.
Las variables locales se declaran utilizando la instrucción de asignación ordinaria. Esto significa que los enlaces de variables en cualquier otro ámbito requieren una anotación explícita para ser recogida por el compilador (declaraciones globales y no locales para ámbitos externos, notación de acceso a atributos, por ejemplo, ámbitos). Esto reduce enormemente la cantidad de repeticiones necesarias cuando se programa, pero significa que se necesitan herramientas de análisis estático de terceros (como pyflakes) para realizar comprobaciones manejadas por el compilador en lenguajes que requieren declaraciones de variables explícitas.
El contenido de los módulos, los objetos de clase e incluso el espacio de nombres incorporado se puede modificar en tiempo de ejecución. Esto es enormemente poderoso, permitiendo muchas técnicas extremadamente útiles. Sin embargo, esta flexibilidad significa que Python no ofrece algunas características comunes a los lenguajes OO de tipo estático. En particular, el parámetro "self" para los métodos de instancia es explícito en lugar de implícito (dado que los "métodos" no tienen que definirse dentro de una clase, se pueden agregar más tarde modificando la clase, lo que significa que no es particularmente práctico para pasar la referencia de instancia implícitamente) y los controles de acceso a los atributos no se pueden aplicar fácilmente en función de si el código está "dentro" o "fuera" de la clase (ya que esa distinción solo existe mientras se ejecuta la definición de clase).
Esto también es cierto para muchos otros lenguajes de alto nivel, pero Python tiende a abstraer la mayoría de los detalles del hardware. Los lenguajes de programación de sistemas como C y C ++ siguen siendo mucho más adecuados para manejar el acceso directo al hardware (sin embargo, Python hablará con ellos con gusto a través de los módulos de extensión CPython o, de manera más portátil, a través de la
ctypes
biblioteca).fuente
Ejemplo de alcance roto; transcripción de la sesión de intérprete:
global
ynonlocal
se han introducido palabras clave para corregir esta estupidez de diseño.fuente
global
ononlocal
en Python. Tan raramente que olvido que este problema existe y tengo que volver a buscarlo en Google las pocas veces que aparece, a pesar de que escribo código Python todos los días en el trabajo. Para mí, el código que necesita modificar las variables globales (o peor, las variables externas no globales) es un olor a código. Por lo general, (no siempre) hay una mejor manera.Me parece muy inquietante la combinación de sintaxis orientada a objetos
this.method()
y procesal / funcional de Pythonmethod(this)
:Esto es particularmente malo porque una gran cantidad de funciones (en lugar de métodos) simplemente se vuelcan en el espacio de nombres global : métodos relacionados con listas, cadenas, números, constructores, metaprogramación, todo mezclado en una gran lista ordenada alfabéticamente.
Como mínimo, los lenguajes funcionales como F # tienen todas las funciones correctamente espaciadas en los módulos:
Entonces no están todos juntos. Además, este es un estándar seguido en toda la biblioteca, por lo que al menos es consistente.
Entiendo las razones para hacer la función vs método , pero todavía creo que es una mala idea mezclarlos de esta manera. Sería mucho más feliz si se siguiera la sintaxis del método, al menos para las operaciones comunes:
Si los métodos están mutando o no, tenerlos como métodos en el objeto tiene varias ventajas:
Module
al llamarModule.method(x)
. Tomando el ejemplo de la lista funcional anterior, ¿por qué tengo que seguir diciendoList
una y otra vez? ¡Debe saber que es unList
y no quiero llamar a laNavigation.map()
función en él! El uso de lax.map()
sintaxis lo mantiene SECO y sin ambigüedades.Y, por supuesto, tiene ventajas sobre la forma de hacerlo de poner todo en el espacio de nombres global . No es que la forma actual sea incapaz de hacer las cosas. Incluso es bastante conciso (
len(lst)
), ¡ya que nada tiene espacio de nombres! Entiendo las ventajas de usar funciones (comportamiento predeterminado, etc.) sobre los métodos, pero todavía no me gusta.Es solo desordenado. Y en grandes proyectos, el desorden es tu peor enemigo.
fuente
len()
es una función, y cuáles son las ventajas. También dije por qué creo que es una mala idea, por qué creo que las funciones globales son una idea particularmente mala, y por qué creo que los métodos proporcionan un método conveniente para organizar y determinar su funcionalidad =)def
,class
y otras llamadas sin función. Compare eso con más de 100 en la mayoría de los otros idiomas populares. Además, considere la línea deimport this
:Namespaces are one honking great idea -- let's do more of those!
. Creo que podría malinterpretar los espacios de nombres de Python;)Falta de homoiconicidad .
Python tuvo que esperar 3.x para agregar una palabra clave "con". En cualquier lenguaje homoicónico podría haberse agregado trivialmente en una biblioteca.
La mayoría de los otros problemas que he visto en las respuestas son de uno de 3 tipos:
1) Cosas que se pueden arreglar con herramientas (p. Ej., Pyflakes) 2) Detalles de implementación (GIL, rendimiento) 3) Cosas que se pueden arreglar con estándares de codificación (es decir, características que la gente desearía que no estuvieran allí)
# 2 no es un problema con el idioma, IMO # 1 y # 3 no son problemas serios.
fuente
with
estaba disponible desde Python 2.5 confrom __future__ import with_statement
, pero estoy de acuerdo, ocasionalmente encuentro desafortunado que declaraciones comoif
/for
/print
/ etc sean "especiales" en lugar de funciones regularesPython es mi lenguaje favorito, ya que es muy expresivo, pero aún así evita que cometas demasiados errores. Todavía tengo algunas cosas que me molestan:
No hay funciones anónimas reales. Lambda puede usarse para funciones de una sola declaración, y la
with
declaración puede usarse para muchas cosas en las que usaría un bloque de código en Ruby. Pero en algunas situaciones hace que las cosas sean un poco más torpes de lo que deberían ser. (Lejos de ser tan torpe como sería en Java, pero aún así ...)Alguna confusión en la relación entre módulos y archivos. Ejecutar "python foo.py" desde la línea de comandos es diferente de "import foo". Las importaciones relativas en Python 2.x también pueden causar problemas. Aún así, los módulos de Python son mucho mejores que las características correspondientes de C, C ++ y Ruby.
Explícito
self
. Aunque entiendo algunas de las razones, y aunque uso Python a diario, tiendo a cometer el error de olvidarlo. Otro problema con esto es que se vuelve un poco tedioso convertir una clase en un módulo. El yo explícito está relacionado con el alcance limitado del que otros se han quejado. El alcance más pequeño en Python es el alcance de la función. Si mantiene sus funciones pequeñas, como debería, eso no es un problema en sí mismo y la OMI a menudo proporciona un código más limpio.Algunas funciones globales, como
len
, que esperarías que fuera un método (que en realidad está detrás de escena).Sangrado significativo. No es la idea en sí, lo que creo que es genial, pero dado que esto es lo único que impide que tanta gente pruebe Python, quizás Python estaría mejor con algunos símbolos de inicio / fin (opcionales). Ignorando a esas personas, también podría vivir totalmente con un tamaño forzado para la sangría.
Que no es el lenguaje incorporado de los navegadores web, en lugar de JavaScript.
De estas quejas, es solo la primera que me importa lo suficiente y creo que debería agregarse al idioma. Los otros son bastante menores, excepto el último, ¡lo que sería genial si sucediera!
fuente
datetime.datetime.now()
cuando un proyecto podría escribirdatetime.now
y luego mezclar dos proyectos de una manera de escribirlo descarta el otro y seguramente esto no habría sucedido en Java, que no nombraría un módulo igual que un archivo (?) si ve cómo la forma común parece hacer que el módulo nos confunda con el archivo cuando ambos usos se practican y son explícitosself
, todavía trato de entenderlo ya que las llamadas no tienen el mismo número de argumentos que las funciones. ¿Y podría pensar que la máquina virtual Python tiene es lenta?Python no está completamente maduro: el lenguaje python 3.2 en este momento tiene problemas de compatibilidad con la mayoría de los paquetes actualmente distribuidos (generalmente son compatibles con python 2.5). Este es un gran inconveniente que actualmente requiere más esfuerzo de desarrollo (encuentre el paquete necesario; verifique la compatibilidad; evalúe elegir un paquete que no sea tan bueno que pueda ser más compatible; tome la mejor versión, actualícela a 3.2, lo que podría llevar días; luego comenzar a hacer algo útil).
Probablemente a mediados de 2012 esto será un inconveniente menor.
Tenga en cuenta que supongo que un fan-boy me votó negativamente. Sin embargo, durante una discusión de desarrolladores, nuestro equipo de desarrolladores de alto nivel llegó a la misma conclusión.
La madurez en un sentido principal significa que un equipo puede usar la tecnología y ponerse en marcha muy rápidamente sin riesgos ocultos (incluidos los problemas de compatibilidad). Los paquetes de Python de terceros y muchas aplicaciones no funcionan en 3.2 para la mayoría de los paquetes de hoy. Esto crea más trabajo de integración, prueba, reimplementación de la tecnología en sí misma en lugar de resolver el problema en cuestión == tecnología menos madura.
Actualización para junio de 2013: Python 3 todavía tiene problemas de madurez. De vez en cuando, un miembro del equipo mencionará un paquete necesario y luego dirá "excepto que es solo para 2.6" (en algunos de estos casos he implementado una solución alternativa a través del socket localhost para usar el paquete solo 2.6 con 2.6, y el resto de nuestras herramientas se quedan con 3.2). Ni siquiera MoinMoin, el wiki de Python puro, está escrito en Python 3.
fuente
El alcance de Python está muy roto, lo que hace que la programación orientada a objetos en Python sea muy incómoda.
fuente
self.
delante de cada referencia a una propiedad y método de instancia. Hace que sea imposible usar Python para crear un DSL como es tan fácil de hacer en Ruby.Mis quejas sobre Python:
fuente
Los modificadores de acceso en Python no son exigibles, lo que dificulta la escritura de código bien estructurado y modularizado.
Supongo que eso es parte del alcance roto de @ Mason, un gran problema en general con este lenguaje. Para el código que se supone que es legible, parece bastante difícil imaginar qué puede y debe estar dentro del alcance y qué valor tendrá en un momento dado: actualmente estoy pensando en pasar del lenguaje Python debido a estos inconvenientes. .
Solo porque "todos somos adultos con consentimiento" no significa que no cometamos errores y que no trabajemos mejor dentro de una estructura sólida, especialmente cuando trabajamos en proyectos complejos: la sangría y los subrayados sin sentido no parecen ser suficientes .
fuente
Pero tiene algunas excelentes características de rescate:
fuente
Estoy a favor de Python y la primera desventaja que me viene a la mente es que cuando comento una declaración como
if myTest():
esta, debe cambiar la sangría de todo el bloque ejecutado que no tendría que ver con C o Java. De hecho, en Python, en lugar de comentar una cláusula if, comencé a comentarlo de esta manera: `if True: #myTest (), por lo que no tendré que cambiar el siguiente bloque de código. Como Java y C no dependen de la sangría, hace que comentar las declaraciones sea más fácil con C y Java.fuente
if something()
aif False and something()
. Otro truco es "comentar" con una cadena de varias líneas.El despacho múltiple no se integra bien con el sistema de tipo de despacho único establecido y no es muy eficiente.
La carga dinámica es un problema enorme en sistemas de archivos paralelos donde la semántica similar a POSIX conduce a ralentizaciones catastróficas para operaciones intensivas en metadatos. Tengo colegas que han quemado un cuarto de millón de horas centrales con solo cargar Python (con numpy, mpi4py, petsc4py y otros módulos de extensión) en 65k núcleos. (La simulación arrojó nuevos resultados científicos significativos, por lo que valió la pena, pero es un problema cuando se quema más de un barril de petróleo para cargar Python una vez). La incapacidad de vincular estáticamente nos ha obligado a ir a grandes contorsiones para tiempos de carga razonables a escala, incluyendo parchear libc-rtld para
dlopen
realizar el acceso al sistema de archivos colectivo.fuente
dlopen
material está en nuestra biblioteca collfs . Ese repositorio también contiene trucos zipimport adicionales inspirados en el almacenamiento en caché de ruta de Asher Langton. Estamos trabajando en una mejor distribución y un papel.De todos modos, Python es mi idioma principal desde hace 4 años. Ser fanboys, elitistas o monomaníacos no es parte de la cultura python.
fuente
len(s)
a través__len__(self)
y otros "métodos especiales"__add__
y__iadd__
para+
y+=
)self
como primer parámetro del métodofuente
"Inmutabilidad" no es exactamente su punto fuerte. Los números AFAIK, las tuplas y las cadenas son inmutables, todo lo demás (es decir, los objetos) es mutable. Compare eso con lenguajes funcionales como Erlang o Haskell, donde todo es inmutable (al menos por defecto).
Sin embargo, la inmutabilidad realmente brilla con la concurrencia *, que tampoco es el punto fuerte de Python, por lo que al menos es consecuente.
(* = Para los nitpickers: me refiero a la concurrencia que es al menos parcialmente paralela. Creo que Python está bien con la concurrencia de "subproceso único", en la que la inmutabilidad no es tan importante. (Sí, amantes de FP, sé que la inmutabilidad es genial incluso sin concurrencia.))
fuente
Me encantaría tener construcciones explícitamente paralelas. Más a menudo que no, cuando escribo una lista de comprensión como
No me importa el orden en que se procesarán los elementos. A veces, ni siquiera me importa en qué orden se devuelven.
Incluso si CPython no puede hacerlo bien cuando mi f es Python puro, un comportamiento como este podría definirse para que otras implementaciones lo usen.
fuente
Python no tiene optimización de llamadas de cola, principalmente por razones filosóficas . Esto significa que el recursivo de cola en estructuras grandes puede costar memoria O (n) (debido a la pila innecesaria que se mantiene) y requerirá que reescriba la recursión como un bucle para obtener memoria O (1).
fuente