Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> python

Programação Orientada a Objetos em Python: Guia Completo

O Python tem sido uma linguagem orientada a objetos desde que existe. Por causa disso, criar e usar classes e objetos é extremamente 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 experiência prévia com programação orientada a objetos (OO), pode querer consultar um curso introdutório sobre isso ou pelo menos um tutorial de algum tipo para que você tenha uma noção dos conceitos básicos.

No entanto, aqui está uma pequena introdução à Programação Orientada a Objetos (POO) para colocá-lo em dia:

Visão Geral da Terminologia POO

Criando Classes

A instrução class cria uma nova definição de classe. O nome da classe segue imediatamente a palavra-chave class seguida por dois pontos:

class ClassName:
    'Optional class documentation string'
    class_suite

Exemplo

Segue 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)

Criando 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 de ponto com o objeto. 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, 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  # Adiciona um atributo 'age'.
emp1.age = 8  # Modifica atributo 'age'.
del emp1.age  # Deleta atributo 'age'.

Em vez de usar as instruções normais para acessar atributos, você pode usar as seguintes funções:

hasattr(emp1, 'age')    # Retorna true se atributo 'age' existe
getattr(emp1, 'age')    # Retorna valor do atributo 'age'
setattr(emp1, 'age', 8) # Define atributo 'age' como 8
delattr(emp1, 'age')    # Deleta atributo 'age'

Atributos de Classe Embutidos

Toda classe Python mantém os seguintes atributos embutidos e eles podem ser acessados usando o operador de ponto como qualquer outro atributo:

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, 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': , 'empCount': 2, 'displayEmployee': , '__doc__': 'Common base class for all employees', '__init__': }

Destruindo Objetos (Coleta de Lixo)

O Python deleta objetos desnecessários (tipos embutidos ou instâncias de classe) automaticamente para liberar espaço de memória. O processo pelo qual o Python periodicamente recupera 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 é acionado quando a contagem de referências de um objeto chega a zero. A contagem de referências de um objeto muda conforme o número de aliases que apontam para ele muda.

A contagem de referências de um objeto aumenta quando ele é atribuído a um novo nome ou colocado em um container (lista, tupla ou dicionário). A contagem de referências do objeto diminui quando é deletado com del, sua referência é reatribuída ou sua referência sai do escopo. Quando a contagem de referências de um objeto chega a zero, o Python o coleta automaticamente.

a = 40      # Cria objeto <40>
b = a       # Aumenta cont. de ref. de <40>
c = [b]     # Aumenta cont. de ref. de <40>
del a       # Diminui cont. de ref. de <40>
b = 100     # Diminui cont. de ref. de <40>
c[0] = -1   # Diminui cont. de ref. de <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 destrutor, que é invocado quando a instância está prestes a ser destruída. Este método pode ser usado para limpar quaisquer recursos não de memória usados por uma instância.

Exemplo

Este destrutor __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))  # imprime os ids dos objetos
del pt1
del pt2
del pt3

Quando o código acima é executado, produz o seguinte resultado:

3083401324 3083401324 3083401324
Point destroyed

Nota - Idealmente, você deve definir suas classes em arquivo separado, então deve importá-las no seu arquivo de programa principal usando a instrução import.

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 fossem definidos na classe filha. Uma classe filha também pode sobrescrever membros de dados e métodos do pai.

Sintaxe

Classes derivadas são declaradas muito parecidas com sua classe pai; no entanto, uma lista de classes base para herdar é dada 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()          # instância da child
c.childMethod()      # child chama seu método
c.parentMethod()     # chama método do parent
c.setAttr(200)       # novamente chama método do parent
c.getAttr()          # novamente chama método do parent

Quando o código acima é executado, produz o seguinte resultado:

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

De forma similar, você pode derivar uma classe de múltiplas classes pai da seguinte forma:

class A:
    # define sua classe A .....
class B:
    # define sua classe B .....
class C(A, B):
    # subclasse de A e B .....

Você pode usar as funções issubclass() ou isinstance() para verificar relações entre duas classes e instâncias.

Sobrescrevendo Métodos

Você sempre pode sobrescrever os métodos da sua classe pai. Uma razão para sobrescrever métodos do pai é porque você pode querer funcionalidade especial ou diferente na 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()          # instância da child
c.myMethod()         # child chama método sobrescrito

Quando o código acima é executado, produz o seguinte resultado:

Calling child method

Métodos de Sobrecarga Base

A tabela a seguir lista algumas funcionalidades genéricas que você pode sobrescrever em suas próprias classes:

Nº Método, Descrição e Chamada de Exemplo
1

__init__ ( self [,args...] )

Construtor (com quaisquer argumentos opcionais)

Chamada de Exemplo: obj = className(args)

2

__del__( self )

Destrutor, deleta um objeto

Chamada de Exemplo: del obj

3

__repr__( self )

Representação em string avaliável

Chamada de Exemplo: repr(obj)

4

__str__( self )

Representação em string imprimível

Chamada de Exemplo: str(obj)

5

__cmp__ ( self, x )

Comparação de objetos

Chamada de Exemplo: cmp(obj, x)

Sobrecarga de Operadores

Suponha que você criou uma classe Vector para representar vetores bidimensionais. O que acontece quando você usa o operador mais para somá-los? Muito provavelmente o Python vai reclamar.

Você poderia, no entanto, definir o método __add__ em sua classe para realizar adição de vetores e então o operador mais se comportaria como esperado:

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, 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 então não serão diretamente visíveis para outsiders.

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, produz o seguinte resultado:

1
2
Traceback (most recent call last):
  File "test.py", line 12, in 
    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 tais atributos como object._className__attrName. Se você substituir sua última linha pela seguinte, funcionará para você:

print(counter._JustCounter__secretCount)

Quando o código acima é executado, produz o seguinte resultado:

1
2
2

python

  1. Classes e Objetos em C#: Fundamentos para POO Robusta
  2. Dominando Tipos de Dados em Python: Guia Prático
  3. Dominando Operadores em Python: Guia Completo
  4. Dominando a Declaração Pass em Python: Guia Prático
  5. Dominando Dicionários em Python: Criação, Manipulação e Técnicas Avançadas
  6. Dominando Exceções Customizadas em Python: Guia Prático
  7. Dominando Programação Orientada a Objetos em Python: Classes, Herança, Encapsulamento e Polimorfismo
  8. Dominando Herança em Python: Conceitos, Sintaxe e Exemplos Práticos
  9. Padrão Singleton em Java Explicado: Como Implementar e Usar com Segurança
  10. Rastreamento Automatizado de Objetos Baseado em Visão com Raspberry Pi e OpenCV