Python3 02 – “Variáveis” no Python

novembro 9th, 2017 by Rudson Alves Leave a reply »
Este artigo é a parte 2 de 2 na série Python3

Neste texto, será apresentada uma breve introdução a variáveis em Python, tentando mostrar algumas particularidades da linguagem. Aproveitando o momento, pretendo dar alguns passos sobre a superfície da orientação a objetos, explorando as funções embutidas nos objetos (métodos), mas sem muita profundidade.

Tipagem dinâmica em Python

Não há declarações de variáveis no Python, podendo, em qualquer momento, uma variável ser apontada para uma string, um inteiro ou qualquer outro tipo de dado. Para acompanhar a discussão, é aconselhável iniciar o interpretador e acompanhar os exemplos:

alves@luskan:$ python3
Python 3.6.1 (default, Jul 28 2017, 17:35:34) 
[GCC 7.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>  idade = 29
>>>  pot = 1606938044258990275541962092341162602522202993782792835301376
>>>  nome = 'Sara'
>>>  sobrenome = "Bertoluci"
>>>  salário = 3600.52
>>>  Salário = "€3.600,52"

As duas primeiras variáveis declaradas são inteiros, sendo pot o valor de 2^200. O Python não possui um barreira para o tamanho de um inteiro, sendo este limitado apenas pela memória da máquina. Na sequência, são criadas duas strings, nome e sobrenome. Uma string pode ser delimitada tanto por aspas simples ou dupla, a gosto do programador. Uma novidade no Python 3 é o total suporte a Unicode, suportando qualquer caractere tanto no nome das grandezas como no conteúdo das variáveis sem qualquer restrição como na maioria das linguagens que se limitam ao um conjunto de caracteres dentro da tabela ASCII.

Os nomes das variáveis também são case sensitive (sensível à caixa das letras), de forma que salário é uma variável tipo float (ponto flutuante), enquanto Salário é uma string com o valor do salário em euros.

>>>  salário
3600.52
>>>  type(salário)
<class 'float'>
>>>  Salário
'€3.600,52'
>>>  type(Salário)
<class 'str'>

A função type() retorna a tipagem da variável.

Strings são Sequências

Uma string, em Python, é uma sequência de caracteres e, como todas as demais sequências em Python que serão discutidas em textos futuros, cada elemento (caractere) pode ser indexado por colchetes [], como em um vetor.

>>>  sobrenome
'Bertoluci'
>>>  sobrenome[3]
't'
>>>  sobrenome[-4]
'l'

Sequências também podem ser endereçadas de forma reversa, sendo -1 o índice do último elemento da sequência, -2 o penúltimo, e assim por diante. A Figura 01 apresenta todo o indexamento para os elementos da string sobrenome, de forma direta e reversa.

Figura 01: Indexação dos elementos da sequência de caracteres sobrenome.

O índice do primeiro elemento de uma sequência é sempre o zero. Todas as formas de sequências em Python obedecem ao mesmo padrão de indexamento dos elementos, assim como o fatiamento de sequências (slicing).

Slicing/Fatiamento de sequências

Sequências podem ser fatiadas passando o início e o fim do fatiamento entre colchetes como a sintaxe abaixo:


seq[início:fim]
seq[início:fim:step]

Veja algumas aplicações abaixo:

>>>  sobrenome[1:5]
'erto'
>>>  sobrenome[2:4]
'rt'
>>>  sobrenome[1:5:2]
'et'
>>>  sobrenome[2:]
'rtoluci'
>>>  sobrenome[:-2]
'Bertolu'

O primeiro comando pega do elemento [1] até o elemento [5-1] da sequência, sendo este o elemento de índice [4] da sequência sobrenome. No comando seguinte, é impresso do elemento [2] até o elemento [4-1]. No terceiro comando, é passada a opção step, a qual declara o intervalo entre os elementos tomados. Desta forma, será impresso o elemento [1] e, em seguida, o elemento [3] (início+step) da sequência.

As duas últimas linhas mostram que, quando o início não é definido, o índice 0, primeiro elemento da sequência, é tomado como padrão e, quando o fim não é definido, o índice -1, último elemento da sequência, é tomado como padrão. Portanto o sobrenome[2:] imprime do elemento de índice 2 até o final da string, enquanto que o sobrenome[:-2], imprime do início da sequência até o penúltimo elemento da sequência.

Imutável e Referência

Tipos numéricos e strings no Python são imutáveis e, por isto, não podem ter seu valor alterado uma vez definido. Ao invés de alterar o valor da variável numérica, o Python instancia um novo objeto e aponta a variável para o objeto criado.

O instanciamento de um objeto é uma consequência de que, no Python, todas estruturas de dados são objetos criados a partir de alguma classe, mas isto será abordado um pouco adiante. No momento, se atenha ao ‘imutável’ comentado anteriormente. Observe o exemplo a seguir:

>>>  a = 3
>>>  b = a
>>>  a, b
(3, 3)
>>>  a = 8
>>>  a, b
(8, 3)

Agora, veja como o Python processa estes comandos:

  1. primeiro é instanciado um objeto inteiro com conteúdo 3 e, em seguida, a referência a este objeto é passada a variável “a“, Figura 02-a;
  2. b” recebe uma cópia da referência de “a“, Figura 02-b;
  3. imprime os conteúdos apontados nas referências de “a” e “b“;
  4. em seguida, é instanciado um novo objeto inteiro com o conteúdo 8 e sua referência é passada para “a“, Figura 02-c;
  5. por fim, imprime os conteúdos apontados pelas referências em “a” e “b“.

Referenciando objetos no Python

Após “a” ter seu valor referido ao novo objeto “8”, uma consulta a “b” continua retornando o inteiro 3, pois a variável “b” continha a referência ao objeto inteiro 3. Para o programador, tudo se passa como em outras linguagens de programação tradicionais, como se a variável b tivesse seu valor sobrescrito pelo conteúdo de a, na linha b = a.

As aspas duplas empregadas nas variáveis “a” e “b” foram adicionadas com o intuito de salientar que, no Python, estas “variáveis” são, na verdade, apontamentos para objetos, no caso os inteiros 3 e 8, como fazem os ponteiros na linguagem de programação C e não variáveis como na forma tradicional.

Retomando o foco à variável sobrenome, observe que não se pode sobrescrever o conteúdos de um de seus elementos:

>>>  sobrenome[3]
't'
>>>  sobrenome[3] = 'r'
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'str' object does not support item assignment
>>>  sobrenome = 'Ribeiro'
>>>

Como dito anteriormente, uma string no Python é um imutável e não pode ter seu valor alterado. No entanto, é perfeitamente possível referenciar um novo objeto string 'Ribeiro' para o apontador sobrenome.

Embora as “variáveis” em Python sejam apenas apontadores para objetos, instancias de classes, aqui e ao longo de todos demais textos vou chamá-las apenas de variáveis, uma vez que isto é transparente para o programador. Estas escolhas do Python possuem como objetivos a performance do interpretador, bem como atender a algumas especificidades da linguagem. De forma transparente, o interpretador irá liberar a memória sempre que um objeto se tornar órfão e instanciar novos objetos sempre que for necessário.

Uma aplicação simples desta peculiaridade do Python é o swap dos valores entre duas variáveis:

>>>  a = 12
>>>  b = 'alvo'
>>>  a, b = b, a
>>>  a, b
('alvo', 12)

Como a e b são apenas apontadores para os conteúdos inteiro 12 e string 'alvo', a linha a, b = b, a apenas atribui o apontador de a para b e o de b para a.

Funções Embutidas

Uma grande vantagem da orientação a objetos para programadores iniciantes está nas funções embutidas no próprio objeto, mais conhecidas como métodos e atributos da classe. Mesmo que o programador não conheça nada de orientação a objetos, ele pode iniciar seus programas com uma gama enorme de funções e atributos essenciais para manipulação das informações em suas variáveis. Estes métodos e atributos podem ser consultados com o comando dir(), o qual gera uma lista com todos os métodos e atributos do objeto.

>>>  nome
'Sara'
>>>  dir(nome)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', 
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__',
'__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
'__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', 
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 
'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 
'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 
'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 
'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 
'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 
'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 
'zfill']

Não pretendo explorar todos os métodos e atributos da classe string, ainda porque não conheço a todos, mas vou fazer uma passada em alguns métodos interessantes que podem ser bem úteis na criação de programas.

Alguns métodos, cujos nomes possuem o formato ‘__método/atributo__‘, são para acesso a algum atributo da classe, como o seu comprimento (__len__), valor impresso (__str__) ou operadores para os quais a classe possui suporte, como:

  • __add__ adição (+), concatenação de strings
  • __mul__ multiplicação por inteiro
  • __eq__ igualdade (==)
  • __ge__ maior ou igual a (>=)
  • __gt__ maior que (>)
>>>  'H'*10
'HHHHHHHHHH'
>>>  nome += ' ' + sobrenome + ' Bertolucci'
>>>  nome
'Sara Ribeiro Bertolucci'
>>>  len(nome)
23
>>>  nome.__len__()
23
>>>  'abcd' > 'abcDe'
True
>>>  'abcd' < 'abcDe' 
False 
>>>  'abcdef'.__contains__('e')
True
>>>  'e' in 'abcdef'
True

Geralmente não se usa, nem mesmo se é encorajado usar, os métodos __len__() ou __contains__() para saber o comprimento de uma string ou se uma segunda string esta contida na primeira. O que geralmente se faz é empregar formas mais naturais como a função len() e o teste in.

A função len(nome) somente acessa o método __len__() do objeto nome e, este sim, retorna o seu comprimento. A questão é que, se o objeto não possuir o método __len__(), ele não possui a propriedade comprimento. O mesmo serve para __add__, __mul__, __le__ e tantos outros.

As linhas a seguir ilustram este ponto.

>>>  a = 10
>>>  '__len__' in  dir(a)
False
>>>  '__len__' in dir(nome)
True
>>>  len(a)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: object of type 'int' has no len()
>>>  len(nome)
23

Lembre-se de que o comando dir(objeto) retorna uma lista de métodos/atributos do objeto. Portanto, '__len__' in dir(a) retornará verdadeiro (True) somente se o método '__len__' estiver contido na lista retornada por dir(a).

Como o método __len__ não está contido na lista gerada pelos métodos/atributos do inteiro 10, o inteiro 10 não possui a propriedade comprimento e, por isto, uma tentativa de acessar seu comprimento gera o erro TypeError. Já o comando len(nome) retorna sem problemas o comprimento da string apontado por nome.

Em geral, os atributos e métodos iniciados por ‘_’ ou ‘__’ não devem ser acessador diretamente, mas sim por intermédio de outras funções ou operações. Já os nomeados são, e devem, ser usados. Seguem alguns métodos bem úteis em strings:

  • capitalize() – retorna uma string com caixa alta no primeiro caractere;
  • >>>  Nome = 'albert einstein'
    >>>  Nome.capitalize()
    'Albert einstein'
  • center(width[, fillchar]) – retorna uma string centralizada em comprimento width. O fillchar (caractere de preenchimento) é opcional, mas preenche os espaços vazios da centralização com o caractere de preenchimento;
  • >>>  Nome.center(60)
    '                      albert einstein                       '
    >>>  Nome.center(40, '*')
    '************albert einstein*************'
  • count(sub[, start[, end]]) – retorna o número de ocorrências da substring sub na string. start e end são opicionais, mas denotam as posições de início e final da busca;
  • >>>  NOME = nome + ' - ' + Nome
    >>>  NOME
    'Sara Ribeiro Bertolucci - albert einstein'
    >>>  NOME.count('er')
    2
  • find(sub[, start[, end]]) – retorna o menor índice onde a substring sub é encontrada. start e end denotam as posições de início e final da busca;
  • NOME.find('er')
    14
    >>>  NOME.find('er', 15)
    29
  • format(*args, **kwargs) – permite uma série de formatações que serão abordadas em um texto posterior;
  • >>>  Esposa='mileva marić'
    >>>  print('{Esposa} foi a ex-esposa de {Nome}.'.format(**locals()))
    mileva marić foi a ex-esposa de albert einstein.
    >>>  print('{0} foi a ex-esposa de {1}.'.format(Esposa, Nome))
    mileva marić foi a ex-esposa de albert einstein.
  • isalnum/isalpha/isdecimal/is... – uma série de testes na string que retorna verdadeiro se o teste for bem sucedido. Essencialmente, nome.islower() retorna True se todos os caracteres forem caixa baixa, nome.isdigit() retorna True se todos os caracteres forem números, …;
  • >>>  '1905'.isdigit()
    True
    >>>  'albert'.isdigit()
    False
    >>>  'albert'.islower()
    True
  • lower()/upper() – retorna uma string em caixa baixa/alta;
  • >>>  NOME
    'Sara Ribeiro Bertolucci - albert einstein'
    >>>  NOME.upper()
    'SARA RIBEIRO BERTOLUCCI - ALBERT EINSTEIN'
    >>>  NOME.lower()
    'sara ribeiro bertolucci - albert einstein'
  • split(sep=None) – retorna uma lista de palavras usando sep como caractere separador. O separador padrão é o espaço;
  • >>>  NOME.split()
    ['Sara', 'Ribeiro', 'Bertolucci', '-', 'albert', 'einstein']
    >>>  Nome.split('e')
    ['alb', 'rt ', 'inst', 'in']
  • join(interable) – retorna uma string que é a concatenação das strings no interable. Veja exemplo a seguir;
  • >>>  ' '.join(Nome.split('e'))
    'alb rt  inst in'
    >>>  'e'.join(Nome.split('e'))
    'albert einstein'
  • strip/rstrip/lstrip() – remove espaços vazios ao redor, à direita e à esquerda da string, respectivamente;
  • >>>  sobrenome = '   einstein    '
    >>>  sobrenome.strip()
    'einstein'
    >>>  sobrenome.rstrip()
    '   einstein'
    >>>  sobrenome.lstrip()
    'einstein    '
  • title() – coloca o texto no formato de título, com caixa alta nos primeiros caracteres;
  • >>>  Esposa.title()
    'Mileva Marić'
    >>>  print('{0} foi a ex-esposa de {1}.'.format(Esposa.title(), Nome.title()))
    Mileva Marić foi a ex-esposa de Albert Einstein.

QR Code
Advertisement

Deixe uma resposta

This blog is kept spam free by WP-SpamFree.