Python - Orientado a Objetos
Python tem sido uma linguagem orientada a objetos desde que existiu. Por causa disso, criar e usar classes e objetos é muito fácil. Este capítulo ajuda você a se tornar um especialista no uso do suporte de programação orientada a objetos do Python.
Se você não tem nenhuma experiência anterior com programação orientada a objetos (OO), você pode querer consultar um curso introdutório sobre isso ou pelo menos um tutorial de algum tipo para que você tenha uma compreensão dos conceitos básicos.
No entanto, aqui está uma pequena introdução da Programação Orientada a Objetos (OOP) para trazê-lo à velocidade -
Visão geral da terminologia OOP
-
Classe − Um protótipo definido pelo usuário para um objeto que define um conjunto de atributos que caracterizam qualquer objeto da classe. Os atributos são membros de dados (variáveis de classe e variáveis de instância) e métodos, acessados via notação de ponto.
-
Variável de classe − Uma variável que é compartilhada por todas as instâncias de uma classe. As variáveis de classe são definidas dentro de uma classe, mas fora de qualquer um dos métodos da classe. As variáveis de classe não são usadas com tanta frequência quanto as variáveis de instância.
-
Membro de dados − Uma variável de classe ou variável de instância que contém dados associados a uma classe e seus objetos.
-
Sobrecarga de funções − A atribuição de mais de um comportamento a uma determinada função. A operação executada varia de acordo com os tipos de objetos ou argumentos envolvidos.
-
Variável de instância − Uma variável que é definida dentro de um método e pertence apenas à instância atual de uma classe.
-
Herança − A transferência das características de uma classe para outras classes que dela derivam.
-
Instância − Um objeto individual de uma determinada classe. Um objeto obj que pertence a uma classe Circle, por exemplo, é uma instância da classe Circle.
-
Instanciação − A criação de uma instância de uma classe.
-
Método − Um tipo especial de função que é definido em uma definição de classe.
-
Objeto − Uma instância única de uma estrutura de dados que é definida por sua classe. Um objeto compreende membros de dados (variáveis de classe e variáveis de instância) e métodos.
-
Sobrecarga do operador − A atribuição de mais de uma função a um determinado operador.
Criando turmas
A classe declaração cria uma nova definição de classe. O nome da classe segue imediatamente a palavra-chave class seguido por dois pontos como segue -
class ClassName: 'Optional class documentation string' class_suite
-
A classe tem uma string de documentação, que pode ser acessada via ClassName.__doc__ .
-
A class_suite consiste em todas as instruções de componentes que definem membros de classe, atributos de dados e funções.
Exemplo
A seguir está o exemplo de uma classe Python simples -
class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
-
A variável empCount é uma variável de classe cujo valor é compartilhado entre todas as instâncias desta classe. Isso pode ser acessado como Employee.empCount de dentro da classe ou de fora da classe.
-
O primeiro método __init__() é um método especial, que é chamado de construtor de classe ou método de inicialização que o Python chama quando você cria uma nova instância dessa classe.
-
Você declara outros métodos de classe como funções normais com a exceção de que o primeiro argumento para cada método é self . Python adiciona o self argumento para a lista para você; você não precisa incluí-lo ao chamar os métodos.
Criando objetos de instância
Para criar instâncias de uma classe, você chama a classe usando o nome da classe e passa qualquer argumento que seja __init__ método aceita.
"This would create first object of Employee class" emp1 = Employee("Zara", 2000) "This would create second object of Employee class" emp2 = Employee("Manni", 5000)
Acessando atributos
Você acessa os atributos do objeto usando o operador ponto com objeto. A variável de classe seria acessada usando o nome da classe da seguinte maneira -
emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
Agora, juntando todos os conceitos -
Demonstração ao vivo
#!/usr/bin/python class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary "This would create first object of Employee class" emp1 = Employee("Zara", 2000) "This would create second object of Employee class" emp2 = Employee("Manni", 5000) emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
Quando o código acima é executado, ele produz o seguinte resultado -
Name : Zara ,Salary: 2000 Name : Manni ,Salary: 5000 Total Employee 2
Você pode adicionar, remover ou modificar atributos de classes e objetos a qualquer momento -
emp1.age = 7 # Add an 'age' attribute. emp1.age = 8 # Modify 'age' attribute. del emp1.age # Delete 'age' attribute.
Em vez de usar as instruções normais para acessar atributos, você pode usar as seguintes funções -
-
O getattr(obj, name[, default]) − para acessar o atributo do objeto.
-
O hasattr(obj,nome) − para verificar se um atributo existe ou não.
-
O setattr(obj,nome,valor) − para definir um atributo. Se o atributo não existir, ele será criado.
-
O delattr(obj, nome) − para excluir um atributo.
hasattr(emp1, 'age') # Returns true if 'age' attribute exists getattr(emp1, 'age') # Returns value of 'age' attribute setattr(emp1, 'age', 8) # Set attribute 'age' at 8 delattr(empl, 'age') # Delete attribute 'age'
Atributos de classe incorporados
Cada classe Python continua seguindo atributos embutidos e eles podem ser acessados usando o operador ponto como qualquer outro atributo −
-
__dict__ − Dicionário contendo o namespace da classe.
-
__doc__ − Sequência de documentação da classe ou nenhuma, se indefinida.
-
__name__ − Nome da classe.
-
__módulo__ − Nome do módulo no qual a classe está definida. Este atributo é "__main__" no modo interativo.
-
__bases__ − Uma tupla possivelmente vazia contendo as classes base, na ordem de sua ocorrência na lista de classes base.
Para a classe acima, vamos tentar acessar todos esses atributos -
Demonstração ao vivo
#!/usr/bin/python class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary print "Employee.__doc__:", Employee.__doc__ print "Employee.__name__:", Employee.__name__ print "Employee.__module__:", Employee.__module__ print "Employee.__bases__:", Employee.__bases__ print "Employee.__dict__:", Employee.__dict__
Quando o código acima é executado, ele produz o seguinte resultado -
Employee.__doc__: Common base class for all employees Employee.__name__: Employee Employee.__module__: __main__ Employee.__bases__: () Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}
Destruindo objetos (coleta de lixo)
O Python exclui objetos desnecessários (tipos internos ou instâncias de classe) automaticamente para liberar espaço de memória. O processo pelo qual o Python recupera periodicamente blocos de memória que não estão mais em uso é chamado de Coleta de Lixo.
O coletor de lixo do Python é executado durante a execução do programa e é acionado quando a contagem de referência de um objeto chega a zero. A contagem de referência de um objeto muda conforme o número de aliases que apontam para ele muda.
A contagem de referência de um objeto aumenta quando ele recebe um novo nome ou é colocado em um contêiner (lista, tupla ou dicionário). A contagem de referência do objeto diminui quando ele é excluído com del , sua referência é reatribuída ou sua referência sai do escopo. Quando a contagem de referência de um objeto chega a zero, o Python a coleta automaticamente.
a = 40 # Create object <40> b = a # Increase ref. count of <40> c = [b] # Increase ref. count of <40> del a # Decrease ref. count of <40> b = 100 # Decrease ref. count of <40> c[0] = -1 # Decrease ref. count of <40>
Você normalmente não notará quando o coletor de lixo destruir uma instância órfã e recuperar seu espaço. Mas uma classe pode implementar o método especial __del__() , chamado de destruidor, que é invocado quando a instância está prestes a ser destruída. Esse método pode ser usado para limpar quaisquer recursos que não sejam de memória usados por uma instância.
Exemplo
Este destruidor __del__() imprime o nome da classe de uma instância que está prestes a ser destruída −
Demonstração ao vivo
#!/usr/bin/python class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed" pt1 = Point() pt2 = pt1 pt3 = pt1 print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts del pt1 del pt2 del pt3
Quando o código acima é executado, ele produz o seguinte resultado -
3083401324 3083401324 3083401324 Point destroyed
Observação − Idealmente, você deve definir suas classes em um arquivo separado, então você deve importá-las em seu arquivo de programa principal usando import declaração.
Herança de classe
Em vez de começar do zero, você pode criar uma classe derivando-a de uma classe preexistente listando a classe pai entre parênteses após o nome da nova classe.
A classe filha herda os atributos de sua classe pai e você pode usar esses atributos como se estivessem definidos na classe filha. Uma classe filha também pode substituir membros de dados e métodos do pai.
Sintaxe
As classes derivadas são declaradas de maneira muito semelhante à classe pai; no entanto, uma lista de classes base para herdar é fornecida após o nome da classe -
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suite
Exemplo
Demonstração ao vivo#!/usr/bin/python class Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttr class Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method' c = Child() # instance of child c.childMethod() # child calls its method c.parentMethod() # calls parent's method c.setAttr(200) # again call parent's method c.getAttr() # again call parent's method
Quando o código acima é executado, ele produz o seguinte resultado -
Calling child constructor Calling child method Calling parent method Parent attribute : 200
De maneira semelhante, você pode direcionar uma classe de várias classes pai da seguinte maneira -
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
Você pode usar as funções issubclass() ou isinstance() para verificar os relacionamentos de duas classes e instâncias.
-
A issubclass(sub, sup) A função booleana retorna true se a subclasse sub fornecida é de fato uma subclasse da superclasse sup .
-
A isinstance(obj, Class) função booleana retorna true se obj é uma instância da classe Class ou é uma instância de uma subclasse de Class
Métodos de substituição
Você sempre pode substituir seus métodos de classe pai. Uma razão para substituir os métodos do pai é porque você pode querer uma funcionalidade especial ou diferente em sua subclasse.
Exemplo
Demonstração ao vivo#!/usr/bin/python class Parent: # define parent class def myMethod(self): print 'Calling parent method' class Child(Parent): # define child class def myMethod(self): print 'Calling child method' c = Child() # instance of child c.myMethod() # child calls overridden method
Quando o código acima é executado, ele produz o seguinte resultado -
Calling child method
Métodos de sobrecarga de base
A tabela a seguir lista algumas funcionalidades genéricas que você pode substituir em suas próprias classes -
Nº Sr. | Método, descrição e amostra de chamada |
---|---|
1 | __init__ ( self [,args...] ) Construtor (com quaisquer argumentos opcionais) Chamada de exemplo:obj =className(args) |
2 | __del__( próprio ) Destruidor, exclui um objeto Chamada de amostra:del obj |
3 | __repr__( auto ) Representação de string avaliável Chamada de amostra:repr(obj) |
4 | __str__( próprio ) Representação de string para impressão Chamada de exemplo:str(obj) |
5 | __cmp__ ( self, x ) Comparação de objetos Chamada de exemplo:cmp(obj, x) |
Sobrecarregando operadores
Suponha que você tenha criado uma classe Vector para representar vetores bidimensionais, o que acontece quando você usa o operador mais para adicioná-los? Muito provavelmente Python vai gritar com você.
Você pode, no entanto, definir o __add__ método em sua classe para realizar a adição de vetores e, em seguida, o operador mais se comportaria de acordo com a expectativa -
Exemplo
Demonstração ao vivo#!/usr/bin/python class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10) v2 = Vector(5,-2) print v1 + v2
Quando o código acima é executado, ele produz o seguinte resultado -
Vector(7,8)
Ocultação de dados
Os atributos de um objeto podem ou não ser visíveis fora da definição da classe. Você precisa nomear atributos com um prefixo de sublinhado duplo e esses atributos não serão diretamente visíveis para pessoas de fora.
Exemplo
Demonstração ao vivo#!/usr/bin/python class JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCount counter = JustCounter() counter.count() counter.count() print counter.__secretCount
Quando o código acima é executado, ele produz o seguinte resultado -
1 2 Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCount AttributeError: JustCounter instance has no attribute '__secretCount'
O Python protege esses membros alterando internamente o nome para incluir o nome da classe. Você pode acessar atributos como object._className__attrName . Se você substituir sua última linha da seguinte forma, funcionará para você -
......................... print counter._JustCounter__secretCount
Quando o código acima é executado, ele produz o seguinte resultado -
1 2 2
python