Compilación de @Pythonetc, julio de 2018

Esta es la segunda colección de consejos y programación de Python de mi feed @pythonetc . Selecciones anteriores:


Idiomas regulares


Un lenguaje regular es un lenguaje formal que se puede representar como una máquina de estados finitos . En otras palabras, para el procesamiento de texto de carácter por carácter solo necesita recordar el estado actual, y el número de dichos estados es finito.

Un ejemplo perfecto: una máquina que verifica si la entrada es un primo como –3, 2.2 o 001. Al comienzo del artículo, se muestra una máquina de estados finitos. Los círculos dobles indican el estado final, en el que la máquina puede detenerse.

La máquina comienza desde la posición . Quizás encuentre un signo menos, luego un dígito, y luego en la posición ③ procesa el número requerido de dígitos. Después de eso, se puede verificar el separador decimal (③ → ④), seguido de un dígito (④ → ⑤) o más (⑤ → ⑤).

Un ejemplo clásico de un lenguaje irregular es una familia de expresiones de cadena de la forma:

ab
aaa-bbb
aaaaa-bbbbb


Formalmente, necesitamos una cadena que contenga N instancias de a , luego , luego - N instancias de b , donde N es un número entero mayor que 0. No puede implementar esto con una máquina de estados, ya que tendrá que recordar la cantidad de caracteres que pensó que podría hecho solo usando un número infinito de estados.

Las expresiones regulares solo pueden especificar idiomas regulares. Antes de usarlos, asegúrese de que su cadena incluso se pueda procesar usando una máquina de estados. Por ejemplo, no son adecuados para procesar JSON, XML o incluso expresiones aritméticas con paréntesis.

Es curioso que muchos motores regex modernos no sean regulares. Por ejemplo, el módulo regex para Python admite la recursividad (que ayudará a resolver el problema con aaa-bbb ).

Programación dinámica


Cuando Python realiza una llamada al método, digamos af(b, c, d) , primero debe seleccionar la función correcta f . En virtud del polimorfismo, a determina lo que finalmente se elegirá. El proceso de selección de un método se denomina comúnmente despacho dinámico.

Python solo admite polimorfismo de despacho único. Esto significa que solo el objeto en sí mismo afecta la elección del objeto (en nuestro ejemplo, a ). En otros lenguajes, se pueden tener en cuenta los tipos b , c y d ; este mecanismo se denomina despacho múltiple. Un ejemplo sorprendente es el lenguaje C #.

Sin embargo, la programación múltiple se puede emular usando una sola. Es por eso que se creó la plantilla de diseño de visitante: utiliza dos veces un solo envío para simular un doble.

Recuerde que los métodos de sobrecarga (como en Java y C ++) no son análogos a la distribución múltiple. El despacho dinámico funciona en tiempo de ejecución, y la sobrecarga se realiza solo durante la compilación.

Estos ejemplos lo ayudarán a comprender mejor el tema:


Nombres en línea


En Python, puede modificar fácilmente todas las variables estándar que están disponibles en el ámbito global:

 >>> print = 42 >>> print(42) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable 

Esto es útil si su módulo define funciones cuyos nombres coinciden con los nombres de las funciones integradas. Esto también sucede en situaciones en las que practica la metaprogramación y toma un valor de cadena arbitrario como identificador.

Pero incluso si duplica los nombres de algunas funciones integradas, es posible que necesite acceder a lo que originalmente se refería. Es por eso que existe el módulo integrado:

 >>> import builtins >>> print = 42 >>> builtins.print(1) 1 

También en la mayoría de los módulos, la variable __builtins__ está disponible. Pero hay un truco. En primer lugar, esta es una característica de la implementación de cpython y, por lo general, no debe usarse en absoluto. En segundo lugar, __builtins__ puede referirse tanto a builtins como a builtins.__dict__ , dependiendo de cómo se cargó el módulo actual.

strace


A veces la aplicación comienza a comportarse de manera extraña en la batalla. En lugar de reiniciarlo, es posible que desee comprender la causa de los problemas mientras sea posible.

La solución obvia es analizar las acciones del programa e intentar comprender qué parte del código se está ejecutando. El registro adecuado hace que esta tarea sea más fácil, pero sus registros pueden no estar lo suficientemente detallados debido a la arquitectura o al nivel de registro seleccionado en la configuración.

En tales casos, strace puede ser útil. Esta es una utilidad de Unix que rastrea las llamadas del sistema. Puede ejecutarlo previamente - strace python script.py - pero generalmente es más conveniente conectarse a una aplicación que ya se está ejecutando: strace -p PID .

 $ cat test.py with open('/tmp/test', 'w') as f: f.write('test') $ strace python test.py 2>&1 | grep open | tail -n 1 open("/tmp/test", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3 

Cada línea de la traza contiene el nombre de la llamada al sistema, los argumentos entre paréntesis y el valor de retorno. Dado que algunos argumentos se utilizan para devolver el resultado de una llamada al sistema y no para pasarle datos, la salida de línea se puede pausar hasta que finalice la llamada del sistema.

En este ejemplo, la salida se detiene hasta que se completa la escritura en STDIN:

 $ strace python -c 'input()' read(0, 

Tuples literales


Una de las partes más inconsistentes de la sintaxis de Python son los tuples literales.

Para crear una tupla, es suficiente enumerar los valores separados por comas: 1, 2, 3 . ¿Qué pasa con una tupla de un solo elemento? Simplemente agregue una coma colgante: 1, ,. Parece feo y a menudo conduce a errores, pero es bastante lógico.

¿Qué tal una tupla vacía? Esta es una coma ... No, esto es () . ¿Y qué, los corchetes crean una tupla, como comas? No, (4) no es una tupla, es solo 4 .

 In : a = [ ...: (1, 2, 3), ...: (1, 2), ...: (1), ...: (), ...: ] In : [type(x) for x in a] Out: [tuple, tuple, int, tuple] 

Para confundir las cosas aún más, los literales de tupla a menudo requieren paréntesis adicionales. Si necesita que la tupla sea el único argumento para la función, entonces obviamente f(1, 2, 3) no funcionará; tendrá que escribir f((1, 2, 3)) .

Source: https://habr.com/ru/post/es419025/


All Articles