Guia de Estilo de Código

Este guia foi baseado nos PEPs (Python Enhacement Proposals):  PEP 8 (para o texto principal) e  PEP 257 para convenções de docstring.

O código fonte do software InVesalius deve ser escrito em inglês, com identificadores e comentários neste idioma.

1. Layout

Identação

Devem ser utilizados 4 espaços para cada nível de identação. Não devem ser utilizadas tabulações.

Comprimento máximo de linha

Todas as linhas devem ter no máximo 79 caracteres.

Para longos blocos de texto (docstrings ou comentários), sugere-se limitar a 72 caracteres por linha.

Linhas em branco

Funções de alto-nível e definições de classe devem ser separadas por duas linhas em branco.

Definições de método dentro de cada classe são separadas por uma linha em branco.

Linhas em branco extras podem ser utilizadas (eventualmente) para separar grupos de funções relacionadas. Utilizar linhas em branco em funções, eventualmente, para separar seções lógicas.

Codificação

O código fonte deve ser em ASCII.

Para eventuais caracteres especiais, deve ser utilizado UTF-8. Caracteres latinos tem preferência a representações como \x, \u ou \U quando nomes de autores forem apresentados em comentários ou docstrings.

2. Importação

Módulos devem ser importados em linhas separadas, por exemplo:

# Sim:
import os
import sys

# Não:
import sys, os

# Pode-se fazer isso, entretanto:
from subprocess import Popen, PIPE

Imports sempre devem ser colocados no topo do arquivo, depois de docstrings e comentários do móduo, e antes de constantes e variáveis globais de módulo.

Eles devem ser agrupados seguindo a seguinte ordem:

  1. Importação de bibliotecas padrão
  2. Importação de bibliotecas de terceiros
  3. Importação de aplicativos e bibliotecas locais específicos

Deve ser colocada uma linha em branco entre cada grupo de importações.

Após as importações devem ser inseridas quaisquer especificações all.

São desencorajadas importações relativas para situações inter-pacotes. Devem ser utilizados caminhos absolutos visando a portabilidade e legibilidade.

Para importar classes de módulos que contém classes, deve-se utilizar:

from module import MyClass
from module.bar.yourclass import YourClass

3. Espaços em branco em expressões e declarações

Evite espaços em brancos desnecessários nas seguintes situações:

  • Imediatamente entre parênteses, colchetes e chaves
# Sim:
spam(ham[1], {eggs: 2}

# Não:
spam( ham[ 1 ], { eggs: 2 })
  • Imediatamente antes de vírgulas, dois pontos e ponto & virgula
# Sim:
if x == 4: print x, y;  x, y = y, x

# Não:
if x == 4 : print x , y ;  x , y = y , x
  • Imediatamente antes de parênteses de abertura da lista de argumentos em uma chamada de função
# Sim:
spam(1)

# Não:
spam (1)
  • Imediatamente antes de abertura parênteses
# Sim:
dict['key'] = list[index]

# Não:
dict ['key'] = list [index]
  • Mais de um espaço ao redor de um operador de atribuição (ou outro) para alinhar com outro
# Sim:
x = 1
y = 2
long_variable = 3

# Não:
x             = 1
y             = 2
long_variable = 3

  • Outras indicações

Sempre cerque operadores binários com um espaço simples dos dois lados: atribuição (=), atribuição aumentada (+=, -=. etc), comparações (==, <, >, !=, <>, <=, >=, in, not in, is, is not), booleanos <and, or, not>.

Use espaços entre operadores aritméticos:

{{ # Sim: i = i + 2 submitted += 1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b)

# Não: i=i+1 sib,otted +=1 x = x*2 -1 hypot2 = x*x + y*y c = (a+b) * (a-b)

}}}

Não use espaços entre o operador '=' quando utilizá-lo para identificar o valor padrão de um parâmetro:

# Sim:
def complex(real, imag = 0.0):
    return magic(r=real, i=imag)

# Não:
def complex(real, imag = 0.0)
    return magic(r = real, i = imag)

Declarações compostas (múltiplas declarações em uma mesma linha) são desencorajadas:

# Sim:
if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three

# Não:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()

Não escreva linhas longas com múltiplas declarações:

# Não:
if foo == 'blah': do_blah_thing()
for x in lst: total += x
while t < 1-: t = delay()

# Jamais:
if foo == 'blah': do_blah_thing()
else: do_non_blah_thing()

try: something()
finally: cleanup()

do_one(); do_two(); do_three(long, argument, list, like, this)
if foo == 'blah': one(); two(); three()

4. Comentários

Comentários que contradizem o código são piores do que nenhum comentário. Sempre dê prioridade para manter os comentários atualizados quando o código for alterado!

Comentários devem ser sentenças completas. Se um comentário é uma frase ou sentença, ele deve ser iniciado com letra maiúscula, a menos que seja iniciado com um identificador que seja iniciado por letra minúscula.

Se o comentário for curto, o ponto no fim pode ser omitido. Comentários de bloco geralmente consistem em um ou mais parágrafos construídos a partir de sentenças completas, sendo que cada sentença deve ser finalizada com um ponto.

Todos os comentários devem ser escritos em inglês.

  • Comentários de bloco

Comentários de bloco devem ser referentes a alguns ou todos os códigos que os seguem, sendo identados de acordo com o mesmo nível de tal código. Cada linha do bloco deve começar com # seguido por um espaço simples (a não ser que o texto dentro dele serja identado).

Os parágrafos dentro de um comentário são separados por uma linha contendo apenas um #.

  • Comentários em linha

Comentários em linha deve ser evitados.

# Evite:
x = x +  1   # Compensate for border

5. Documentação

Para documentação do código fonte devem ser utilizadas "docstrings".

  • Deve-se escrever docstrings para todos os módulos públicos, funções, classes e métodos. Não é necessário escrever docstrings para métodos não-públicos, mas deve-se comentar o que o método faz. Este comentário deve ser escrito na linha abaixo ao def.
  • Para dosctrings de uma linha apenas, sugere-se utiizar """ também.
  • O """ de fechamento do dosctring de múltiplas linhas deve estar em uma linha própria, preferencialmente sendo precedido por uma linha em branco.
def complex(real=0.0, imag=0.0):
    """
    Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)

    """
    if imag == 0.0 and real == 0.0:
         return complex_zero
    ...

6. Versionamento

Deve ser incluída a seguinte linha depois do docstring do módulo, antes de qualquer outro código, separado por uma linha branca antes e depois:

__version__ = "$Revision: 63990 $"

Ele será sincronizado com o SVN.

7. Convenções de Nomenclatura

É fundamental manter consistência dentro de bibliotecas e módulos.

Existem os seguintes estilos de nomenclatura:

  • b (única letra minúscula)
  • B (única letra maiúscula)
  • lowercase (minúsculas)
  • lowercase_with_underscore (minúscula com '_')
  • UPPERCASE (maiúscula)
  • UPPERCASE_WITH_UNDERSCORE (maiúscula com '_')
  • CapitalizedWords? (iniciais com letras maiúsculas), neste caso, entretanto, quando houverem siglas, devem ser mantidas com maiúsculas ex: HTTPServerError)
  • mixedCase (igual a CapitalizedWords?, mas com iniciais minúsculas)
  • Capitalized_Words_With_Underscore (semelhante a CapitalizedWords?, mas com '_' entre as palavras - FEIO!)

Prescrição de Nomenclatura

There's also the style of using a short unique prefix to group related names together. This is not used much in Python, but it is mentioned for completeness. For example, the os.stat() function returns a tuple whose items traditionally have names like st_mode, st_size, st_mtime and so on. (This is done to emphasize the correspondence with the fields of the POSIX system call struct, which helps programmers familiar with that.)

The X11 library uses a leading X for all its public functions. In Python, this style is generally deemed unnecessary because attribute and method names are prefixed with an object, and function names are prefixed with a module name.

In addition, the following special forms using leading or trailing underscores are recognized (these can generally be combined with any case convention):

  • _single_leading_underscore: weak "internal use" indicator. E.g. "from M import *" does not import objects whose name starts with an underscore.
  • single_trailing_underscore_: used by convention to avoid conflicts with Python keyword, e.g.

Tkinter.Toplevel(master, class_='ClassName?')

  • double_leading_underscore: when naming a class attribute, invokes name mangling (inside class FooBar?, boo becomes _FooBarboo; see below).
  • double_leading_and_trailing_underscore: "magic" objects or attributes that live in user-controlled namespaces. E.g. init, import or file. Never invent such names; only use them as documented.

Prescriptive: Naming Conventions

Names to Avoid

Never use the characters l' (lowercase letter el), O' (uppercase letter oh), or `I' (uppercase letter eye) as single character variable names.

In some fonts, these characters are indistinguishable from the numerals one and zero. When tempted to use l', use L' instead.

Package and Module Names

Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability. Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

Since module names are mapped to file names, and some file systems are case insensitive and truncate long names, it is important that module names be chosen to be fairly short -- this won't be a problem on Unix, but it may be a problem when the code is transported to older Mac or Windows versions, or DOS.

When an extension module written in C or C++ has an accompanying Python module that provides a higher level (e.g. more object oriented) interface, the C/C++ module has a leading underscore (e.g. _socket).

Class Names

Almost without exception, class names use the CapWords? convention. Classes for internal use have a leading underscore in addition.

Exception Names

Because exceptions should be classes, the class naming convention applies here. However, you should use the suffix "Error" on your exception names (if the exception actually is an error).

Global Variable Names

(Let's hope that these variables are meant for use inside one module only.) The conventions are about the same as those for functions.

Modules that are designed for use via "from M import *" should use the all mechanism to prevent exporting globals, or use the older convention of prefixing such globals with an underscore (which you might want to do to indicate these globals are "module non-public").

Function Names

Function names should be lowercase, with words separated by underscores as necessary to improve readability.

mixedCase is allowed only in contexts where that's already the prevailing style (e.g. threading.py), to retain backwards compatibility.

Function and method arguments

Always use 'self' for the first argument to instance methods.

Always use 'cls' for the first argument to class methods.

If a function argument's name clashes with a reserved keyword, it is generally better to append a single trailing underscore rather than use an abbreviation or spelling corruption. Thus "print_" is better than "prnt". (Perhaps better is to avoid such clashes by using a synonym.)

Method Names and Instance Variables

Use the function naming rules: lowercase with words separated by underscores as necessary to improve readability.

Use one leading underscore only for non-public methods and instance variables.

To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.

Python mangles these names with the class name: if class Foo has an attribute named a, it cannot be accessed by Foo.a. (An insistent user could still gain access by calling Foo._Fooa.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.

Note: there is some controversy about the use of names (see below).

Designing for inheritance

Always decide whether a class's methods and instance variables (collectively: "attributes") should be public or non-public. If in doubt, choose non-public; it's easier to make it public later than to make a public attribute non-public.

Public attributes are those that you expect unrelated clients of your class to use, with your commitment to avoid backward incompatible changes. Non-public attributes are those that are not intended to be used by third parties; you make no guarantees that non-public attributes won't change or even be removed.

We don't use the term "private" here, since no attribute is really private in Python (without a generally unnecessary amount of work).

Another category of attributes are those that are part of the "subclass API" (often called "protected" in other languages). Some classes are designed to be inherited from, either to extend or modify aspects of the class's behavior. When designing such a class, take care to make explicit decisions about which attributes are public, which are part of the subclass API, and which are truly only to be used by your base class.

With this in mind, here are the Pythonic guidelines:

  • Public attributes should have no leading underscores.
  • If your public attribute name collides with a reserved keyword, append a single trailing underscore to your attribute name. This is preferable to an abbreviation or corrupted spelling. (However, notwithstanding this rule, 'cls' is the preferred spelling for any variable or argument which is known to be a class, especially the first argument to a class method.)

Note 1: See the argument name recommendation above for class methods.

  • For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.

Note 1: Properties only work on new-style classes.

Note 2: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine.

Note 3: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap.

  • If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name.

Note 1: Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions.

Note 2: Name mangling can make certain uses, such as debugging and getattr(), less convenient. However the name mangling algorithm is well documented and easy to perform manually.

Note 3: Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers.

8. Recomendações de Programação

  • O código deve ser escrito de um modo que não seja desvantajoso a outras implementações do Python (PyPy?, Jython, IronPython?, Pyrex, Psyco, e similares). Por exemplo:
# Concatenação de string
# Utilizando CPython temos bom desempenho ao fazer:
a += b

# Mas isso roda mais lentamente em Jython. Para manter um desempenho adequado, deve-se utilizar nestes casos:
a.join(b)

# Isso permite que a concatenação ocorra em tempo linear em todas as implementações
  • Comparações com None devem ser realizadas utilizando 'is' ou 'is not', nunca com operadores de igualdade. É importante, também, atentar para utilização de "if x" quando se deseja expressar "if x is not None", pois a resposta poderia ser a mesma se c contiver um operador booleano.
  • Utilize exceções baseadas em classes. Para criar novas excessões em módulos deve-se utilizar a forma apresentada a seguir. Sempre escreva o docstring.
class MessageError(Exception):
    """
    Base class for erros in the email package.
     """

Deve-se obedecer as convenções de nomenclatura de classe, adicionando-se o sufixo "Error" às classes de exceção, se corresponderem a um erro. Exceções que não9 correspondem a erro não precisam de sufixo.

  • Quando gerar uma exceção, utilize:
    raise ValueError('message')
    
  • Quando tratar exceções, sempre especifique o tipo de exceção tratada.
try:
    import plataform_specific_module
except ImportError:
    plataform_specific_module = None

Um 'except' perdido pode esconder outros problemas.

  • Juntamente, para todas as cláusulas try / except, insira a menor quantidade de código necessário na cláusula 'try'. Novamente, evite mascarar bugs.
# Sim:
try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

# Não:
try:
    # muitas informações
    return handle_value(collection[key])
except KeyError:
    # também pegará o KeyError lançado por handle_value()
    return key_not_found(key)
  • Utilize métodos da string ao invés de utilizar o módulo string.

Métodos de string são muito mais rápidos e utilizam a mesma API que strings unicode.

* Utilize ".startswith()" e ".endswith()" ao invés de fatiar a string para avaliar sufixos e prefixos.

# Sim:
if foo.statswith('bar'):

# Não:
if foo[:3] == 'bar':
  • Para comparar o tipo de objetos deve-se utilizar isinstance() ao invés de compará-los diretamente.
# Sim:
if isinstance(obj, int):

# Não:
if type(obj) is type(1):
  • Quando verificar se um objeto é uma string, atente que pode ser uma string unicode também!
  • Para sequências (strings, listas e tuplas), utilize o fato que sequências vazias são falsas.
# Sim:
if not seq:
if seq:

# Não:
if len(seq):
if not len(seq):
  • Não escreva literais do tipo string que dependam de espaços em branco significativos. Eles são visualmente indistinguíveis e alguns editores irão removê-los (ou o  reindent-py).
  • Não compare valores booleanos com True ou False utilizando ==
# Sim:
if greeting:

# Não:
if greeting == True:

# Nunca:
if greeting is True:

Attachments