Chapter 2: A linguagem Python

 A linguagem Python

Python

 Sobre o Python

Python é uma linguagem de programação de alto nível de propósito geral. Sua filosofia de design enfatiza a produtividade do programador e a legibilidade do código. Ele tem uma sintaxe básica minimalista com poucos comandos básicos e semântica simples, mas também possui uma biblioteca padrão grande e abrangente, incluindo uma API (Interface de Programação de Aplicativo).

API
 para muitas das funções do sistema operacional (SO) subjacente. O código Python, embora minimalista, define objetos internos, como listas vinculadas ( list ), tuplas ( tuple ), tabelas hash ( dict ) e inteiros arbitrariamente longos ( long ).

O Python suporta vários paradigmas de programação, incluindo orientados a objetos ( class ), imperativo ( def ) e funcional ( lambda ) programação. O Python possui um sistema de tipo dinâmico e gerenciamento automático de memória usando contagem de referência (semelhante a Perl, Ruby e Scheme).

O Python foi lançado pela primeira vez por Guido van Rossum em 1991. O idioma tem um modelo de desenvolvimento aberto e baseado na comunidade, gerenciado pela Python Software Foundation, uma instituição sem fins lucrativos. Existem muitos interpretadores e compiladores que implementam a linguagem Python, incluindo um em Java (Jython), mas, nesta breve revisão, nos referimos à implementação de referência C criada por Guido.

Você pode encontrar muitos tutoriais, a documentação oficial e as referências de biblioteca da linguagem no site oficial do Python. [python]

Para referências adicionais em Python, podemos recomendar os livros na ref. [guido]   e ref. [lutz]  .

Você pode pular este capítulo se já estiver familiarizado com a linguagem Python.

 Começando

shell

As distribuições binárias do web2py para o Microsoft Windows ou o Apple OS X vêm empacotadas com o interpretador Python embutido no próprio arquivo diqstribution.

Você pode iniciá-lo no Windows com o seguinte comando (digite no prompt do DOS):

web2py.exe -S welcome

No Apple OS X, digite o seguinte tipo de comando em uma janela do Terminal (supondo que você esteja na mesma pasta que web2py.app):

./web2py.app/Contents/MacOS/web2py -S welcome

Em um Linux ou outra caixa Unix, é provável que você já tenha o Python instalado. Em caso afirmativo, em um prompt do shell, digite:

python web2py.py -S welcome

Se você não tiver o Python 2.7 instalado, você terá que baixá-lo e instalá-lo antes de executar o web2py.

o -S welcome  opção de linha de comando instrui o web2py a executar o shell interativo como se os comandos fossem executados em um controlador para o bem vinda aplicação, a aplicação web2py scaffolding. Isso expõe quase todas as classes web2py, objetos e funções para você. Esta é a única diferença entre a linha de comando interativa do web2py e a linha de comando normal do Python.

A interface administrativa também fornece um shell baseado na web para cada aplicativo. Você pode acessar aquele para o aplicativo "welcome" em.

http://127.0.0.1:8000/admin/shell/index/welcome

Você pode tentar todos os exemplos neste capítulo usando o shell normal ou o shell baseado na web.

 ajuda, dir
help
 
dir

A linguagem Python fornece dois comandos para obter documentação sobre objetos definidos no escopo atual, tanto interno como definido pelo usuário.

Nós podemos pedir help  sobre um objeto, por exemplo "1":

>>> help(1)
Help on int object:

class int(object)
 |  int(x[, base]) -> integer
 |
 |  Convert a string or number to an integer, if possible.  A floating point
 |  argument will be truncated towards zero (this does not include a string
 |  representation of a floating point number!)  When converting a string, use
 |  the optional base.  It is an error to supply a base when converting a
 |  non-string. If the argument is outside the integer range a long object
 |  will be returned instead.
 |
 |  Methods defined here:
 |
 |  __abs__(...)
 |      x.__abs__() <==> abs(x)
...

e, como "1" é um inteiro, obtemos uma descrição sobre o int  classe e todos os seus métodos. Aqui a saída foi truncada porque é muito longa e detalhada.

Da mesma forma, podemos obter uma lista de métodos do objeto "1" com o comando dir :

>>> dir(1)
['__abs__', ..., '__xor__']

 Tipos

type

O Python é uma linguagem tipificada dinamicamente, o que significa que as variáveis não possuem um tipo e, portanto, não precisam ser declaradas. Os valores, por outro lado, têm um tipo. Você pode consultar uma variável para o tipo de valor que ela contém:

>>> a = 3
>>> print type(a)
<type 'int'>
>>> a = 3.14
>>> print type(a)
<type 'float'>
>>> a = 'hello python'
>>> print type(a)
<type 'str'>

O Python também inclui, nativamente, estruturas de dados, como listas e dicionários.

  str
str
 
ASCII
 
UTF8
 
Unicode
 
encode

O Python suporta o uso de dois tipos diferentes de strings: strings ASCII e strings Unicode. Strings ASCII são delimitadas por '...' , "..."  ou pela '''..'''  ou """...""" . Aspas triplas delimitam cadeias de caracteres de múltiplas linhas. Strings Unicode começam com um u  seguido pela string contendo caracteres Unicode. Uma string Unicode pode ser convertida em uma string ASCII escolhendo uma codificação por exemplo:

>>> a = 'this is an ASCII string'
>>> b = u'This is a Unicode string'
>>> a = b.encode('utf8')

Depois de executar estes três comandos, o resultado a  é uma string ASCII que armazena caracteres codificados em UTF8. Por design, o web2py usa strings codificadas em UTF8 internamente.

Também é possível gravar variáveis em cadeias de várias maneiras:

>>> print 'number is ' + str(3)
number is 3
>>> print 'number is %s' % (3)
number is 3
>>> print 'number is %(number)s' % dict(number=3)
number is 3

A última notação é mais explícita e menos propensa a erros e deve ser preferida.

Muitos objetos Python, por exemplo, números, podem ser serializados em strings usando str  ou repr . Esses dois comandos são muito semelhantes, mas produzem resultados ligeiramente diferentes. Por exemplo:

>>> for i in [3, 'hello']:
        print str(i), repr(i)
3 3
hello 'hello'

Para classes definidas pelo usuário, str  e repr  pode ser definido/redefinido usando os operadores especiais __str__  e __repr__ . Estes são brevemente descritos mais adiante; para mais, consulte a documentação oficial do Python [pydocs]  . repr  sempre tem um valor padrão.

Outra característica importante de uma string Python é que, como uma lista, é um objeto iterável.

>>> for i in 'hello':
        print i
h
e
l
l
o

  list

list

Os principais métodos de uma lista do Python são acrescentar, inserir e excluir:

>>> a = [1, 2, 3]
>>> print type(a)
<type 'list'>
>>> a.append(8)
>>> a.insert(2, 7)
>>> del a[0]
>>> print a
[2, 7, 3, 8]
>>> print len(a)
4

As listas podem ser cortadas:

>>> print a[:3]
[2, 7, 3]
>>> print a[1:]
[7, 3, 8]
>>> print a[-2:]
[3, 8]

e concatenado:

>>> a = [2, 3]
>>> b = [5, 6]
>>> print a + b
[2, 3, 5, 6]

Uma lista é iterável; você pode passar por cima disso:

>>> a = [1, 2, 3]
>>> for i in a:
        print i
1
2
3

Os elementos de uma lista não precisam ser do mesmo tipo; eles podem ser qualquer tipo de objeto Python.

Existe uma situação muito comum para a qual uma compreensão de lista pode ser usada. Considere o seguinte código:

>>> a = [1, 2, 3, 4, 5]
>>> b = []
>>> for x in a:
        if x % 2 == 0:
            b.append(x * 3)
>>> b
[6, 12]

Esse código processa claramente uma lista de itens, seleciona e modifica um subconjunto da lista de entrada e cria uma nova lista de resultados, e esse código pode ser totalmente substituído pela seguinte compreensão da lista:

>>> a = [1, 2, 3, 4, 5]
>>> b = [x * 3 for x in a if x % 2 == 0]
>>> b
[6, 12]

  tuple

tuple

Uma tupla é como uma lista, mas seu tamanho e elementos são imutáveis, enquanto em uma lista eles são mutáveis. Se um elemento da tupla é um objeto, os atributos do objeto são mutáveis. Uma tupla é delimitada por colchetes.

>>> a = (1, 2, 3)

Então, enquanto isso funciona para uma lista:

>>> a = [1, 2, 3]
>>> a[1] = 5
>>> print a
[1, 5, 3]

a designação de elemento não funciona para uma tupla:

>>> a = (1, 2, 3)
>>> print a[1]
2
>>> a[1] = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Uma tupla, como uma lista, é um objeto iterável. Observe que uma tupla que consiste em um único elemento deve incluir uma vírgula final, conforme mostrado abaixo:

>>> a = (1)
>>> print type(a)
<type 'int'>
>>> a = (1, )
>>> print type(a)
<type 'tuple'>

As tuplas são muito úteis para o empacotamento eficiente de objetos devido à sua imutabilidade, e os suportes são muitas vezes opcionais:

>>> a = 2, 3, 'hello'
>>> x, y, z = a
>>> print x
2
>>> print z
hello

  dict

dict

Um Python dict -ionary é uma tabela de hash que mapeia um objeto-chave para um objeto de valor. Por exemplo:

>>> a = {'k':'v', 'k2':3}
>>> a['k']
v
>>> a['k2']
3
>>> a.has_key('k')
True
>>> a.has_key('v')
False

As chaves podem ser de qualquer tipo hashable (int, string ou qualquer objeto cuja classe implemente __hash__  método). Os valores podem ser de qualquer tipo. Chaves e valores diferentes no mesmo dicionário não precisam ser do mesmo tipo. Se as chaves forem caracteres alfanuméricos, um dicionário também poderá ser declarado com a sintaxe alternativa:

>>> a = dict(k='v', h2=3)
>>> a['k']
v
>>> print a
{'k':'v', 'h2':3}

Métodos úteis são has_key , keys , values  e items :

>>> a = dict(k='v', k2=3)
>>> print a.keys()
['k', 'k2']
>>> print a.values()
['v', 3]
>>> print a.items()
[('k', 'v'), ('k2', 3)]

o items  O método produz uma lista de tuplas, cada uma contendo uma chave e seu valor associado.

Elementos de dicionário e elementos de lista podem ser excluídos com o comando del :

>>> a = [1, 2, 3]
>>> del a[1]
>>> print a
[1, 3]
>>> a = dict(k='v', h2=3)
>>> del a['h2']
>>> print a
{'k':'v'}

Internamente, o Python usa o hash  operador para converter objetos em inteiros, e usa esse inteiro para determinar onde armazenar o valor.

>>> hash("hello world")
-1500746465

 Sobre indentação

Python usa recuo para delimitar blocos de código. Um bloco começa com uma linha que termina em dois pontos e continua para todas as linhas com um recuo semelhante ou mais alto que a linha seguinte. Por exemplo:

>>> i = 0
>>> while i < 3:
>>>    print i
>>>    i = i + 1
>>>
0
1
2

É comum usar quatro espaços para cada nível de recuo. É uma boa política não misturar guias com espaços, o que pode resultar em confusão (invisível).

  for...in

for

No Python, você pode fazer um loop sobre objetos iteráveis:

>>> a = [0, 1, 'hello', 'python']
>>> for i in a:
        print i
0
1
hello
python

Um atalho comum é xrange , que gera um intervalo iterável sem armazenar toda a lista de elementos.

>>> for i in xrange(0, 4):
        print i
0
1
2
3

Isto é equivalente à sintaxe C/C++/C#/Java:

for(int i=0; i<4; i=i+1) { print(i); }

Outro comando útil é enumerate , que conta enquanto loop:

>>> a = [0, 1, 'hello', 'python']
>>> for i, j in enumerate(a):
        print i, j
0 0
1 1
2 hello
3 python

Existe também uma palavra-chave range(a, b, c)  que retorna uma lista de números inteiros começando com o valor a , incrementando por c e terminando com o último valor menor que b , a  o padrão é 0 e c  O padrão é 1. xrange  é semelhante, mas na verdade não gera a lista, apenas um iterador sobre a lista; Assim, é melhor para o loop.

Você pode pular de um loop usando break

>>> for i in [1, 2, 3]:
         print i
         break
1

Você pode pular para a próxima iteração de loop sem executar todo o bloco de código com continue

>>> for i in [1, 2, 3]:
         print i
         continue
         print 'test'
1
2
3

  while

while

o while  O loop no Python funciona da mesma forma que em muitas outras linguagens de programação, fazendo um loop por um número indefinido de vezes e testando uma condição antes de cada iteração. Se a condição é False , o loop termina.

>>> i = 0
>>> while i < 10:
        i = i + 1
>>> print i
10

Não há loop...until  construir em Python.

  if...elif...else
if
 
elif
 
else

O uso de condicionais no Python é intuitivo:

>>> for i in range(3):
>>>     if i == 0:
>>>         print 'zero'
>>>     elif i == 1:
>>>         print 'one'
>>>     else:
>>>         print 'other'
zero
one
other

"elif" significa "mais se". Ambos as cláusulas elif  e else são opcionais. Pode haver mais de um elif  mas apenas um else  declaração. Condições complexas podem ser criadas usando o not , and  e or  operadores.

>>> for i in range(3):
>>>     if i == 0 or (i == 1 and i + 1 == 2):
>>>         print '0 or 1'

  try...except...else...finally
try
 
except
 
finally
 
Exception

Python pode jogar - perdão, levantar - Exceções:

>>> try:
>>>     a = 1 / 0
>>> except Exception, e:
>>>     print 'oops: %s' % e
>>> else:
>>>     print 'no problem here'
>>> finally:
>>>     print 'done'
oops: integer division or modulo by zero
done

Se a exceção é levantada, ela é capturada pela cláusula except, que é executada, enquanto a cláusula else não é. Se nenhuma exceção for levantada, a cláusula except não é executada, mas o else é. A cláusula finally é sempre executada.

Pode haver várias cláusulas except  para diferentes exceções possíveis:

>>> try:
>>>     raise SyntaxError
>>> except ValueError:
>>>     print 'value error'
>>> except SyntaxError:
>>>     print 'syntax error'
syntax error

as cláusulas else  e finally são opcionais.

Aqui está uma lista de exceções do Python + HTTP (definidas pelo web2py)

BaseException
 +-- HTTP (defined by web2py)
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- Exception
      +-- GeneratorExit
      +-- StopIteration
      +-- StandardError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |    |    +-- UnicodeError
      |    |         +-- UnicodeDecodeError
      |    |         +-- UnicodeEncodeError
      |    |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning

Para uma descrição detalhada de cada um deles, consulte a documentação oficial do Python.

web2py expõe apenas uma nova exceção, chamada HTTP . Quando levantada, faz com que o programa retorne uma página de erro HTTP (para mais informações, consulte o Capítulo 4).

Qualquer objeto pode ser levantaar uma exceção, mas é uma boa prática levantar objetos que estendem uma das classes de exceção internas.

  def...return
def
 
return

Funções são declaradas usando def . Aqui está uma função típica do Python:

>>> def f(a, b):
        return a + b
>>> print f(4, 2)
6

Não há necessidade (ou forma) de especificar os tipos de argumentos ou o (s) tipo (s) de retorno. Neste exemplo, uma função f  é definido que pode levar dois argumentos.

Funções são o primeiro recurso de sintaxe de código descrito neste capítulo para introduzir o conceito de scope ou namespace . No exemplo acima, os identificadores a  e b  são indefinidos fora do escopo da função f :

>>> def f(a):
        return a + 1
>>> print f(1)
2
>>> print a
Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    print a
NameError: name 'a' is not defined

Identificadores definidos fora do escopo da função são acessíveis dentro da função; observe como o identificador a  é tratado no seguinte código:

>>> a = 1
>>> def f(b):
        return a + b
>>> print f(1)
2
>>> a = 2
>>> print f(1) # new value of a is used
3
>>> a = 1 # reset a
>>> def g(b):
        a = 2 # creates a new local a
        return a + b
>>> print g(2)
4
>>> print a # global a is unchanged
1

E se a  for modificado, as chamadas de função subseqüentes usarão o novo valor do a  porque a definição da função liga o local de armazenamento do identificador a , não o valor de a  se no momento da declaração de função; no entanto, se a  é atribuído a dentro da função g , o global a  não é afetado porque o novo local a  esconde o valor global. A referência de escopo externo pode ser usada na criação de encerramentos :

>>> def f(x):
        def g(y):
            return x * y
        return g
>>> doubler = f(2) # doubler is a new function
>>> tripler = f(3) # tripler is a new function
>>> quadrupler = f(4) # quadrupler is a new function
>>> print doubler(5)
10
>>> print tripler(5)
15
>>> print quadrupler(5)
20

Função f  cria novas funções; e observe que o escopo do nome g  é inteiramente interno para f . Fechamentos são extremamente poderosos.

Argumentos de função podem ter valores padrão e podem retornar vários resultados:

>>> def f(a, b=2):
        return a + b, a - b
>>> x, y = f(5)
>>> print x
7
>>> print y
3

Os argumentos da função podem ser passados explicitamente pelo nome, e isso significa que a ordem dos argumentos especificados no chamador pode ser diferente da ordem dos argumentos com os quais a função foi definida:

>>> def f(a, b=2):
        return a + b, a - b
>>> x, y = f(b=5, a=2)
>>> print x
7
>>> print y
-3

As funções também podem ter um número de argumentos de variável de tempo de execução:

>>> def f(*a, **b):
        return a, b
>>> x, y = f(3, 'hello', c=4, test='world')
>>> print x
(3, 'hello')
>>> print y
{'c':4, 'test':'world'}

Aqui os argumentos não passados pelo nome (3, 'olá') são armazenados na tupla a e argumentos passados pelo nome ( c  e test ) são armazenados no dicionário b .

No caso oposto, uma lista ou tupla pode ser passada para uma função que requer argumentos posicionais individuais, descompactando-os:

>>> def f(a, b):
        return a + b
>>> c = (1, 2)
>>> print f(*c)
3

e um dicionário pode ser descompactado para fornecer argumentos de palavras-chave:

>>> def f(a, b):
        return a + b
>>> c = {'a':1, 'b':2}
>>> print f(**c)
3

  lambda

lambda

lambda  fornece uma maneira de criar uma função muito curta sem nome muito facilmente:

>>> a = lambda b: b + 2
>>> print a(3)
5

A expressão " lambda  [a]: [b] "literalmente lê como" uma função com argumentos [a] que retorna [b] ". lambda  expressão é ela mesma sem nome, mas a função adquire um nome sendo atribuída ao identificador a . As regras de escopo para def  aplicar a lambda  igualmente, e de fato o código acima, com relação a a , é idêntica à declaração de função usando def :

>>> def a(b):
        return b + 2
>>> print a(3)
5

O único benefício de lambda  é brevidade; no entanto, a brevidade pode ser muito conveniente em determinadas situações. Considere uma função chamada map  que aplica uma função a todos os itens de uma lista, criando uma nova lista:

>>> a = [1, 7, 2, 5, 4, 8]
>>> map(lambda x: x + 2, a)
[3, 9, 4, 7, 6, 10]

Esse código teria dobrado de tamanho def  foi usado em vez de lambda . A principal desvantagem de lambda  é que (na implementação do Python) a sintaxe permite apenas uma única expressão; no entanto, para funções mais longas, def  pode ser usado e o custo extra de fornecer um nome de função diminui à medida que o comprimento da função aumenta. Assim como def , lambda  pode ser usado para funções curry : novas funções podem ser criadas agrupando funções existentes de tal forma que a nova função carrega um conjunto diferente de argumentos:

>>> def f(a, b): return a + b
>>> g = lambda a: f(a, 3)
>>> g(2)
5

Existem muitas situações em que o currying é útil, mas uma delas é diretamente útil no web2py: caching. Suponha que você tenha uma função cara que verifique se o argumento é primo:

def isprime(number):
    for p in range(2, number):
        if (number % p) == 0:
            return False
    return True

Esta função é obviamente demorada.

Suponha que você tenha uma função de cache cache.ram  isso leva três argumentos: uma chave, uma função e um número de segundos.

value = cache.ram('key', f, 60)

A primeira vez que é chamado, chama a função f() , armazena a saída em um dicionário na memória (digamos "d") e retorna para que o valor seja:

value = d['key']=f()

A segunda vez que é chamada, se a chave estiver no dicionário e não for mais antiga que o número de segundos especificado (60), ela retornará o valor correspondente sem executar a chamada de função.

value = d['key']

Como você armazenaria em cache a saída da função isprime para alguma entrada? Aqui está como:

>>> number = 7
>>> seconds = 60
>>> print cache.ram(str(number), lambda: isprime(number), seconds)
True
>>> print cache.ram(str(number), lambda: isprime(number), seconds)
True

A saída é sempre a mesma, mas a primeira vez cache.ram  é chamado, isprime  é chamado; a segunda vez não é.

Funções Python, criadas com def  ou lambda  permitir refatorar funções existentes em termos de um conjunto diferente de argumentos. cache.ram  e cache.disk  são funções de cache web2py.

  class

class

Como o Python é digitado dinamicamente, as classes e objetos do Python podem parecer estranhos. Na verdade, você não precisa definir as variáveis de membro (atributos) ao declarar uma classe, e instâncias diferentes da mesma classe podem ter atributos diferentes. Os atributos são geralmente associados à instância, não à classe (exceto quando declarados como "atributos de classe", que é o mesmo que "variáveis de membro estático" em C ++/Java).

Aqui está um exemplo:

>>> class MyClass(object): pass
>>> myinstance = MyClass()
>>> myinstance.myvariable = 3
>>> print myinstance.myvariable
3

Notar que pass  é um comando do-nothing. Neste caso, é usado para definir uma classe MyClass  que não contém nada. MyClass()  chama o construtor da classe (neste caso, o construtor padrão) e retorna um objeto, uma instância da classe. o (object)  na definição de classe indica que nossa classe estende o built-in object  classe. Isso não é obrigatório, mas é uma boa prática.

Aqui está uma classe mais complexa:

>>> class MyClass(object):
>>>    z = 2
>>>    def __init__(self, a, b):
>>>        self.x = a
>>>        self.y = b
>>>    def add(self):
>>>        return self.x + self.y + self.z
>>> myinstance = MyClass(3, 4)
>>> print myinstance.add()
9

Funções declaradas dentro da classe são métodos. Alguns métodos possuem nomes reservados especiais. Por exemplo, __init__  é o construtor. Todas as variáveis são variáveis locais do método, exceto variáveis declaradas fora dos métodos. Por exemplo, z  é uma variável de classe , equivalente a uma 'variável de membro estático' em C ++ que contém o mesmo valor para todas as instâncias da classe.

Notar que __init__  leva 3 argumentos e add  leva um, e ainda os chamamos com argumentos 2 e 0, respectivamente. O primeiro argumento representa, por convenção, o nome local usado dentro do método para se referir ao objeto atual. Aqui nós usamos self  para se referir ao objeto atual, mas poderíamos ter usado qualquer outro nome. self  desempenha o mesmo papel que *this  em C ++ ou this  em Java, mas self  não é uma palavra reservada.

Essa sintaxe é necessária para evitar ambigüidade ao declarar classes aninhadas, como uma classe que é local para um método dentro de outra classe.

 Atributos especiais, métodos e operadores

Atributos de classe, métodos e operadores que começam com sublinhado duplo geralmente são intencionalmente privados (isto é, para serem usados internamente, mas não expostos fora da classe), embora essa seja uma convenção que não é imposta pelo interpretador.

Alguns deles são palavras-chave reservadas e têm um significado especial.

Aqui, como exemplo, são três deles:

  • __len__
  • __getitem__
  • __setitem__

Eles podem ser usados, por exemplo, para criar um objeto contêiner que age como uma lista:

>>> class MyList(object):
>>>     def __init__(self, *a): self.a = list(a)
>>>     def __len__(self): return len(self.a)
>>>     def __getitem__(self, i): return self.a[i]
>>>     def __setitem__(self, i, j): self.a[i] = j
>>> b = MyList(3, 4, 5)
>>> print b[1]
4
>>> b.a[1] = 7
>>> print b.a
[3, 7, 5]

Outros operadores especiais incluem __getattr__  e __setattr__ , que definem os atributos get e set para a classe, e __sum__  e __sub__ , que sobrecarregam os operadores aritméticos. Para o uso desses operadores, encaminhamos o leitor para livros mais avançados sobre esse assunto. Já mencionamos os operadores especiais __str__  e __repr__ .

 Entrada/saída de arquivo
file.read
 
file.write

No Python, você pode abrir e gravar em um arquivo com:

>>> file = open('myfile.txt', 'w')
>>> file.write('hello world')
>>> file.close()

Da mesma forma, você pode ler de volta do arquivo com:

>>> file = open('myfile.txt', 'r')
>>> print file.read()
hello world

Alternativamente, você pode ler em modo binário com "rb", escrever no modo binário com "wb" e abrir o arquivo no modo de acréscimo "a", usando a notação C padrão.

o read  comando recebe um argumento opcional, que é o número de bytes. Você também pode pular para qualquer local em um arquivo usando seek .

file.seek

Você pode ler de volta do arquivo com read

>>> print file.seek(6)
>>> print file.read()
world

e você pode fechar o arquivo com:

>>> file.close()

Na distribuição padrão do Python, que é conhecida como CPython, as variáveis são contadas por referência, incluindo aquelas que contêm identificadores de arquivo, portanto o CPython sabe que quando a contagem de referência de um identificador de arquivo aberto diminui para zero, o arquivo pode ser fechado e a variável descartado. No entanto, em outras implementações do Python, como PyPy, a coleta de lixo é usada em vez da contagem de referência, e isso significa que é possível que possa acumular muitos identificadores de arquivos abertos ao mesmo tempo, resultando em um erro antes do '' gc ' 'tem a chance de fechar e dispor de todos eles. Portanto, é melhor fechar explicitamente os identificadores de arquivo quando eles não forem mais necessários. 'web2py' fornece duas funções auxiliares read_file()  e write_file()  dentro de gluon.fileutils  namespace que encapsulam o acesso ao arquivo e garantem que os manipuladores de arquivos que estão sendo usados sejam fechados corretamente.

Ao usar o web2py, você não sabe onde o diretório atual está, porque depende de como o web2py está configurado. A variável request.folder  contém o caminho para o aplicativo atual. Caminhos podem ser concatenados com o comando os.path.join , discutido abaixo.

  exec , eval
exec
 
eval

Ao contrário do Java, o Python é uma linguagem verdadeiramente interpretada. Isso significa que ele tem a capacidade de executar instruções do Python armazenadas em strings. Por exemplo:

>>> a = "print 'hello world'"
>>> exec(a)
'hello world'

O que acabou de acontecer? A função exec  diz ao intérprete para chamar a si mesmo e executar o conteúdo da string passada como argumento. Também é possível executar o conteúdo de uma string dentro de um contexto definido pelos símbolos em um dicionário:

>>> a = "print b"
>>> c = dict(b=3)
>>> exec(a, {}, c)
3

Aqui o intérprete, ao executar a string a , vê os símbolos definidos em c  ( b  no exemplo), mas não vê c  ou a  si mesmos. Isso é diferente de um ambiente restrito, já que exec  não limita o que o código interno pode fazer; Apenas define o conjunto de variáveis visíveis para o código.

Uma função relacionada é eval , que funciona muito bem exec  exceto que espera que o argumento avalie para um valor e retorna esse valor.

>>> a = "3*4"
>>> b = eval(a)
>>> print b
12

  import
import
 
random

O poder real do Python está em seus módulos de biblioteca. Eles fornecem um conjunto grande e consistente de Interfaces de Programação de Aplicativos (APIs) para muitas bibliotecas do sistema (geralmente de maneira independente do sistema operacional).

Por exemplo, se você precisar usar um gerador de números aleatórios, você pode fazer:

>>> import random
>>> print random.randint(0, 9)
5

Isso imprime um número inteiro aleatório entre 0 e 9 (incluindo 9), 5 no exemplo. A função randint  é definido no módulo random . Também é possível importar um objeto de um módulo para o namespace atual:

>>> from random import randint
>>> print randint(0, 9)

ou importe todos os objetos de um módulo para o namespace atual:

>>> from random import *
>>> print randint(0, 9)

ou importe tudo em um namespace recém-definido:

>>> import random as myrand
>>> print myrand.randint(0, 9)

No restante deste livro, usaremos principalmente objetos definidos em módulos os , sys , datetime , time  e cPickle .

Todos os objetos web2py são acessíveis através de um módulo chamado gluon e esse é o assunto dos capítulos posteriores. Internamente, o web2py usa muitos módulos do Python (por exemplo thread ), mas você raramente precisa acessá-los diretamente.

Nas subseções a seguir, consideramos os módulos mais úteis.

  os
os
 
os.path.join
 
os.unlink

Este módulo fornece uma interface para a API do sistema operacional. Por exemplo:

>>> import os
>>> os.chdir('..')
>>> os.unlink('filename_to_be_deleted')

Algumas das funções do módulo os , como chdir NÃO DEVEM ser usado em web2py porque elas não são thread-safe.

os.path.join  é muito útil; permite a concatenação de caminhos de uma maneira independente do SO:
>>> import os
>>> a = os.path.join('path', 'sub_path')
>>> print a
path/sub_path

Variáveis de ambiente do sistema podem ser acessadas via:

>>> print os.environ

que é um dicionário somente leitura.

  sys
sys
 
sys.path

o módulo sys contém muitas variáveis e funções, mas a que usamos mais é sys.path . Ele contém uma lista de caminhos em que o Python procura por módulos. Quando tentamos importar um módulo, o Python procura em todas as pastas listadas sys.path . Se você instalar módulos adicionais em algum local e quiser que o Python os encontre, precisará anexar o caminho para esse local sys.path .

>>> import sys
>>> sys.path.append('path/to/my/modules')

Ao executar o web2py, o Python permanece residente na memória e há apenas um sys.path , embora existam muitos threads atendendo as solicitações HTTP. Para evitar um vazamento de memória, é melhor verificar se um caminho já está presente antes de anexar:

>>> path = 'path/to/my/modules'
>>> if not path in sys.path:
        sys.path.append(path)

  datetime
date
 
datetime
 
time

O uso do módulo datetime é melhor ilustrado por alguns exemplos:

>>> import datetime
>>> print datetime.datetime.today()
2008-07-04 14:03:90
>>> print datetime.date.today()
2008-07-04

Ocasionalmente, você pode precisar registrar os dados do carimbo de data e hora com base na hora UTC, em vez da hora local. Neste caso, você pode usar a seguinte função:

>>> import datetime
>>> print datetime.datetime.utcnow()
2008-07-04 14:03:90

O módulo datetime contém várias classes: date, datetime, time e timedelta. A diferença entre duas datas ou dois objetos datetime ou two time é um timedelta:

>>> a = datetime.datetime(2008, 1, 1, 20, 30)
>>> b = datetime.datetime(2008, 1, 2, 20, 30)
>>> c = b - a
>>> print c.days
1

No web2py, date e datetime são usados para armazenar os tipos SQL correspondentes quando passados ou retornados do banco de dados.

  time

time

O módulo de tempo difere date  e datetime  porque representa o tempo como segundos da época (início de 1970).

>>> import time
>>> t = time.time()
1215138737.571

Consulte a documentação do Python para funções de conversão entre o tempo em segundos e o tempo como um datetime .

  cPickle

cPickle

Este é um módulo muito poderoso. Ele fornece funções que podem serializar praticamente qualquer objeto Python, incluindo objetos auto-referenciais. Por exemplo, vamos construir um objeto estranho:

>>> class MyClass(object): pass
>>> myinstance = MyClass()
>>> myinstance.x = 'something'
>>> a = [1 , 2, {'hello':'world'}, [3, 4, [myinstance]]]

e agora:

>>> import cPickle
>>> b = cPickle.dumps(a)
>>> c = cPickle.loads(b)

Neste exemplo, b  é uma representação de string de a e c  é uma cópia do a  gerado por desserialização b .

O cPickle também pode serializar e desserializar a partir de um arquivo:

>>> cPickle.dump(a, open('myfile.pickle', 'wb'))
>>> c = cPickle.load(open('myfile.pickle', 'rb'))
 top