x o y: ¿idioma aceptable, o ofuscación?

Tengo que extraer valores de una variable que puede ser Ninguna, con algunos valores predeterminados en mente. Primero escribí este código:

if self.maxTiles is None: maxX, maxY = 2, 2 else: maxX, maxY = self.maxTiles 

Entonces me di cuenta de que podía acortarlo a:

 maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2) 

Pero luego me di cuenta de que esto podría ser el más breve y fácil de leer:

 maxX, maxY = self.maxTiles or (2, 2) 

¿Es este último aceptable, o demasiado hacker?

    Acerca de, específicamente,

     self.maxTiles if self.maxTiles is not None else (2, 2) 

    He encontrado que los “dobles negativos” de la forma general, if not A: B else: C (ya sea como declaraciones o expresiones) pueden ser bastante confusos / engañosos; esto no es literalmente un if not .. else , pero mover el not hace que el “doble negativo” desaparezca.

    Entonces, en general, solo reescribo tales construcciones a if A: C else: B En este caso particular, si seleccionara el formulario de operador ternario, lo codificaría como

     (2, 2) if self.maxTiles is None else self.maxTiles 

    En la pregunta más general: a = b or c está bien si y solo si realmente quieres usar c para cualquier valor falso de b , no está bien tratar específicamente si b es None . IOW, b or c es una mejor manera de express

     b if b else c 

    pero no es una forma de express una expresión similar donde la prueba central es, en cambio, b is None . En teoría, si “sabe” que el único valor falso posible para b es None , son semánticamente equivalentes, pero esa fuerte restricción de “solo falso valor posible” no será evidente para los lectores / mantenedores de su código, y si tiene que agregar un comentario para explicar que, cualquier ventaja de concisión que se pueda afirmar se anula … mejor, cuando sea posible, “decirlo en el código”, en lugar de que el código sea oscuro y necesite comentarios para aclarar exactamente lo que es. hacer y cuándo (los comentarios que son realmente útiles son más bien los que explican, no el qué y el cuándo [[el código mismo debería mostrar eso! -)]], sino el por qué cuando no es obvio, ¿cuál es el propósito de la aplicación? atendido por este dato específico de funcionalidad de código).

    Junto con la respuesta de gddc (de los problemas de asumir que maxTiles es una tupla), probablemente haría la segunda opción, pero agregaría paréntesis para mayor claridad:

     maxX, maxY = (self.maxTiles) if (self.maxTiles is not None) else (2, 2) 

    Si estás haciendo esto al principio de una función , usaría la forma más larga, ya que es más idiomática y reconocible al instante. Sí, son más líneas, pero apenas se guardan los caracteres, y las líneas cortas que se ajustan a 79 líneas de caracteres = buena.

    Además, si alguna vez tiene que ajustar la lógica o agregar más pasos, probablemente volvería a la forma larga de todos modos.

    Evito la syntax y if x else z cuando puedo. Es inherentemente una syntax fea e intuitiva, y uno de los errores más grandes en el diseño de Python. Es una expresión fuera de orden: x se evalúa antes de y. No es intuitivo; naturalmente se lee como “si x entonces y, si no z”. La syntax de C nos da un orden establecido por décadas, comprendido universalmente para esto: x? y:z x? y:z . Python se equivocó mucho.

    Dicho esto, la syntax ternaria es el mecanismo incorrecto para proporcionar un valor predeterminado de todos modos. En self.maxTiles if self.maxTiles is not None else (2, 2) , tenga en cuenta la redundancia: debe especificar self.maxTiles dos veces. Eso es repetitivo, por lo que se necesita más trabajo para leer el código. Tengo que leerlo dos veces para asegurarme de que no diga, por ejemplo, self.minTiles if self.maxTiles is not None else (2, 2) .

    self.maxTiles or (0,2) evita estos problemas; Es perfectamente claro de un vistazo.

    Una advertencia: si self.maxTiles es () o 0 o algún otro valor falso, el resultado es diferente. Probablemente esto sea aceptable según lo que parezca que estás haciendo, pero ten esto en cuenta. Es un problema cuando se proporciona un valor predeterminado para un booleano o un entero, y realmente necesita la prueba is None . Para aquellos que prefiero un condicional simple, pero a veces recurriré a una expresión ternaria.

    Editar; Una forma más clara de escribir la versión condicional es:

     if self.maxTiles is None: maxX, maxY = 2, 2 else: maxX, maxY = self.maxTiles 

    Tu código es un lenguaje perfectamente aceptable. De hecho, me parece más legible que los dos primeros.

    Mi única consideración es que estás haciendo dos cosas en una línea, para proporcionar un valor predeterminado y descomprimirlas en x, y. Tal vez sea más claro si los separas en dos.

     maxTiles = self.maxTiles or (2, 2) maxX, maxY = maxTiles 

    Esto también desvía la crítica de gddc, aunque no es realmente una seria.

    No me gusta usar y and como reemplazo de un operador ternario en Python. Me he encontrado con problemas como que un valor de 0 se trata como “falso” demasiadas veces, cuando solo tenía la intención de comprobar None . Considero que es mucho mejor ser explícito, incluso si es más detallado, así que tu segundo ejemplo es el mejor:

     maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2)