Python - Orientado a Objetos
Python tem sido uma linguagem orientada a objetos desde que existiu. Por causa disso, criar e usar classes e objetos são extremamente fáceis. 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), pode consultar um curso introdutório sobre ela 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 de Programação Orientada a Objetos (OOP) para trazê-lo em velocidade -
Visão geral da terminologia OOP
Class- 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.
Class variable- Uma variável que é compartilhada por todas as instâncias de uma classe. Variáveis de classe são definidas dentro de uma classe, mas fora de qualquer um dos métodos da classe. Variáveis de classe não são usadas com tanta frequência quanto as variáveis de instância.
Data member - Uma variável de classe ou variável de instância que contém dados associados a uma classe e seus objetos.
Function overloading- A atribuição de mais de um comportamento a uma função específica. A operação executada varia de acordo com os tipos de objetos ou argumentos envolvidos.
Instance variable - Uma variável que é definida dentro de um método e pertence apenas à instância atual de uma classe.
Inheritance - A transferência das características de uma classe para outras classes que dela derivam.
Instance- Um objeto individual de uma determinada classe. Um objeto obj que pertence a uma classe Circle, por exemplo, é uma instância da classe Circle.
Instantiation - A criação de uma instância de uma classe.
Method - Um tipo especial de função que é definido em uma definição de classe.
Object- Uma instância única de uma estrutura de dados definida por sua classe. Um objeto compreende membros de dados (variáveis de classe e variáveis de instância) e métodos.
Operator overloading - A atribuição de mais de uma função a um determinado operador.
Criação de classes
A instrução de classe cria uma nova definição de classe. O nome da classe segue imediatamente a palavra-chave class seguida por dois pontos da seguinte forma -
class ClassName:
'Optional class documentation string'
class_suite
A classe tem uma string de documentação, que pode ser acessada via ClassName .__ doc__ .
O class_suite consiste em todas as instruções do componente que definem os membros da 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 ou 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 argumento self à lista para você; você não precisa incluí-lo ao chamar os métodos.
Criação de objetos de instância
Para criar instâncias de uma classe, você chama a classe usando o nome da classe e passa quaisquer argumentos que seu método __init__ aceite.
"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 forma -
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
Agora, juntando todos os conceitos -
#!/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,name) - para verificar se um atributo existe ou não.
o setattr(obj,name,value)- para definir um atributo. Se o atributo não existir, ele será criado.
o delattr(obj, name) - 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 integrados
Cada classe Python segue 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__ - String de documentação de classe ou nenhum, se indefinido.
__name__ - Nome da classe.
__module__- Nome do módulo no qual a classe é 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 -
#!/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 é denominado Coleta de Lixo.
O coletor de lixo do Python é executado durante a execução do programa e é disparado 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>
Normalmente, você não notará quando o coletor de lixo destrói uma instância órfã e recupera seu espaço. Mas uma classe pode implementar o método especial __del __ () , chamado de destruidor, que é invocado quando a instância está para ser destruída. Este 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 -
#!/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
Note- Idealmente, você deve definir suas classes em um arquivo separado, então você deve importá-los em seu arquivo de programa principal usando a instrução de importação .
Herança de classe
Em vez de começar do zero, você pode criar uma classe derivando-a de uma classe pré-existente listando a classe pai entre parênteses após o novo nome da 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
#!/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 conduzir 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.
o issubclass(sub, sup) a função booleana retorna verdadeiro se a subclasse fornecida sub é de fato uma subclasse da superclasse sup.
o isinstance(obj, Class)a função booleana retorna verdadeiro se obj for 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 sobrescrever os métodos parent é porque você pode desejar uma funcionalidade especial ou diferente em sua subclasse.
Exemplo
#!/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 -
Sr. Não. | Método, descrição e chamada de amostra |
---|---|
1 | __init__ ( self [,args...] ) Construtor (com quaisquer argumentos opcionais) Chamada de exemplo: obj = className (args) |
2 | __del__( self ) Destruidor, apaga um objeto Amostra de chamada: del obj |
3 | __repr__( self ) Representação de string avaliável Chamada de amostra: repr (obj) |
4 | __str__( self ) Representação de string para impressão Amostra de chamada: str (obj) |
5 | __cmp__ ( self, x ) Comparação de objetos Chamada de amostra: cmp (obj, x) |
Operadores de sobrecarga
Suponha que você tenha criado uma classe Vector para representar vetores bidimensionais, o que acontece quando você usa o operador mais para adicioná-los? O mais provável é que Python grite com você.
Você poderia, no entanto, definir o método __add__ em sua classe para realizar a adição de vetores e, em seguida, o operador mais se comportaria de acordo com a expectativa -
Exemplo
#!/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 os atributos com um prefixo de sublinhado duplo, e esses atributos não ficarão diretamente visíveis para os de fora.
Exemplo
#!/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'
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 como a seguir, isso funcionará para você -
.........................
print counter._JustCounter__secretCount
Quando o código acima é executado, ele produz o seguinte resultado -
1
2
2