Atributos da Classe e Métodos Estáticos em Python
Atributos de Classe
Além dos atributos específicos de cada objeto, é possível definir atributos de classe. Esses atributos são variáveis declaradas no nível do próprio classe e compartilhadas por todos os objetos dela. Por exemplo:
class Person:
type = "Person"
description = "Describes a person"
print(Person.type) # Person
print(Person.description) # Describes a person
Person.type = "Class Person"
print(Person.type) # Class Person
Neste exemplo, a classe Person
define dois atributos: type
, que armazena o nome da classe, e description
, que fornece uma descrição. Esses atributos podem ser acessados pelo nome da classe, como em Person.type
, e, assim como os atributos de objeto, podemos obter e modificar seus valores.
Esses atributos são compartilhados por todos os objetos da classe:
class Person:
type = "Person"
def __init__(self, name):
self.name = name
tom = Person("Tom")
bob = Person("Bob")
print(tom.type) # Person
print(bob.type) # Person
# Alterando o atributo de classe
Person.type = "Class Person"
print(tom.type) # Class Person
print(bob.type) # Class Person
Os atributos de classe são úteis quando queremos definir valores padrão para todos os objetos da classe. Por exemplo:
class Person:
default_name = "Undefined Name"
def __init__(self, name):
self.name = name if name else Person.default_name
tom = Person("Tom")
bob = Person("")
print(tom.name) # Tom
print(bob.name) # Undefined Name
Neste caso, o atributo default_name
guarda um nome padrão. Se o construtor receber uma string vazia como nome, o valor padrão de default_name
é atribuído a name
. Para acessar atributos de classe dentro de métodos, usamos o nome da classe, como em Person.default_name
.
Atributo de Classe e Atributo de Objeto com o Mesmo Nome
Pode ocorrer que um atributo de classe e um atributo de objeto tenham o mesmo nome. Quando o atributo do objeto não tem um valor atribuído, o valor do atributo de classe será utilizado:
class Person:
name = "Undefined Name"
def print_name(self):
print(self.name)
tom = Person()
bob = Person()
tom.print_name() # Undefined Name
bob.print_name() # Undefined Name
bob.name = "Bob"
bob.print_name() # Bob
tom.print_name() # Undefined Name
Neste exemplo, print_name
usa o atributo name
do objeto, mas como o atributo de objeto não foi definido para tom
, o valor de name
da classe é usado. Quando atribuimos um valor ao atributo name
de bob
, ele passa a utilizar seu próprio valor em vez do valor da classe.
Se o valor do atributo de classe for alterado, o atributo name
dos objetos que ainda usam o valor da classe refletirá essa mudança:
Person.name = "Some Person"
bob.name = "Bob"
bob.print_name() # Bob
tom.print_name() # Some Person
Aqui, bob
possui seu próprio valor de name
, enquanto tom
usa o valor atualizado do atributo de classe.
Métodos Estáticos
Além dos métodos comuns, uma classe também pode definir métodos estáticos. Estes são precedidos pelo decorador @staticmethod
e são associados à classe como um todo, não a objetos específicos:
class Person:
__type = "Person"
@staticmethod
def print_type():
print(Person.__type)
Person.print_type() # Person - chamado através do nome da classe
tom = Person()
tom.print_type() # Person - chamado através de um objeto
Neste exemplo, a classe Person
possui um atributo __type
, que armazena um valor comum para toda a classe. Como este atributo é precedido por dois sublinhados, ele é privado, evitando alterações não autorizadas.
O método estático print_type
exibe o valor de __type
. Como sua função não depende de objetos específicos, ele pode ser definido como estático, permitindo uma consistência ao exibir o mesmo valor para qualquer instância.