Skip to content

12. Classes e objetos

Uma classe é o modelo a partir do qual os objetos são criados. Diz-se que um objeto é uma instância de uma classe.

Image

Nota: A pasta [shared] foi colocada na pasta [Root Sources] do projeto.

12.1. script [classes_01]: uma classe Object

O script [classes_01] demonstra uma utilização obsoleta de classes:

#  a class
class Objet(object):
    """une classe Objet vide"""


#  any variable of type [Object] can have attributes by construction
obj1 = Objet()
obj1.attr1 = "un"
obj1.attr2 = 100
#  displays the
print(f"objet1=[{obj1}, {type(obj1)},{id(obj1)},{obj1.attr1},{obj1.attr2}]")
#  modify object
obj1.attr2 += 100
#  displays the
print(f"objet1=[{obj1.attr1},{obj1.attr2}]")
#  assign reference obj1 to obj2
obj2 = obj1
#  modifies the object pointed to by obj2
obj2.attr2 = 0
#  displays both objects - obj1 now points to a modified object
print(f"objet1=[{obj1.attr1},{obj1.attr2}]")
print(f"objet2=[{obj2.attr1},{obj2.attr2}]")
#  obj1 and obj2 point to the same object
print(f"objet1=[{obj1}, {id(obj1)},{obj1.attr1},{obj1.attr2}]")
print(f"objet2=[{obj2}, {id(obj2)},{obj2.attr1},{obj2.attr2}]")
print(obj1 == obj2)
#  instance type obj1
print(f"type(obj1)={type(obj1)}")
print(f"isinstance(obj1,Objet)={isinstance(obj1, Objet)}, isinstance(obj1,object)={isinstance(obj1, object)}")
#  any type is an object in Python
print(f"type(4)={type(4)}")
print(f"isinstance(4, int)={isinstance(4, int)}, isinstance(4, object)={isinstance(4, object)}")

Notas:

  • linhas 2-3: uma classe [Object] vazia;
  • Linha 2: A classe pode ser declarada de três formas:
    • class Object;
    • class Object();
    • class Object(object);
  • linha 3: outra forma de comentário. Este, precedido por três "", pode abranger várias linhas;
  • linha 7: instância da classe Object. O resultado é um endereço, conforme mostrado nas linhas 24–26;
  • linhas 8–9: inicialização direta de dois atributos do objeto;
  • linha 17: cópia de referências. As variáveis obj1 e obj2 são dois ponteiros (referências) para o mesmo objeto;
  • linha 19: modificamos o objeto apontado por [obj2]. Como [obj1] e [obj2] apontam para o mesmo objeto, as exibições dos objetos [obj1, obj2] nas linhas 21 e 22 mostrarão que o objeto apontado por [obj1] foi alterado;
  • linhas 24–26: estas linhas destinam-se a demonstrar que as variáveis [obj1] e [obj2] são iguais. A saída da linha 26 irá confirmar isto. Nesta comparação, são os endereços de [obj1] e [obj2] que são iguais;
  • Cada objeto Python é identificado por um ID único obtido através da expressão [id(object)]. As linhas 24 e 25 mostrarão que os IDs dos objetos apontados por [obj1] e [obj2] são idênticos, demonstrando assim que estas duas referências apontam para o mesmo objeto;
  • Linhas 27–29: A função [isinstance(expr, Type)] retorna o valor booleano True se a expressão [expr] for do tipo [Type]. Aqui, veremos que [obj1] é do tipo [Object], o que parece natural, mas também do tipo [object]. A classe [object] é a classe pai de todas as classes Python. Pela propriedade da herança de classes, uma classe filha F possui todas as propriedades da sua classe pai P, e a função [isinstance(instância de F, P)] retorna True;
  • linhas 30–32: mostram que o tipo [int] também é um tipo [object]. Todos os tipos Python derivam da classe [object];

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_01.py
objet1=[<__main__.Objet object at 0x0000025C3F469BB0>, <class '__main__.Objet'>,2595221838768,un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
objet1=[<__main__.Objet object at 0x0000025C3F469BB0>, 2595221838768,un,0]
objet2=[<__main__.Objet object at 0x0000025C3F469BB0>, 2595221838768,un,0]
True
type(obj1)=<class '__main__.Objet'>
isinstance(obj1,Objet)=True, isinstance(obj1,object)=True
type(4)=<class 'int'>
isinstance(4, int)=True, isinstance(4, object)=True
 
Process finished with exit code 0

12.2. Script [classes_02]: uma classe Pessoa

O script [classes_02] demonstra que os atributos de uma classe são públicos: podem ser acedidos diretamente a partir do exterior da classe. Este é outro exemplo de utilização de uma classe que não é recomendada. No entanto, incluímo-lo porque poderá ocasionalmente deparar-se com este tipo de código (o Python permite-o) e precisa de ser capaz de o compreender.

#  person class
class Personne:
    #  class attributes
    #  undeclared - can be created dynamically

    #  method
    def identité(self: object) -> str:
        #  a priori, uses non-existent attributes
        return f"[{self.prénom},{self.nom},{self.âge}]"


#  ---------------------------------- main
#  attributes are public and can be created dynamically
#  class instantiation
p = Personne()
#  direct initialization of class attributes
p.prénom = "Paul"
p.nom = "de la Hûche"
p.âge = 48
#  call a method of the
print(f"personne={p.identité()}")
#  instance type p
print(f"type(p)={type(p)}")
print(f"isinstance(Personne)={isinstance(p, Personne)}, isinstance(object)={isinstance(p, object)}")

Notas:

  • linhas 2–9: uma classe com um método;
  • linha 7: todos os métodos de uma classe devem ter o objeto self, que se refere ao objeto atual, como seu primeiro parâmetro. O método [identity] retorna uma string;
  • linha 15: instanciação de um objeto [Person];
  • linhas 16–19: mostram que os atributos do objeto podem ser criados dinamicamente (eles não existem na definição da classe);
  • linha 9: os atributos da classe são denotados pela notação [self.attribute];
  • linhas 23–24 demonstram que o objeto [p] é tanto uma instância da classe [Person] como da classe [object];

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_02.py
personne=[Paul,de la Hûche,48]
type(p)=<class '__main__.Personne'>
isinstance(Personne)=True, isinstance(object)=True
 
Process finished with exit code 0

12.3. Script [classes_03]: a classe Person com um construtor

O script [classes_03] demonstra a utilização padrão de uma classe:

#  person class
class Personne:
    #  builder - initializes three attributes
    def __init__(self: object, prénom: str, nom: str, âge: int):
        #  first name: person's first name
        #  name: person's name
        #  age: age of the person

        self.prénom = prénom
        self.nom = nom
        self.âge = âge

    #  renders class attributes in string form
    def identité(self: object) -> str:
        return f"[{self.prénom},{self.nom},{self.âge}]"


#  ---------------------------------- main
#  a Person object
p = Personne("Paul", "de la Hûche", 48)
#  method call
print(f"personne={p.identité()}")

Notas:

  • linha 4: o construtor da classe chama-se __init__. Tal como acontece com outros métodos, o seu primeiro parâmetro é self;
  • linha 20: é criado um objeto Person utilizando o construtor da classe;
  • linhas 13–15: o método [identity] devolve uma cadeia de caracteres que representa o conteúdo do objeto;
  • linha 22: exibe a identidade da pessoa;

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_03.py
personne=[Paul,de la Hûche,48]
 
Process finished with exit code 0

12.4. Script [classes_04]: métodos estáticos

Definimos a seguinte classe [Utils] (utils.py) na pasta [modules]:

Image

class Utils:
    #  static method
    @staticmethod
    def is_string_ok(string: str) -> bool:
        #  string is a string
        erreur = not isinstance(string, str)
        if not erreur:
            #  is the chain empty?
            erreur = string.strip() == ''
        #  result
        return not erreur

Notas

  • Linha 3: A anotação [@staticmethod] indica que o método marcado com ela é um método de classe, e não um método de instância. Isto é evidente pelo facto de o primeiro parâmetro do método anotado não ser a palavra-chave [self]. Portanto, o método estático não tem acesso aos atributos do objeto. Em vez de escrever:
u=Utils()
print(u.is_string_ok("abcd")

escrevemos

print(Utils.is_string_ok("abcd")

Como escrevemos [Utils.is_string_ok] acima, o método [is_string_ok] é chamado de método de classe (a classe Utils, neste caso). Para que isso aconteça, o método [Utils.is_string_ok] deve ser anotado com a palavra-chave [@staticmethod].

O método estático [Utils.is_string_ok] permite-nos verificar aqui se um dado é uma cadeia de caracteres não vazia.

O script [classes_04] utiliza a classe [Utils] da seguinte forma:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from utilitaires import Utils

print(Utils.is_string_ok("  "))
print(Utils.is_string_ok(47))
print(Utils.is_string_ok(" q "))
  • Linhas 1-4: Utilizamos um script de configuração;

O script de configuração [config.py] é o seguinte:

def configure():
    import os

    #  configuration file folder
    script_dir = os.path.dirname(os.path.abspath(__file__))

    #  absolute paths of folders to put in the syspath
    absolute_dependencies = [
        f"{script_dir}/shared",
        "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages",
        "C:/myprograms/Python38/lib",
        "C:/myprograms/Python38/DLLs"
    ]

    #  update syspath
    from myutils import set_syspath
    set_syspath(absolute_dependencies)

    #  return the config
    return {}
  • Linha 9: A pasta [shared] será adicionada ao Python Path;

O resultado da execução é o seguinte:

1
2
3
4
5
6
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_04.py
False
False
True

Process finished with exit code 0

12.5. Script [classes_05]: Verificações de validade de atributos

O script [classes_05] apresenta novos conceitos:

  • definição de um tipo de exceção personalizado;
  • definição do método [_str_], que é o método de identidade padrão para classes;
  • definição de propriedades;
#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from utilitaires import Utils


#  a proprietary exception class derived from [BaseException]
class MyException(BaseException):
    #  do nothing: empty classroom
    pass


#  person class
class Personne:
    #  manufacturer
    def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0):
        #  first name: person's first name
        #  name: person's name
        #  age: age of the person

        #  parameter storage
        #  initializations will be made via setters
        self.prénom = prénom
        self.nom = nom
        self.âge = âge

    #  method toString of class
    def __str__(self: object) -> str:
        return f"[{self.__prénom},{self.__nom},{self.__âge}]"

    #  getters
    @property
    def prénom(self) -> str:
        return self.__prénom

    @property
    def nom(self) -> str:
        return self.__nom

    @property
    def âge(self) -> int:
        return self.__âge

    #  setters
    @prénom.setter
    def prénom(self, prénom: str):
        #  first name must be non-empty
        if Utils.is_string_ok(prénom):
            self.__prénom = prénom.strip()
        else:
            raise MyException("Le prénom doit être une chaîne de caractères non vide")

    @nom.setter
    def nom(self, nom: str):
        #  first name must be non-empty
        if Utils.is_string_ok(nom):
            self.__nom = nom.strip()
        else:
            raise MyException("Le nom doit être une chaîne de caractères non vide")

    @âge.setter
    def âge(self, âge: int):
        #  age must be an integer >=0
        erreur = False
        if isinstance(âge, int):
            if âge >= 0:
                self.__âge = âge
            else:
                erreur = True
        else:
            erreur = True
        #  mistake?
        if erreur:
            raise MyException("L'âge doit être un entier >=0")


#  ---------------------------------- main
#  a Person object
try:
    #  instantiation Person class
    p = Personne("Paul", "de la Hûche", 48)
    #  object display p
    print(f"personne={p}")
except MyException as erreur:
    #  error display
    print(erreur)

#  another object Nobody
try:
    #  instantiation Person class
    p = Personne("xx", "yy", "zz")
    #  object display p
    print(f"personne={p}")
except MyException as erreur:
    #  error display
    print(erreur)

#  another person without parameters this time
try:
    #  instantiation Person class
    p = Personne()
    #  object display p
    print(f"personne={p}")
except MyException as erreur:
    #  error msg display
    print(erreur)

#  you cannot access the __attr private attributes of the
p.__prénom = "Gaëlle"
print(f"p.prénom={p.prénom}")
print(f"p.__prénom={p.__prénom}")
p.prénom = "Sébastien"
print(f"p.prénom={p.prénom}")
print(f"p.__prénom={p.__prénom}")

Notas:

  • linhas 10–13: uma classe MyException derivada da classe BaseException (abordaremos este ponto um pouco mais adiante). Ela não adiciona nenhuma funcionalidade à última. Está lá apenas para fornecer uma exceção personalizada;
  • linha 19: o construtor tem valores por defeito para os seus parâmetros. Assim, a operação p = Person() é equivalente a p = Person("x", "y", 0);
  • linhas 34–45: as propriedades da classe. São métodos anotados com a palavra-chave [@property]. São utilizados para definir os valores dos atributos;
  • linhas 47–77: os setters da classe. São métodos anotados com a palavra-chave [@attributsetter]. São utilizados para definir o valor dos atributos;
  • linhas 48–54: o setter para o atributo [first_name]. Este método será chamado sempre que um valor for atribuído ao atributo [first_name]:
p=Personne(…)
p.prénom=valeur

A linha 2 irá acionar a chamada [p.firstName(value)]. A vantagem de utilizar um setter para atribuir um valor a um atributo é que, uma vez que o setter é uma função, podemos verificar a validade do valor atribuído ao atributo;

  • linha 51: verificamos se o valor atribuído ao atributo [first_name] é uma cadeia de caracteres não vazia. Para tal, utilizamos o método estático [Utils.isStringOk] mencionado anteriormente;
  • linha 52: o valor atribuído ao atributo [first_name] é despojado dos espaços em branco à esquerda e à direita e atribuído ao atributo [self.__first_name]. Portanto, o próprio atributo [first_name] não é utilizado aqui. Não poderíamos ter feito de outra forma, ou teríamos uma chamada recursiva infinita. Poderíamos ter usado qualquer nome de atributo. O facto de termos usado o atributo [__prénom] com dois sublinhados no início do identificador tem um significado especial: os atributos precedidos por dois sublinhados são privados da classe. Isto significa que não são visíveis a partir do exterior da classe. Portanto, não podemos escrever:
p=Personne(…)
p.__prénom=valeur

Na verdade, veremos em breve que é possível escrever isso, mas não altera o primeiro nome. Faz outra coisa;

  • linhas 53–54: se o valor atribuído a first_name estiver incorreto, é lançada uma exceção. Desta forma, o código de chamada saberá que a sua chamada está incorreta;
  • linhas 35–37: a propriedade [first_name]. Será chamada sempre que [p.first_name] for escrito numa expressão. O método [p.first_name()] será então chamado. Linha 37: Devolvemos o valor do atributo [__first_name], uma vez que vimos que o setter do atributo [first_name] atribui o seu valor ao atributo privado [__first_name];
  • Linhas 56–62: O setter do atributo [last_name] é construído de forma semelhante ao do atributo [first_name]. O mesmo se aplica ao setter do atributo [age] nas linhas 64–77;
  • embora as propriedades [first_name, last_name, value] não sejam os atributos reais — que são, na verdade, [__first_name, __last_name, __age] — continuaremos a referir-nos a elas como os atributos da classe, uma vez que são utilizadas como tal;
  • linhas 19–28: O construtor da classe utiliza implicitamente os setters para os atributos [first_name, last_name, age]. De facto, ao escrever [self.first_name = first_name] na linha 26, o método [first_name(self, first_name)] é implicitamente chamado. A validade do parâmetro [first_name] será então verificada. O mesmo se aplica aos outros dois atributos [last_name, age];
  • com este modelo, não podemos atribuir valores incorretos aos atributos da classe [first_name, last_name, age];
  • linhas 30–32: a função __str__ substitui o método anteriormente chamado identity. O nome [__str__] (dois sublinhados antes e depois) não é insignificante. Veremos isso mais tarde;
  • linhas 83–86: instanciação de uma pessoa, seguida da exibição da sua identidade;
  • linha 84: instanciação;
  • Linha 86: Exibição. A operação requer a exibição do objeto p como uma string. O interpretador Python chama automaticamente o método p.__str__() se este existir. Este método tem a mesma finalidade que o método toString() nas linguagens Java ou .NET;
  • linhas 87–89: tratamento de uma potencial MyException. Em seguida, exibe o erro;
  • linhas 91–99: igual ao anterior para uma segunda pessoa instanciada com parâmetros incorretos;
  • linhas 102–109: igual ao anterior para uma terceira pessoa instanciada com parâmetros padrão: não são passados parâmetros. Os valores padrão destes parâmetros no construtor são então utilizados aqui;
  • linhas 112–117: dissemos que o atributo [__first_name] era privado e, portanto, normalmente inacessível de fora da classe. Queremos verificar isso;
  • linhas 112–114: atribuímos um valor ao atributo [__first_name] e, em seguida, verificamos os valores dos atributos [__first_name] e [first_name], que normalmente deveriam ser iguais;
  • linhas 115–117: Repetimos a operação, desta vez inicializando o atributo [first_name];

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_05.py
personne=[Paul,de la Hûche,48]
L'âge doit être un entier >=0
personne=[x,y,0]
p.prénom=x
p.__prénom=Gaëlle
p.prénom=Sébastien
p.__prénom=Gaëlle
 
Process finished with exit code 0

Notas

  • linhas 5-6: vemos que a atribuição [p.__first_name = "Gaëlle"] não alterou o valor do atributo [first_name], linha 5;
  • linhas 7-8: vemos que a atribuição [p.first_name = "Sébastien"] não alterou o valor do atributo [__first_name], linha 8;

O que podemos concluir disto? Que, provavelmente, a operação [p.__first_name = "Gaëlle"] criou um atributo público [__first_name] para a classe, mas que este é diferente do atributo privado [__first_name] manipulado no seu interior;

12.6. Script [classes_06]: Adicionar um método de inicialização de objeto

O script [classes_06] adiciona um método à classe [Person]:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from utilitaires import Utils


#  a proprietary exception class derived from [BaseException]
class MyException(BaseException):
    #  do nothing: empty classroom
    pass


#  person class
class Personne:
    #  manufacturer
    def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0):
        #  first name: person's first name
        #  name: person's name
        #  age: age of the person

        #  parameter storage
        #  initializations will be made via setters
        self.prénom = prénom
        self.nom = nom
        self.âge = âge

    #  other initialization method
    def init_with_personne(self: object, p: object):
        #  initializes the current object with a person p
        self.__init__(p.prénom, p.nom, p.âge)

    #  method toString of class
    def __str__(self: object) -> str:
        return f"[{self.__prénom},{self.__nom},{self.__âge}]"

    #  getters
    

    #  setters
    


#  ---------------------------------- main
#  a Person object
try:
    #  instantiation Person class
    p = Personne("Paul", "de la Hûche", 48)
    #  object display p
    print(f"personne={p}")
except MyException as erreur:
    #  error msg display
    print(erreur)

#  another object Nobody
try:
    #  instantiation Person class
    p = Personne("xx", "yy", "zz")
    #  object display p
    print(f"p={p}")
except MyException as erreur:
    #  error msg display
    print(erreur)

#  another person without parameters this time
try:
    #  instantiation Person class
    p = Personne()
    #  object display p
    print(f"p={p}")
except MyException as erreur:
    #  error msg display
    print(erreur)

#  another Person obtained by recopying
try:
    #  instantiation Person class
    p2 = Personne()
    p2.init_with_personne(p)
    #  object display p2
    print(f"p2={p2}")
except MyException as erreur:
    #  error msg display
    print(erreur)

Notas:

  • A diferença em relação ao script anterior está nas linhas 30–33. Adicionámos o método initWithPerson. Este método chama o construtor __init__. Ao contrário das linguagens tipadas, não é possível ter métodos com o mesmo nome que se distingam pela natureza dos seus parâmetros ou pelos seus valores de retorno. Portanto, não é possível ter múltiplos construtores que criariam o objeto a partir de parâmetros diferentes, neste caso um objeto do tipo Pessoa;

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_06.py
personne=[Paul,de la Hûche,48]
L'âge doit être un entier >=0
p=[x,y,0]
p2=[x,y,0]
 
Process finished with exit code 0

12.7. Script [classes_07]: uma lista de objetos Person

Vamos agora colocar as classes [MyException] e [Person] num módulo para que possamos utilizá-las sem ter de copiar o seu código:

Image

Ambas as classes estarão no módulo [myclasses.py] acima.

O script [classes_07] mostra que podemos ter uma lista de objetos:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from myclasses import Personne

#  ---------------------------------- main
#  create a list of person objects
groupe = [Personne("Paul", "Langevin", 48), Personne("Sylvie", "Lefur", 70)]
#  identity of these persons
for i in range(len(groupe)):
    print(f"groupe[{i}]={groupe[i]}")

Notas:

  • linha 7: importamos a classe [Person];
  • linha 11: uma lista de objetos do tipo [Person];
  • linhas 13–14: percorremos esta lista para apresentar cada um dos seus elementos;
  • linha 14: a função [print] irá exibir a cadeia de caracteres que representa o objeto [group[i]]. Por predefinição, será chamado o método [__str__] destes objetos;

Resultados


C:\Users\serge\.virtualenvs\cours-python-v02\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/v-02/classes/01/classes_07.py
groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]
 
Process finished with exit code 0

12.8. Script [classes_08]: criação de uma classe derivada da classe Pessoa

Definimos a seguinte classe [Teacher] no módulo [myclasses]:


# classe Enseignant
class Enseignant(Personne):
    # constructeur
    def __init__(self, prénom: str = "x", nom: str = "x", âge: int = 0, discipline: str = "x"):
        # prénom : prénom de la personne
        # nom : nom de la personne
        # âge : âge de la personne
        # discipline : discpline enseignée
 
        # initialisation du parent
        Personne.__init__(self, prénom, nom, âge)
        # autres initialisations
        self.discipline = discipline
 
    # toString
    def __str__(self) -> str:
        return f"enseignant[{super().__str__()},{self.discipline}]"
 
    # propriétés
    @property
    def discipline(self) -> str:
        return self.__discipline
 
    @discipline.setter
    def discipline(self, discipline: str):
        # la discipline doit être une chaîne non vide
        if Utils.is_string_ok(discipline):
            self.__discipline = discipline
        else:
            raise MyException("La discipline doit être une chaîne de caractères non vide")
  • Linha 2: declara a classe Teacher como uma subclasse da classe Person. Uma subclasse possui todas as propriedades (atributos e métodos) da sua classe pai, além das suas próprias;
  • linha 13: a classe [Teacher] define um novo atributo [subject];
  • linha 11: o construtor da classe derivada Teacher deve chamar o construtor da classe pai Person, passando-lhe os parâmetros que esta espera;
  • linha 17: a função [super()] chama a classe pai. Aqui, chamamos a função [__str__] da classe pai;
  • linhas 19–30: são definidos os getter e setter para o novo atributo [subject];

O script [classes_08] utiliza a classe [Teacher] da seguinte forma:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from myclasses import Personne, Enseignant

#  ---------------------------------- main
#  creation of an array of Personne and derived objects
groupe = [Enseignant("Paul", "Langevin", 48, "anglais"), Personne("Sylvie", "Lefur", 70)]
#  identity of these persons
for i in range(len(groupe)):
    print(f"groupe[{i}]={groupe[i]}")

Notas:

  • linha 7: importamos as classes [Person] e [Teacher] definidas no ficheiro [myclasses.py];
  • linhas 11–14: definimos um grupo de pessoas e, em seguida, exibimos as suas identidades;

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_08.py
groupe[0]=enseignant[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
 
Process finished with exit code 0

12.9. Script [classes_09]: segunda classe derivada da classe Pessoa

O script [classes_09] apresenta a classe [Student] derivada da classe [Person]. Esta é definida da seguinte forma no módulo [myclasses]:


# classe Etudiant
class Etudiant(Personne):
    # constructeur
    def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0, formation: str = "x"):
        Personne.__init__(self, prénom, nom, âge)
        self.formation = formation
 
    # toString
    def __str__(self: object) -> str:
        return f"étudiant[{super().__str__()},{self.formation}]"
 
    # propriétés
    @property
    def formation(self) -> str:
        return self.__formation
 
    @formation.setter
    def formation(self, formation: str):
        # la formation doit être une chaîne non vide
        if Utils.is_string_ok(formation):
            self.__formation = formation
        else:
            raise MyException("La formation doit être une chaîne de caractères non vide")

O script [classes_09] utiliza a classe [Student] da seguinte forma:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from myclasses import Personne, Enseignant, Etudiant

#  ---------------------------------- main
#  creation of an array of Personne and derived objects
groupe = [Enseignant("Paul", "Langevin", 48, "anglais"), Personne("Sylvie", "Lefur", 70),
          Etudiant("Steve", "Boer", 22, "iup2 qualité")]
#  identity of these persons
for personne in groupe:
    #  person display
    print(personne)

Notas:

  • Este script é semelhante ao anterior.

Resultados


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_09.py
enseignant[[Paul,Langevin,48],anglais]
[Sylvie,Lefur,70]
étudiant[[Steve,Boer,22],iup2 qualité]
 
Process finished with exit code 0

12.10. Script [classes_10]: a propriedade [__dict__]

O script [classes_10] apresenta a propriedade [__dict__], que utilizaremos frequentemente mais adiante:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from myclasses import Etudiant

#  ---------------------------------- main
#  student creation
étudiant=Etudiant("Steve", "Boer", 22, "iup2 qualité")
#  property dictionary
print(étudiant.__dict__)

Comentários

  • linhas 1-4: a aplicação é configurada;
  • linha 7: a classe [Student] é importada;
  • linha 11: instanciação de um aluno;
  • linha 13: utilização do método predefinido [__dict__] (dois sublinhados antes e depois do identificador);

Os resultados são os seguintes:

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_10.py
{'_Personne__prénom': 'Steve', '_Personne__nom': 'Boer', '_Personne__âge': 22, '_Etudiant__formation': 'iup2 qualité'}

Process finished with exit code 0
  • Na linha 2, obtemos um dicionário cujas chaves são as propriedades do objeto, precedidas pelo nome da classe a que pertencem. Utilizaremos este dicionário para criar uma ponte entre o objeto e o dicionário;