Home >Backend Development >Python Tutorial >OOP Concepts in Python for C Programmers 98

OOP Concepts in Python for C Programmers 98

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-11-16 15:50:03466browse

Conceitos de POO em Python para Programadores C  98

Here is a comprehensive demonstration of OOP concepts in Python for a C 98 programmer:

Class Definition and Object Creation

Python

# Privado por convenção: _underscore_simples
# "Realmente privado": __underscore_duplo (name mangling)
# Público: sem underscore

from abc import abstractmethod
class Animal(ABC):
    # Em python, variáveis declaradas no escopo da classe e não dentro de um
    # método específico, são automaticamente compartilhadas por todas instâncias.
    species_count = 0 # além disso, elas podem ser inicializadas diretamente dentro da classe.

    # Construtor
    def __init__(self, name):
        # Variáveis de instância
        self.name = name       # público
        self._age = 0          # protegido por convenção
        self.__id = id(self)   # privado (mas você consegue acessar com name mangling)
        Animal.species_count += 1

    # Destrutor
    def __del__(self):
        Animal.species_count -= 1

    # Método regular
    @abstractmethod
    def make_sound(self):
        pass  # Equivalente a um método abstrato/virtual (deve ser implementado apenas nas classes filhas)

    # Método estático (não precisa da instância para ser utilizado, nem utiliza seus atributos)
    @staticmethod
    def get_kingdom():
        return "Animalia"

    # Método de classe (recebe a classe como primeiro argumento, pode acessar atributos da classe)
    @classmethod
    def get_species_count(cls):
        return cls.species_count

    # Decorador de propriedade (getter)
    @property
    def age(self):
        return self._age

    # Decorador de propriedade (setter)
    @age.setter
    def age(self, value):
        if value >= 0:
            self._age = value

    # Métodos especiais (sobrecarga de operadores)
    def __str__(self):                # Como toString() - para string legível
        return f"Animal named {self.name}"

    def __repr__(self):               # Para debugging
        return f"Animal(name='{self.name}')"

    def __eq__(self, other):          # Operador de comparação ==
        return isinstance(other, Animal) and self.name == other.name

    def __len__(self):                # Função len()
        return self._age

    def __getitem__(self, key):       # Operador de acesso []
        if key == 'name':
            return self.name
        raise KeyError(key)

C 98

#include <iostream>
#include <string>
#include <sstream>

class Animal {
public:
    static int species_count;

    Animal(const std::string& name) : name(name), _age(0), __id(++id_counter) { // construtor
        ++species_count;
    }

    ~Animal() {    // destrutor
        --species_count;
    }

    virtual void make_sound() = 0; // Método não implementável na classe base (virtual/abstrato)

    static std::string get_kingdom() {  // Não existe distinção entre
    //  @classmethod e @staticmethod em cpp, apenas static methods.
        return "Animalia";
    }

    // static methods podem ser utilizados sem instanciar uma classe e têm
    // acesso às propriedades estáticas da classe:
    static int get_species_count() {
        return species_count;
    }

    // getter:
    int get_age() const {
        return _age;
    }

    // setter:
    void set_age(int age) {
        if (age >= 0) {
            _age = age;
        }
    }

    // Implementação dos métodos especiais que vimos em python:
    std::string to_string() const {
        return "Animal named " + name;
    }

    std::string repr() const {
        std::ostringstream oss;
        oss << "Animal(name='" << name << "', age=" << _age << ",>



<h2>
  
  
  Herança
</h2>

<h3>
  
  
  Python
</h3>



<pre class="brush:php;toolbar:false">class Dog(Animal):
    def __init__(self, name, breed):
        # Chama o construtor da classe pai
        super().__init__(name)
        self.breed = breed

    # Sobrescreve o método da classe pai
    def make_sound(self):
        return "Woof!"

C 98

class Dog : public Animal {
public:
    Dog(const std::string& name, const std::string& breed) : Animal(name), breed(breed) {}

    void make_sound() override {
        std::cout << "Woof!" << std::endl;
    }

private:
    std::string breed;
};

Multiple Inheritance

Python

class Pet:
    def is_vaccinated(self):
        return True

class DomesticDog(Dog, Pet):
    pass

C 98

class Pet {
public:
    bool is_vaccinated() const {
        return true;
    }
};

class DomesticDog : public Dog, public Pet {
public:
    DomesticDog(const std::string& name, const std::string& breed) : Dog(name, breed) {}
};

Abstract Class

Python

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

C 98

class Shape {
public:
    virtual ~Shape() {}
    virtual double area() const = 0;
};

Usage Example

Python

if __name__ == "__main__":
    # Cria objetos
    dog = Dog("Rex", "Golden Retriever")

    # Acessa atributos
    print(dog.name)          # Público
    print(dog._age)         # Protegido (ainda acessível)
    # print(dog.__id)       # Isso falhará 
    print(dog._Animal__id)  # Isso funciona (acessando attribute privado com name mangling)

    # Propriedades
    dog.age = 5             # Usa setter automaticamente
    print(dog.age)          # Usa getter automaticamente

    # Métodos estáticos e de classe
    print(Animal.get_kingdom())
    print(Animal.get_species_count())

    # Verifica herança
    print(isinstance(dog, Animal))  # True
    print(issubclass(Dog, Animal)) # True

    # Métodos especiais em ação
    print(str(dog))        # Usa __str__
    print(repr(dog))       # Usa __repr__
    print(len(dog))        # Usa __len__
    print(dog['name'])     # Usa __getitem__

C 98

int main() {
    // Cria objetos
    Dog dog("Rex", "Golden Retriever");

    // Acessa atributos
    std::cout << dog.name << std::endl;          // Público
    std::cout << dog.get_age() << std::endl;     // Protegido (ainda acessível)
    // std::cout << dog.__id << std::endl;       // Isso falhará (privado)

    // Propriedades
    dog.set_age(5);             // Usa setter
    std::cout << dog.get_age() << std::endl;     // Usa getter

    // Métodos estáticos e de classe
    std::cout << Animal::get_kingdom() << std::endl;
    std::cout << Animal::get_species_count() << std::endl;

    // Equivalente aos "métodos especiais":

    // Verifica herança
    if (dog.isinstance<Animal>()) {
        std::cout << "dog é uma instância de Animal" << std::endl;
    }

    std::cout << dog.to_string() << std::endl;   // Usa to_string
    std::cout << dog.repr() << std::endl;        // Usa repr
    std::cout << dog["name"] << std::endl;       // Usa operador []
}

Key Differences between Python and C 98

  1. No public/private/protected keywords (use naming conventions)
  2. Multiple inheritance differs:
    • Python uses Method Resolution Order (MRO) with C3 linearization
    • No need for virtual inheritance like in C
    • super() automatically follows the MRO
    • The order of base classes matters in Python
    • You can inspect the resolution order with __mro__
  3. All methods are virtual by default
  4. There is no distinction between pointers/references
  5. No need for memory management (garbage collector)
  6. Dynamic typing instead of static typing
  7. Property decorators instead of getter/setter methods
  8. Special methods use the __name__ format instead of the operator
  9. keyword
  10. More Pythonic syntax for operator overloading (e.g. __eq__ vs operator==)

Use dir(object) to see all of an object's attributes and methods, and help(object) for documentation.

Special Topics:

Diamond Inheritance Problem

                              Animal

                           .    '    ,
                             _______
                        _  .`_|___|_`.  _
                    Pet     \ \   / /     WorkingAnimal
                             \ ' ' /
                              \ " /   
                               \./

                           DomesticDog

Problems with Diamond Inheritance in C 98

Diamond inheritance occurs when a class inherits from two classes that, in turn, inherit from a common base class. This can cause several problems:

  1. Ambiguity: Methods and attributes of the common base class can become ambiguous.
  2. Data Duplication: Each derived class can have its own copy of the members of the common base class, leading to data duplication.

Example of Diamond Inheritance in C 98

class Animal {
public:
    Animal() {
        std::cout << "Animal constructor" << std::endl;
    }
    virtual void make_sound() {
        std::cout << "Some generic animal sound" << std::endl;
    }
};

class Pet : public Animal {
public:
    Pet() : Animal() {
        std::cout << "Pet constructor" << std::endl;
    }
    void make_sound() override {
        std::cout << "Pet sound" << std::endl;
    }
};

class WorkingAnimal : public Animal {
public:
    WorkingAnimal() : Animal() {
        std::cout << "WorkingAnimal constructor" << std::endl;
    }
    void make_sound() override {
        std::cout << "Working animal sound" << std::endl;
    }
};

class DomesticDog : public Pet, public WorkingAnimal {
public:
    DomesticDog() : Animal(), Pet(), WorkingAnimal() {
        std::cout << "DomesticDog constructor" << std::endl;
    }
    void make_sound() override {
        Pet::make_sound();  // Ou WorkingAnimal::make_sound(), dependendo do comportamento desejado
    }
};

int main() {
    DomesticDog dog;
    dog.make_sound();
    return 0;
}

Expected Behavior

Animal constructor
Pet constructor
WorkingAnimal constructor
DomesticDog constructor
Pet sound

In this example, DomesticDog inherits from Pet and WorkingAnimal, both of which inherit from Animal. This creates an heirloom diamond. Virtual inheritance is used to avoid data duplication and ambiguity.

How Python Automatically Prevents Diamond Inheritance

Python uses Method Resolution Order (MRO) with C3 linearization to automatically solve diamond inheritance problems. MRO determines the order in which classes are checked when looking for a method or attribute.

Diamond Inheritance Example in Python

# Privado por convenção: _underscore_simples
# "Realmente privado": __underscore_duplo (name mangling)
# Público: sem underscore

from abc import abstractmethod
class Animal(ABC):
    # Em python, variáveis declaradas no escopo da classe e não dentro de um
    # método específico, são automaticamente compartilhadas por todas instâncias.
    species_count = 0 # além disso, elas podem ser inicializadas diretamente dentro da classe.

    # Construtor
    def __init__(self, name):
        # Variáveis de instância
        self.name = name       # público
        self._age = 0          # protegido por convenção
        self.__id = id(self)   # privado (mas você consegue acessar com name mangling)
        Animal.species_count += 1

    # Destrutor
    def __del__(self):
        Animal.species_count -= 1

    # Método regular
    @abstractmethod
    def make_sound(self):
        pass  # Equivalente a um método abstrato/virtual (deve ser implementado apenas nas classes filhas)

    # Método estático (não precisa da instância para ser utilizado, nem utiliza seus atributos)
    @staticmethod
    def get_kingdom():
        return "Animalia"

    # Método de classe (recebe a classe como primeiro argumento, pode acessar atributos da classe)
    @classmethod
    def get_species_count(cls):
        return cls.species_count

    # Decorador de propriedade (getter)
    @property
    def age(self):
        return self._age

    # Decorador de propriedade (setter)
    @age.setter
    def age(self, value):
        if value >= 0:
            self._age = value

    # Métodos especiais (sobrecarga de operadores)
    def __str__(self):                # Como toString() - para string legível
        return f"Animal named {self.name}"

    def __repr__(self):               # Para debugging
        return f"Animal(name='{self.name}')"

    def __eq__(self, other):          # Operador de comparação ==
        return isinstance(other, Animal) and self.name == other.name

    def __len__(self):                # Função len()
        return self._age

    def __getitem__(self, key):       # Operador de acesso []
        if key == 'name':
            return self.name
        raise KeyError(key)

Expected Behavior

#include <iostream>
#include <string>
#include <sstream>

class Animal {
public:
    static int species_count;

    Animal(const std::string& name) : name(name), _age(0), __id(++id_counter) { // construtor
        ++species_count;
    }

    ~Animal() {    // destrutor
        --species_count;
    }

    virtual void make_sound() = 0; // Método não implementável na classe base (virtual/abstrato)

    static std::string get_kingdom() {  // Não existe distinção entre
    //  @classmethod e @staticmethod em cpp, apenas static methods.
        return "Animalia";
    }

    // static methods podem ser utilizados sem instanciar uma classe e têm
    // acesso às propriedades estáticas da classe:
    static int get_species_count() {
        return species_count;
    }

    // getter:
    int get_age() const {
        return _age;
    }

    // setter:
    void set_age(int age) {
        if (age >= 0) {
            _age = age;
        }
    }

    // Implementação dos métodos especiais que vimos em python:
    std::string to_string() const {
        return "Animal named " + name;
    }

    std::string repr() const {
        std::ostringstream oss;
        oss << "Animal(name='" << name << "', age=" << _age << ",>



<h2>
  
  
  Herança
</h2>

<h3>
  
  
  Python
</h3>



<pre class="brush:php;toolbar:false">class Dog(Animal):
    def __init__(self, name, breed):
        # Chama o construtor da classe pai
        super().__init__(name)
        self.breed = breed

    # Sobrescreve o método da classe pai
    def make_sound(self):
        return "Woof!"

In this example, Python automatically resolves diamond inheritance using MRO. You can check MRO using the __mro__:
attribute

class Dog : public Animal {
public:
    Dog(const std::string& name, const std::string& breed) : Animal(name), breed(breed) {}

    void make_sound() override {
        std::cout << "Woof!" << std::endl;
    }

private:
    std::string breed;
};

MRO in Python ensures that DomesticDog correctly inherits from Pet and WorkingAnimal, and that Animal is resolved before object. Therefore, declaration order influences MRO, but C3 linearization ensures that the hierarchy is respected.

Explanation:

  1. Declaration Order: MRO starts with the most derived class and follows the order in which the base classes are declared.
  2. C3 Linearization: Ensures that each class appears before its superclasses and that the order of inheritance is maintained.

Data Structures: Stack, Queue and Map

Stack

Python

class Pet:
    def is_vaccinated(self):
        return True

class DomesticDog(Dog, Pet):
    pass

C 98

class Pet {
public:
    bool is_vaccinated() const {
        return true;
    }
};

class DomesticDog : public Dog, public Pet {
public:
    DomesticDog(const std::string& name, const std::string& breed) : Dog(name, breed) {}
};

Queue

Python

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

C 98

class Shape {
public:
    virtual ~Shape() {}
    virtual double area() const = 0;
};

Map

Python

if __name__ == "__main__":
    # Cria objetos
    dog = Dog("Rex", "Golden Retriever")

    # Acessa atributos
    print(dog.name)          # Público
    print(dog._age)         # Protegido (ainda acessível)
    # print(dog.__id)       # Isso falhará 
    print(dog._Animal__id)  # Isso funciona (acessando attribute privado com name mangling)

    # Propriedades
    dog.age = 5             # Usa setter automaticamente
    print(dog.age)          # Usa getter automaticamente

    # Métodos estáticos e de classe
    print(Animal.get_kingdom())
    print(Animal.get_species_count())

    # Verifica herança
    print(isinstance(dog, Animal))  # True
    print(issubclass(Dog, Animal)) # True

    # Métodos especiais em ação
    print(str(dog))        # Usa __str__
    print(repr(dog))       # Usa __repr__
    print(len(dog))        # Usa __len__
    print(dog['name'])     # Usa __getitem__

C 98

int main() {
    // Cria objetos
    Dog dog("Rex", "Golden Retriever");

    // Acessa atributos
    std::cout << dog.name << std::endl;          // Público
    std::cout << dog.get_age() << std::endl;     // Protegido (ainda acessível)
    // std::cout << dog.__id << std::endl;       // Isso falhará (privado)

    // Propriedades
    dog.set_age(5);             // Usa setter
    std::cout << dog.get_age() << std::endl;     // Usa getter

    // Métodos estáticos e de classe
    std::cout << Animal::get_kingdom() << std::endl;
    std::cout << Animal::get_species_count() << std::endl;

    // Equivalente aos "métodos especiais":

    // Verifica herança
    if (dog.isinstance<Animal>()) {
        std::cout << "dog é uma instância de Animal" << std::endl;
    }

    std::cout << dog.to_string() << std::endl;   // Usa to_string
    std::cout << dog.repr() << std::endl;        // Usa repr
    std::cout << dog["name"] << std::endl;       // Usa operador []
}

Thank you for following this guide on OOP concepts in Python and C 98. We hope it was useful for your learning journey. If you liked the content, please leave your comment, like and share with your friends and colleagues. If you found an error, leave your comment and I will correct it! Until next time!

The above is the detailed content of OOP Concepts in Python for C Programmers 98. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn