python - online - ¿Qué pautas de PEP 8 ignora, y a cuáles se apega?
python enhancement proposal no 8 pep8 (14)
Con el paso de los años, mientras más escribo en Python, más me convengo en la mayoría de las pautas, aunque de manera consistente e intencionalmente rompo algunas por mis propios motivos.
Sería curioso saber qué en PEP 8 (u otras PEP también tal vez) las personas se adhieren religiosamente y por qué, y qué personas encuentran inconveniente o inadecuado.
En mi caso (y en el trabajo en general), solo nos desviamos de un puñado de cosas:
Ponga el subrayado en minúsculas separadas, puedo ver el punto, ya que será indefectiblemente consistente, pero tendemos a usar lowerCamelCase, incluso si ocasionalmente introduce algunas inconsistencias (como acrónimos parcialmente o mal capitalizados y las siguientes palabras, que son a menudo hasta llamadas de improviso). Sobre todo porque la casi totalidad de las API que utilizamos habitualmente usan camelCase (algunas superiores, otras más bajas), y porque por alguna razón me resulta más fácil de leer, y tienden a reservar guiones bajos como tokens de separación o manipulación / oscurecimiento prescritos.
Todavía no puedo llegar a espaciar las cosas de la manera en que el PEP prescribe objetos internos. new e init Tiendo a irme directamente debajo de la clase sin líneas en blanco, ya que siempre quiero leerlas allí mismo con el nombre de clase y args, métodos que contribuyen al mismo alcance de funcionalidad en la clase (digamos init, get y set del mismo attrib o conjunto de attribs) Solo estoy separado de un espacio, y me gustan tres espacios entre clases, y dos entre métodos que no agregaría mentalmente en el mapa de ese objeto. Esto es, nuevamente, puramente por el impacto visual y la legibilidad del código. Encuentro que los contenidos muy compactos dentro del control de flujo y este tipo de espaciado entre métodos y objetos conducen constantemente mi ojo exactamente a donde quiero que vaya re-lecturas meses después de que el código haya sido estacionado. También responde bien al plegado en mis editores de elección.
Algunas cosas en las que me adhiero, que me vuelven loco cuando leo lo contrario, son pestañas en lugar de espacios (especialmente cuando algunos editores en la aplicación que usamos realmente no tienen funcionalidades de reemplazo de pestañas, lo que contribuye considerablemente a la contaminación en la base de códigos en etapa de prototipado).
Orden de cosas tales como importaciones y qué importaciones, globales, etc. Realmente me deja en los archivos que tienen grandes cantidades de importaciones cuando están mezcladas o fuera de servicio.
Espacios en blanco en las declaraciones, especialmente cuando la gente usa pestañas Y trata de alinear operaciones de asignación entre líneas con diferente longitud en var names (y parece que no hay forma de convencer a quienes lo hacen de que una pieza de código que sobresale NO es más ordenada;)) .
Y espaciado dentro de un bloque de control, particularmente cuando veo un espacio aparentemente aleatorio dentro del mismo bloque de control de flujo, y luego cantidades similares de espaciado usadas dentro del objeto para los métodos. Me veo obligado a editarlos antes de que pueda comenzar a leer la maldita cosa.
Entonces, esos son los míos, y el razonamiento detrás de mis "violaciones" del PEP (algunos compartidos, algunos desaprobados por colegas). Tendría mucha curiosidad por leer lo que otros Pythonistas hacen y no hacen al respecto.
Condicional de varias líneas, etc .: PEP-8 explícitamente dice que se rompa después de un operador binario en lugar de antes. Me temo que no puedo ver el atractivo de eso. Para mí tiene mucho más sentido romper antes del condicional, de modo que en las líneas continuas / envueltas, cada sublínea comienza con el condicional:
if (condition1 /
or condition2 /
or condition3):
do_something()
Como se puede ver, también me gusta agregar una sangría adicional para las sublíneas, de modo que se compensen visualmente desde el siguiente bloque. PEP-8 no dice nada explícito sobre esto (¿verdad?), Pero los ejemplos tienen las sublíneas alineadas con los paréntesis de apertura.
Cuando estoy escribiendo pequeños guiones, a menudo solo uso dos espacios.
Siempre uso el mismo patrón para docstrings:
def function():
"""
Even if it''s a single line.
"""
El "problema" con PEP 8 es que avanza en áreas de preferencia personal que están sujetas a grandes cantidades de emoción para la mayoría de los programadores.
Personalmente, camelCase vs underscores y directivas de alineación de columnas fueron problemas constantes. También veo punto en muchas otras respuestas aquí y algunas veces rompo PEP 8 intencionalmente porque en ese caso particular simplemente "tiene sentido".
Hubo un punto en mi carrera de programación de Python cuando simplemente me rendí y recurrí (usando) PEP 8. Fue relativamente fácil para la mayoría de los artículos, por lo que hoy en día el único problema importante que aún tengo es la alineación de columnas. Ese es demasiado complicado para obedecer (aunque odiosamente lo hago de todos modos). De todos modos, como resultado de mi "renuncia", mi código ahora es mucho más legible para mis colegas y, sorprendentemente, incluso para mí (excepto por el asunto de la alineación de columnas: p).
También debo reconocer lo que PEP 8 ha hecho para Python: entre 2.x (no conforme) y 3.x (compatible), me resulta mucho más fácil "saber siempre" cuál será el nombre de una función en particular. Las "baterías" de Python ahora están mejor clasificadas.
La parte "79 caracteres por línea" no tiene sentido. Su propio ejemplo muestra cómo se convierte el código ilegible cuando se hace esto:
class Rectangle(Blob):
def __init__(self, width, height,
color=''black'', emphasis=None, highlight=0):
if width == 0 and height == 0 and /
color == ''red'' and emphasis == ''strong'' or /
highlight > 100:
raise ValueError("sorry, you lose")
if width == 0 and height == 0 and (color == ''red'' or
emphasis is None):
raise ValueError("I don''t think so -- values are %s, %s" %
(width, height))
Blob.__init__(self, width, height,
color, emphasis, highlight)
Es como intentar-
ing leer
una noticia
cle escrito
Me gusta esto.
Los terminales de 80 columnas no han sido un entorno de desarrollo serio durante más de una década. Cuando necesito editar desde un entorno paralizado de 80x25 en un apuro, el ajuste del editor es un inconveniente menor; No voy a dañar mi código durante el desarrollo normal solo para evitar eso.
El ajuste de 120 columnas es perfectamente razonable para el desarrollo moderno, y no tengo ningún problema con 140. Esta guía es obsoleta y seguirla da como resultado un código feo y difícil de leer.
Las pautas de estilo de mi compañía requieren específicamente pestañas, no espacios. PEP 8 insinúa que los espacios son preferibles, pero hemos encontrado lo contrario. Me gusta ver el código sangrado con 4 ''espacios'' en VIM, un compañero de trabajo prefiere 8 ''espacios'' en Emacs. El uso de pestañas nos permite configurar nuestros editores para mostrar el código como lo prefiramos.
Tenga en cuenta que en otros lenguajes basados en C, la sangría es de hecho simplemente formatear, pero en Python la indentación es sintaxis , por lo que creemos que el indentation level 2
debe estar representado por 2
de algo (es decir, pestañas) no 4
u 8
de algo (espacios) .
La selección del carácter de sangría es probablemente la guerra de las llamas sagradas original (incluso antes de los flamewars de VIM / Emacs), así que espero ser modificado al olvido para expresar una opinión sobre el tema.
Los estándares son críticos y PEP 8 es una muy buena guía de estilo en la que insisto. La única guía con la que no estoy de acuerdo es el espacio entre operadores matemáticos. Por ejemplo, PEP8 insiste en los siguientes espaciamientos
Without PEP8 With PEP8
----------------------------------------------------------------
y = sqrt(x**2 + y**2) y = sqrt(x ** 2 + y ** 2)
a*x**3 + b*x**2 + c*x + d a * x ** 3 + b * x ** 2 + c * x + d
10**(a*x + b) 10 ** (a * x + b)
F = V/(sqrt(g*h) + epsilon) F = V / (sqrt(g * h) + epsilon)
a*cos(nx/pi) + b*sin(nx/pi) a * cos(nx / pi) + b * sin(nx / pi)
Estoy tratando de conformarme, pero esta es la única área en la que estoy luchando. ¿Alguien más también siente que el espaciado de PEP8 hace que las matemáticas sean más difíciles de leer?
Actualizar:
Se corrected PEP8 para recomendar el formateo a la izquierda y desalentar el formato a la derecha:
Sí:
i = i + 1 submitted += 1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b)
No:
i=i+1 submitted +=1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b)
Mi "violación de admitir" se trata de "si"
PEP8 dice que no hay varias instrucciones en una línea, por lo que si debemos hacer esto:
if cond:
actions
...
Pero cuando hay una sola acción, prefiero todo en una línea, por ejemplo, prefiero:
if a == 0: b = 0
que:
if a == 0:
b = 0
No estoy de acuerdo con esto:
- Imports should usually be on separate lines, e.g.:
Yes: import os
import sys
No: import sys, os
Siempre escribo simples importaciones juntas. No veo ninguna ventaja al escribirlos en líneas separadas: todo lo que hace es agregar relleno en la parte superior de cada archivo de origen, y convertir algo conciso y fácil de escribir en algo que es un texto marginal , por ejemplo. algo tan detallado que comienza a ser tentador copiar y pegar desde otros archivos.
Esto es instantáneamente legible y comprensible:
import sys, os, time, gc, inspect, math, doctest
Es corto, fácil de descremada y fácil de agregar. Utilizo múltiples instrucciones de import
si hay demasiadas en una línea, por supuesto, o si necesito una from
importación.
También mantengo generalmente las importaciones de bibliotecas estándar separadas de las importaciones de mis propios módulos y otras bibliotecas, lo que concuerda con el concepto de agrupación que recomienda PEP8.
PEP 8 dice:
Sí:
x = 1
y = 2
long_variable = 3
No:
x = 1
y = 2
long_variable = 3
generalmente lo sigo, pero a veces uso otra variante, por el bien de una mejor legibilidad:
x = 1
y = 2
long_variable = 3
PEP8 dice que evite "más de un espacio alrededor de un operador de asignación (u otro) para alinearlo con otro" y "nunca use más de un espacio" alrededor de operadores matemáticos, pero no sigo esto.
A menudo agrego "espacio en blanco extraño" cuando las líneas vecinas están relacionadas o son muy similares, pero no del todo:
search_start = (f - f_1/3) * n/fs
search_stop = (f + f_1/3) * n/fs
b_lpf, a_lpf = filter(N, 2*pi*fc, ''low'', analog=True)
b_hpf, a_hpf = filter(N, 2*pi*fc, ''high'', analog=True)
p[x > 1] = np.cosh(order * np.arccosh( x[x > 1]))
p[x < -1] = (1 - 2 * (order % 2)) * np.cosh(order * np.arccosh(-x[x < -1]))
b0 = (1 + cos(w0))/2
b1 = -(1 + cos(w0))
Del mismo modo, es molesto que obtenga advertencias de estilo de código para matrices de números formateados de forma legible, ya que normalmente están formateados por la biblioteca :
a = array([[-0.198, 0.248, -1.17 , -0.629, 1.378],
[-1.315, 0.947, -0.736, -1.388, 0.389],
[ 0.241, -0.98 , 0.535, 0.951, 1.143],
[-0.601, 1.286, -0.947, 0.037, -0.864],
[ 0.178, -0.289, -1.037, -1.453, -0.369]])
PEP8 preferiría tenerlo formateado así, aparentemente, porque no podemos tener espacio en blanco adicional antes de las comas o después de los corchetes:
a = array([[-0.198, 0.248, -1.17, -0.629, 1.378],
[-1.315, 0.947, -0.736, -1.388, 0.389],
[0.241, -0.98, 0.535, 0.951, 1.143],
[-0.601, 1.286, -0.947, 0.037, -0.864],
[0.178, -0.289, -1.037, -1.453, -0.369]])
Siempre uso 4 espacios, trato de usar un máximo de 79 caracteres por línea, algo que no es posible en algún momento. También utilicé importaciones como "import sys, os" en el pasado. En general, trato de seguir con PEP 8.
Editar: también use:
def foobar():
"""
foobar
"""
para documentación
Utilizo pylint, http://pypi.python.org/pypi/pylint , es una excelente herramienta para tratar de mantener su código limpio y legible para usted y otros desarrolladores que acceden a su código.
Sin embargo, no cubro todos los temas que dijiste, pero es muy útil.
Puede tener informes como este:
carlos@debian:~/src/fcl/cltools$ pylint numbertoletters.py
No config file found, using default configuration
************* Module numbertoletters
C: 1: Missing docstring
C: 56:es_numero: Missing docstring
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 69:convertnumbertoletters: Empty docstring
C: 90:convertnumbertoletters: Operator not preceded by a space
numero=''%(numero)09d'' % {''numero'' : int(parte_entera)}
^
C: 92:convertnumbertoletters: Comma not followed by a space
for i in [0,3,6]:
^^
W: 69:convertnumbertoletters: Unused argument ''languaje''
C:108:unidades: Empty docstring
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:112:unidades: Invalid name "u" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Empty docstring
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:122:teens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Empty docstring
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:131:tens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:137:tercia: Empty docstring
C:141:tercia: Operator not preceded by a space
numero=''%(numero)03d'' % {''numero'' : int(num)}
^
C:143:tercia: Invalid name "a" (should match [a-z_][a-z0-9_]{2,30}$)
C:144:tercia: Invalid name "b" (should match [a-z_][a-z0-9_]{2,30}$)
C:145:tercia: Invalid name "c" (should match [a-z_][a-z0-9_]{2,30}$)
C:163:tercia: Operator not followed by a space
resultado =''veinti ''+unidades(c)
^
C:165:tercia: Operator not followed by a space
elif b >=3 and b <= 9:
^^
C:178:tercia: Operator not followed by a space
resultado =''ciento ''+unidades(c)
^
C:192:tercia: Operator not followed by a space
resultado =''ciento veinti ''+unidades(c)
^
C:204:tercia: Operator not preceded by a space
prefix=''quinientos ''
^
C:206:tercia: Operator not preceded by a space
prefix=''setecientos ''
^
C:208:tercia: Operator not preceded by a space
prefix=''novecientos ''
^
C:210:tercia: Operator not preceded by a space
prefix=unidades(a)+''cientos ''
^
R:137:tercia: Too many return statements (23/6)
R:137:tercia: Too many branches (41/12)
R:137:tercia: Too many statements (73/50)
Report
======
141 statements analysed.
Raw metrics
-----------
+----------+-------+------+---------+-----------+
|type |number |% |previous |difference |
+==========+=======+======+=========+===========+
|code |144 |68.25 |NC |NC |
+----------+-------+------+---------+-----------+
|docstring |5 |2.37 |NC |NC |
+----------+-------+------+---------+-----------+
|comment |57 |27.01 |NC |NC |
+----------+-------+------+---------+-----------+
|empty |5 |2.37 |NC |NC |
+----------+-------+------+---------+-----------+
Statistics by type
------------------
+---------+-------+-----------+-----------+------------+---------+
|type |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module |1 |NC |NC |0.00 |0.00 |
+---------+-------+-----------+-----------+------------+---------+
|class |0 |NC |NC |0 |0 |
+---------+-------+-----------+-----------+------------+---------+
|method |0 |NC |NC |0 |0 |
+---------+-------+-----------+-----------+------------+---------+
|function |6 |NC |NC |0.00 |0.00 |
+---------+-------+-----------+-----------+------------+---------+
Duplication
-----------
+-------------------------+------+---------+-----------+
| |now |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines |0 |NC |NC |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |NC |NC |
+-------------------------+------+---------+-----------+
Messages by category
--------------------
+-----------+-------+---------+-----------+
|type |number |previous |difference |
+===========+=======+=========+===========+
|convention |32 |NC |NC |
+-----------+-------+---------+-----------+
|refactor |3 |NC |NC |
+-----------+-------+---------+-----------+
|warning |1 |NC |NC |
+-----------+-------+---------+-----------+
|error |0 |NC |NC |
+-----------+-------+---------+-----------+
Messages
--------
+-----------+------------+
|message id |occurrences |
+===========+============+
|C0103 |14 |
+-----------+------------+
|C0322 |6 |
+-----------+------------+
|C0112 |5 |
+-----------+------------+
|C0323 |4 |
+-----------+------------+
|C0111 |2 |
+-----------+------------+
|W0613 |1 |
+-----------+------------+
|R0915 |1 |
+-----------+------------+
|R0912 |1 |
+-----------+------------+
|R0911 |1 |
+-----------+------------+
|C0324 |1 |
+-----------+------------+
Global evaluation
-----------------
Your code has been rated at 7.45/10
I hope it helps.
Recomiendo el uso de pylint para calificar tu código y mantener una forma estándar de programación, especialmente en una comunidad de desarrolladores. =)
Espero que ayude.
python-mode.el, https://launchpad.net/python-mode
Mientras tanto, permite la personalización del estilo:
Mx customize-variable RET py-docstring-style RET
El valor predeterminado es pep-257-nn
Los estilos implementados son DJANGO, ONETWO, PEP-257, PEP-257-NN, SYMMETRIC y NIL.
A un valor de NIL no le importará la posición de las cotizaciones y tratará las cadenas de texto como una cadena normal, cualquier otro valor puede dar como resultado uno de los siguientes estilos de docstring:
DJANGO:
"""
Process foo, return bar.
"""
"""
Process foo, return bar.
If processing fails throw ProcessingError.
"""
UNO DOS:
"""Process foo, return bar."""
"""
Process foo, return bar.
If processing fails throw ProcessingError.
"""
PEP-257:
"""Process foo, return bar."""
"""Process foo, return bar.
If processing fails throw ProcessingError.
"""
PEP-257-NN:
"""Process foo, return bar."""
"""Process foo, return bar.
If processing fails throw ProcessingError.
"""
SIMÉTRICO:
"""Process foo, return bar."""
"""
Process foo, return bar.
If processing fails throw ProcessingError.
"""
PEP8 dice
Tenga en cuenta que lo más importante es que el "" "que finaliza una cadena de documentos multilínea debe estar en una línea por sí mismo, y preferiblemente precedido por una línea en blanco , por ejemplo:
"""Return a foobang Optional plotz says to frobnicate the bizbaz first. """
Encuentro esto bastante extraño, ya que es solo un "espacio en blanco extraño" y trata las citas de apertura de manera diferente a las citas de cierre sin ninguna razón obvia.
Se da una justificación en PEP 257 :
El BDFL recomienda insertar una línea en blanco entre el último párrafo en un docstring de varias líneas y sus citas de cierre, colocando las cotizaciones de cierre en una línea por sí mismas. De esta forma, se puede usar el comando de relleno de párrafo de Emacs.
Emacs, ¿de verdad? Todos deberían hacer cosas raras para adaptarse a la idiosincrasia de un comando en particular en una herramienta de edición particular.
También creo que es extraño poner el comienzo de la docstring en la misma línea que las comillas (no es obligatorio, pero se recomienda), al tiempo que se insiste en que las citas de cierre estén en su propia línea. Creo que esto es más lógico y debería usarse tanto para docstrings de una sola línea como multilínea:
def foobang(bizbaz, plotz=None):
"""
Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
if plotz is not None:
...
Actualización: la parte en negrita se ha eliminado y ahora solo dice "colocar las comillas de cierre en una línea por sí mismas", y que la "línea de resumen puede estar en la misma línea que las comillas de apertura o en la siguiente línea".