Classes combinam dados com comportamento.
As classes são usadas para criar cópias ou instances de dados e comportamento agrupados, comumente conhecidos como objects.
Objetos podem representar entidades do mundo real (como carros ou gatos), ou conceitos mais abstratos (como números inteiros, veículos ou mamíferos).
As classes são parte essencial de uma abordagem de programação orientada a objetos (POO), que convida a pensar em um problema como um ou mais objetos que interagem entre si, mantêm estado e agem sobre os dados.
As classes são as definições de novos tipos de objeto, a partir das quais novas instances de objetos são criadas.
Elas costumam agrupar dados (conhecidos como fields, attributes, properties, data members ou variables) com código ou funções (conhecidas como methods) que operam sobre esses dados.
Nesse sentido, uma classe é uma planta ou um conjunto de instruções a partir do qual muitos objetos de um tipo semelhante podem ser construídos e usados.
Um programa complexo pode ter muitas classes, cada uma construindo muitos tipos diferentes de objetos.
O processo de construir e personalizar um objeto a partir de uma classe é conhecido como instantiation (ou criar uma instância da classe).
A definição de uma classe em Python é simples:
class MyClass:
# Class body goes here
Os campos de classe (também conhecidos como propriedades, atributos, membros de dados ou variáveis) podem ser adicionados ao corpo da classe.
class MyClass:
number = 5
string = "Hello!"
Uma instância (objeto) de MyClass pode ser criada e vinculada a um nome:
>>> new_object = MyClass()
# Class is instantiated and resulting object is bound to the "new_object" name (variable).
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>
Class attributes são compartilhados por todos os objetos (ou instâncias) criados a partir de uma classe e podem ser acessados por meio de dot notation, um . colocado depois do nome do objeto e antes do nome do atributo:
>>> new_object = MyClass()
# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5
# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'
# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()
>>> second_new_object
<__main__.MyClass at 0x15ad99970>
# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True
Os atributos de classe são definidos no corpo da própria classe, antes de qualquer outro método. Eles pertencem à classe, o que permite que sejam compartilhados entre as instâncias. Como esses atributos são compartilhados por todas as instâncias da classe, seu valor pode ser acessado e manipulado diretamente a partir da classe. Alterar o valor de atributos de classe altera o valor para todos os objetos instanciados a partir da classe:
>>> obj_one = MyClass()
>>> obj_two = MyClass()
# Accessing a class attribute from an object.
>>> obj_two.number
5
# Accessing the class attribute from the class itself.
>>> MyClass.number
5
# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27
# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27
>>> obj_two.number
27
Ter um monte de objetos com dados sincronizados o tempo todo não é lá muito útil.
Felizmente, objetos criados a partir de uma classe podem ser personalizados com seus próprios instance attributes (ou propriedades, variáveis ou campos de instância).
Como o nome sugere, os atributos de instância são exclusivos de cada objeto e podem ser modificados de forma independente.
__init__()
O "método dunder" (abreviação de "double underscore method") especial __init__() é usado para personalizar instâncias de classe e pode inicializar atributos ou propriedades de instância dos objetos.
Por seu papel na inicialização de atributos de instância, __init__() também é chamado de class constructor ou initializer.
__init__() recebe um parâmetro obrigatório chamado self, que se refere ao objeto recém-criado ou instanciado.
Os dados para os atributos ou propriedades de instância podem então ser passados como argumentos de __init__(), depois do parâmetro self.
Abaixo, MyClass agora tem atributos de instância chamados location_x e location_y.
Como você pode ver, os dois atributos foram atribuídos ao primeiro e ao segundo índices do argumento location (uma tupla) que foi passado para __init__().
Os atributos location_x e location_y de uma instância de classe agora serão inicializados quando você instanciar a classe e um objeto for criado:
class MyClass:
# These are class attributes, variables, or fields.
number = 5
string = "Hello!"
# This is the class "constructor", with a "location" parameter that is a tuple.
def __init__(self, location):
# This is an instance or object property, attribute, or variable.
# Note that we are unpacking the tuple argument into two separate instance variables.
self.location_x = location[0]
self.location_y = location[1]
# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))
# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))
# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1
>>> new_object_two.location_x
-8
Repare que você só precisa passar um argumento ao inicializar MyClass acima: o Python cuida de passar o self quando a classe é chamada.
Outra forma de criar uma variável de instância é simplesmente acessar uma variável de classe por meio de um objeto e mudá-la para outra coisa:
>>> obj_one = MyClass()
>>> obj_two = MyClass()
>>> MyClass.string
'Hello!'
>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'
>>> obj_one.string
'Hello!'
Agora, veja o que acontece quando a variável de classe muda:
>>> MyClass.string = "World!"
>>> obj_two.string
# obj_two.string has not changed
'Hi!'
>>> obj_one.string
# obj_one.string changed
'World!'
O atributo string agora é uma variável de instância no caso de obj_two, mas continua sendo uma variável de classe em obj_one.
Isso também pode ser feito de dentro da classe:
class Demo:
new_var = 3
def add_two(self):
self.new_var += 2
No momento em que <object>.add_two() é chamado e self.new_var += 2 é lido, new_var passa de variável de classe para variável de instância com o mesmo nome.
Isso pode ser útil durante a inicialização, quando todas as instâncias de uma classe vão precisar que certos atributos comecem com o mesmo valor.
No entanto, a variável de instância então sombreia a variável de classe, o que torna a variável de classe inacessível a partir da instância onde ela foi sombreada.
Diante disso, pode ser mais seguro e mais claro definir os atributos de instância no método __init__() como self.<attribute>.
Um method é uma function que está vinculada à própria classe (conhecido como método de classe, que será discutido em profundidade em um exercício mais adiante) ou a uma instância da classe (objeto).
Os métodos que operam sobre um objeto ou instância precisam ser definidos com self como primeiro parâmetro.
Você pode então definir o restante dos parâmetros como faria para uma função "normal" ou não vinculada.
Os métodos que operam sobre uma classe precisam ser definidos com o decorador @classmethod e (por convenção) com cls como primeiro parâmetro.
Os métodos de classe são chamados diretamente na classe, sem antes criar um objeto a partir dela.
class MyClass:
number = 5
string = "Hello!"
# Class constructor.
def __init__(self, location):
# Instance properties
self.location_x = location[0]
self.location_y = location[1]
# Class method. Uses the @classmethod decorator, and cls as the first parameter.
# Can be called without first making an instance of the class.
@classmethod
def change_string(cls, new_string):
#Class attributes are referred to with cls.
cls.string = new_string
return cls.string
# Instance method. Note "self" as first parameter.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
Assim como no acesso a atributos, chamar um método é tão simples quanto colocar um . depois do nome do objeto e antes do nome do método.
O método chamado não precisa de uma cópia do objeto como primeiro parâmetro: o Python preenche o self automaticamente:
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)
# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)
Os atributos de classe podem ser acessados de dentro de métodos de instância da mesma forma como são acessados fora da classe:
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances from within an instance.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5
>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6
pass
Nos exercícios de conceito anteriores e nos esboços dos exercícios de prática, você já deve ter visto a palavra-chave pass usada dentro do corpo de funções no lugar do código de verdade.
A palavra-chave pass é um marcador sintaticamente válido: ela impede que o Python lance um erro de sintaxe para uma função ou definição de classe vazia.
Essencialmente, é uma forma de dizer ao intérprete do Python: "Não se preocupe! Eu vou colocar código aqui em algum momento, só ainda não fiz isso."
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
# This will compile and run without error, but has no current functionality.
def pending_functionality(self):
# Stubbing or place-holding the body of this method.
pass