Programação orientada a objetos em Java e Python: semelhanças e diferenças

Olá Habr! Apresento a você a tradução do artigo “Programação Orientada a Objetos em Python vs Java”, de John Fincher.


A implementação da programação orientada a objetos (OOP) em Java e Python é diferente. O princípio de trabalhar com objetos, tipos de variáveis ​​e outros recursos de idioma pode causar dificuldades na alternância de um idioma para outro. Este artigo, que pode ser útil para programadores Java que desejam aprender Python e para programadores Python que desejam aprender Java melhor, fornece as principais semelhanças e diferenças entre essas linguagens em relação ao OOP.


Mais detalhes - sob o corte.


Exemplos de classe em Python e Java


Para começar, vamos implementar a classe mais simples em Python e Java para ilustrar algumas das diferenças nessas linguagens, e gradualmente faremos alterações nessa classe.
Imagine que temos a seguinte definição da classe Car em Java:


1 public class Car { 2 private String color; 3 private String model; 4 private int year; 5 6 public Car(String color, String model, int year) { 7 this.color = color; 8 this.model = model; 9 this.year = year; 10 } 11 12 public String getColor() { 13 return color; 14 } 15 16 public String getModel() { 17 return model; 18 } 19 20 public int getYear() { 21 return year; 22 } 23 } 

O nome do arquivo Java de origem deve corresponder ao nome da classe armazenada nele, portanto, devemos nomear o arquivo Car.java. Cada arquivo Java pode conter apenas uma classe pública.
A mesma classe no Python seria assim:


  1 class Car: 2 def __init__(self, color, model, year): 3 self.color = color 4 self.model = model 5 self.year = year 

No Python, você pode declarar uma classe em qualquer lugar, a qualquer hora. Salve este arquivo como car.py.
Usando essas classes como base, continuamos o estudo dos principais componentes de classes e objetos.


Atributos de Objeto


Em todas as linguagens orientadas a objetos, os dados sobre um objeto são armazenados em algum lugar. No Python e Java, esses dados são armazenados em atributos , que são variáveis ​​associadas a objetos específicos.


Uma das diferenças mais significativas entre Python e Java é como eles definem os atributos de classe e objeto e como essas linguagens os controlam. Algumas dessas diferenças são causadas por restrições impostas pelos idiomas, enquanto outras estão associadas a práticas mais eficazes.


Declaração e Inicialização


Em Java, declaramos atributos (indicando seu tipo) dentro da classe, mas fora de todos os métodos. Antes de usar atributos de classe, devemos defini-los:


  1 public class Car { 2 private String color; 3 private String model; 4 private int year; 

Em Python, declaramos e definimos atributos dentro do método da classe init (), que é um análogo do construtor em Java:


  1 def __init__(self, color, model, year): 2 self.color = color 3 self.model = model 4 self.year = year 

Ao especificar a palavra-chave self na frente do nome da variável, dizemos ao Python que esses são atributos. Cada instância da classe obtém sua cópia. Todas as variáveis ​​no Python não são de tipo livre e os atributos não são exceção.


As variáveis ​​também podem ser criadas fora do método init (), mas essa não será a melhor solução e pode levar a erros de detecção difícil. Por exemplo, você pode adicionar um novo atributo de rodas ao objeto Carro da seguinte maneira:


  1 >>> import car 2 >>> my_car = car.Car("yellow", "beetle", 1967) 3 >>> print(f"My car is {my_car.color}") 4 My car is yellow 5 6 >>> my_car.wheels = 5 7 >>> print(f"Wheels: {my_car.wheels}") 8 Wheels: 5 

No entanto, se esquecermos de especificar a expressão my_car.wheels = 5 na sexta linha, obteremos um erro:


  1 >>> import car 2 >>> my_car = car.Car("yellow", "beetle", 1967) 3 >>> print(f"My car is {my_car.color}") 4 My car is yellow 5 6 >>> print(f"Wheels: {my_car.wheels}") 7 Traceback (most recent call last): 8 File "<stdin>", line 1, in <module> 9 AttributeError: 'Car' object has no attribute 'wheels' 

No Python, se você declarar uma variável fora do método, ela será considerada uma variável de classe. Vamos mudar a classe Car:


  1 class Car: 2 3 wheels = 0 4 5 def __init__(self, color, model, year): 6 self.color = color 7 self.model = model 8 self.year = year 

Agora, o uso das rodas variáveis ​​mudará. Em vez de acessá-lo através de um objeto, acessamos usando o nome da classe:


  1 >>> import car 2 >>> my_car = car.Car("yellow", "beetle", 1967) 3 >>> print(f"My car is {my_car.color}") 4 My car is yellow 5 6 >>> print(f"It has {car.Car.wheels} wheels") 7 It has 0 wheels 8 9 >>> print(f"It has {my_car.wheels} wheels") 10 It has 0 wheels 

Nota: no Python, uma variável de classe é acessada usando a seguinte sintaxe:


  1. O nome do arquivo que contém a classe (sem a extensão .py)
  2. Ponto
  3. Nome da classe
  4. Ponto
  5. Nome da variável

Como salvamos a classe Car no arquivo car.py, nos referimos à variável de classe wheels na 6ª linha da seguinte maneira: car.Car.wheels.


Ao trabalhar com a variável wheel, você precisa prestar atenção ao fato de que alterar o valor de uma variável de instância da classe my_car.wheels não leva à alteração da variável da classe car.Car.wheels:


  1 >>> from car import * 2 >>> my_car = car.Car("yellow", "Beetle", "1966") 3 >>> my_other_car = car.Car("red", "corvette", "1999") 4 5 >>> print(f"My car is {my_car.color}") 6 My car is yellow 7 >>> print(f"It has {my_car.wheels} wheels") 8 It has 0 wheels 9 10 >>> print(f"My other car is {my_other_car.color}") 11 My other car is red 12 >>> print(f"It has {my_other_car.wheels} wheels") 13 It has 0 wheels 14 15 >>> # Change the class variable value 16 ... car.Car.wheels = 4 17 18 >>> print(f"My car has {my_car.wheels} wheels") 19 My car has 4 wheels 20 >>> print(f"My other car has {my_other_car.wheels} wheels") 21 My other car has 4 wheels 22 23 >>> # Change the instance variable value for my_car 24 ... my_car.wheels = 5 25 26 >>> print(f"My car has {my_car.wheels} wheels") 27 My car has 5 wheels 28 >>> print(f"My other car has {my_other_car.wheels} wheels") 29 My other car has 4 wheels 

Nas linhas 2 e 3, definimos dois objetos Car: my_car e my_other_car.
Primeiro, a propriedade wheel de ambos os objetos é zero. Na 16ª linha, definimos a variável de classe: car.Car.wheels = 4, agora os dois objetos têm 4 rodas. No entanto, quando na 24ª linha alteramos a propriedade do objeto my_car.wheels = 5, a propriedade do segundo objeto permanece intocada.


Isso significa que agora temos duas cópias diferentes do atributo wheel:


  1. Variável de classe que se aplica a todos os objetos Car
  2. Uma variável de instância de classe específica que se aplica apenas ao objeto my_car.
    Por esse motivo, você pode acidentalmente se referir à instância errada e cometer um erro sutil.

Em Java, o equivalente a um atributo de classe é um atributo estático:


 public class Car { private String color; private String model; private int year; private static int wheels; public Car(String color, String model, int year) { this.color = color; this.model = model; this.year = year; } public static int getWheels() { return wheels; } public static void setWheels(int count) { wheels = count; } } 

Normalmente, acessamos variáveis ​​estáticas em Java através do nome da classe. Você pode acessá-los através de uma instância da classe, como no Python, mas essa não será a melhor solução.


Nossa classe Java está começando a aumentar. Uma das razões pelas quais o Java é "detalhado" para o Python é a noção de métodos e atributos públicos e privados.


Público e privado


Java controla o acesso a métodos e atributos, distinguindo entre dados públicos e privados .
Em Java, espera-se que os atributos sejam declarados privados (ou protegidos, se os descendentes da classe precisarem de acesso a eles). Assim, restringimos o acesso a eles de fora. Para fornecer acesso a atributos privados, declaramos métodos públicos que instalam ou recebem esses dados (mais sobre isso mais adiante).


Lembre-se de que em nosso código Java, a variável color foi declarada privada. Portanto, o código abaixo não será compilado:


 Car myCar = new Car("blue", "Ford", 1972); // Paint the car myCar.color = "red"; 

Se você não especificar o nível de acesso aos atributos, por padrão, ele será definido como protegido por pacote , o que limita o acesso às classes dentro do pacote. Se quisermos que o código acima funcione, teremos que tornar o atributo público.


No entanto, Java não é incentivado a declarar atributos públicos. É recomendável que você as declare particulares e, em seguida, use métodos públicos como getColor () e getModel (), conforme mencionado no código acima.


Por outro lado, o Python não possui a noção de dados públicos e privados. No Python, tudo é público. Este código python funcionará com um estrondo:


 >>> my_car = car.Car("blue", "Ford", 1972) >>> # Paint the car ... my_car.color = "red" 

Em vez de variáveis ​​privadas no Python, existe o conceito de variáveis ​​de instância de classe não pública ( não pública ). Todas as variáveis ​​cujos nomes começam com um único sublinhado são consideradas não públicas. Essa convenção de nomenclatura não nos impede de acessar a variável diretamente.


Adicione a seguinte linha ao nosso carro da classe Python:


 class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._cupholders = 6 

Podemos acessar a variável _cupholders diretamente:


 >>> import car >>> my_car = car.Car("yellow", "Beetle", "1969") >>> print(f"It was built in {my_car.year}") It was built in 1969 >>> my_car.year = 1966 >>> print(f"It was built in {my_car.year}") It was built in 1966 >>> print(f"It has {my_car._cupholders} cupholders.") It has 6 cupholders. 

O Python permite que você acesse essa variável, no entanto, alguns ambientes de desenvolvimento como o VS Code emitem um aviso:



Além disso, o Python usa um sublinhado duplo no início de um nome de variável para ocultar um atributo. Quando o Python vê essa variável, ele muda automaticamente seu nome para dificultar o acesso direto. No entanto, esse mecanismo ainda não nos impede de recorrer a ele. Demonstramos isso com o seguinte exemplo:


 class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self.__cupholders = 6 

Agora, se olharmos para a variável __cupholders, obteremos um erro:


 >>> import car >>> my_car = car.Car("yellow", "Beetle", "1969") >>> print(f"It was built in {my_car.year}") It was built in 1969 >>> my_car.year = 1966 >>> print(f"It was built in {my_car.year}") It was built in 1966 >>> print(f"It has {my_car.__cupholders} cupholders.") Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Car' object has no attribute '__cupholders' 

Então, por que o atributo __cupholders não existe?
Aqui está a coisa. Quando o Python vê um atributo de sublinhado duplo no início, ele o altera adicionando um nome de classe sublinhado ao início. Para acessar o atributo diretamente, você também deve alterar o nome:


 >>> print(f"It has {my_car._Car__cupholders} cupholders") It has 6 cupholders 

Agora surge a pergunta: se o atributo da classe Java é declarado privado e o atributo da classe Python é precedido por sublinhado duplo no nome, como chegar a esses dados?


Controle de acesso


Em Java, acessamos atributos privados usando setters e getters . Para que o usuário repinte sua máquina, adicione o seguinte trecho de código à classe Java:


 public String getColor() { return color; } public void setColor(String color) { this.color = color; } 

Como os métodos getColor () e setColor () são públicos, qualquer usuário pode chamá-los e obter / alterar a cor da máquina. O uso de atributos privados, aos quais acessamos getters e setters públicos, é uma das razões para a maior "verbosidade" do Java em comparação ao Python.


Como mostrado acima, em Python, podemos acessar atributos diretamente. Como tudo é público, podemos chegar a qualquer coisa, a qualquer hora e em qualquer lugar. Podemos obter e definir valores de atributo diretamente chamando pelo nome. No Python, podemos até remover atributos, o que é impensável em Java:


 >>> my_car = Car("yellow", "beetle", 1969) >>> print(f"My car was built in {my_car.year}") My car was built in 1969 >>> my_car.year = 1966 >>> print(f"It was built in {my_car.year}") It was built in 1966 >>> del my_car.year >>> print(f"It was built in {my_car.year}") Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Car' object has no attribute 'year' 

No entanto, também acontece que queremos controlar o acesso aos atributos. Nesse caso, as propriedades Python vêm em nosso auxílio.


No Python, as propriedades fornecem acesso controlado aos atributos de classe usando decoradores. Usando propriedades, declaramos funções em classes Python, como getters e setters em Java (remover atributos é um bônus).


A operação das propriedades pode ser vista no seguinte exemplo da classe Car:


  1 class Car: 2 def __init__(self, color, model, year): 3 self.color = color 4 self.model = model 5 self.year = year 6 self._voltage = 12 7 8 @property 9 def voltage(self): 10 return self._voltage 11 12 @voltage.setter 13 def voltage(self, volts): 14 print("Warning: this can cause problems!") 15 self._voltage = volts 16 17 @voltage.deleter 18 def voltage(self): 19 print("Warning: the radio will stop working!") 20 del self._voltage 

Neste exemplo, estendemos o conceito da classe Car para incluir carros elétricos. A linha 6 declara o atributo _voltage para armazenar a voltagem da bateria.


Nas linhas 9 e 10 para acesso controlado, criamos a função voltage () e retornamos o valor da variável privada. Usando o decorador @property, transformamos em um getter, que qualquer usuário agora pode acessar.


Nas linhas 13 a 15, definimos uma função também chamada de tensão (). No entanto, decoramos de maneira diferente: tensão .setter. Por fim, nas linhas 18 a 20, decoramos a função voltage () com o parâmetro voltage .deleter e podemos remover o atributo _voltage, se necessário.


Funções decoradas têm o mesmo nome, indicando que elas controlam o acesso ao mesmo atributo. Esses nomes de função também se tornam os nomes dos atributos usados ​​para obter seus valores. Veja como funciona:


  1 >>> from car import * 2 >>> my_car = Car("yellow", "beetle", 1969) 3 4 >>> print(f"My car uses {my_car.voltage} volts") 5 My car uses 12 volts 6 7 >>> my_car.voltage = 6 8 Warning: this can cause problems! 9 10 >>> print(f"My car now uses {my_car.voltage} volts") 11 My car now uses 6 volts 12 13 >>> del my_car.voltage 14 Warning: the radio will stop working! 

Observe que usamos voltagem, não _ voltagem. Então dizemos ao Python para aplicar as propriedades que ele acabou de definir:


  • Quando imprimimos o valor my_car.voltage na quarta linha, o Python chama a função voltage (), decorada com @property.
  • Quando atribuímos o valor my_car.voltage na 7ª linha, o Python chama a função voltage (), decorada com voltage .setter.
  • Quando excluímos my_car.voltage na linha 13, o Python chama a função voltage (), decorada com tensão .deleter.

Os decoradores acima nos permitem controlar o acesso aos atributos sem usar vários métodos. Você pode até transformar o atributo em uma propriedade somente leitura, removendo as funções decoradas @ .setter e @ .deleter.


eu e isso


Em Java, uma classe se refere a si mesma usando a palavra-chave this:


 public void setColor(String color) { this.color = color; } 

isso está implícito no código Java. Em princípio, nem é necessário escrevê-lo, exceto quando os nomes das variáveis ​​coincidem.


O setter pode ser escrito assim:


 public void setColor(String newColor) { color = newColor; } 

Como a classe Car possui um atributo chamado color e não há mais variáveis ​​com o mesmo nome no escopo, um link para esse nome é acionado. Usamos a palavra-chave this no primeiro exemplo para distinguir entre um atributo e um parâmetro com o mesmo nome de cor.


No Python, a palavra-chave self serve a um propósito semelhante: acessar membros do atributo, mas, diferentemente do Java, é necessário :


 class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._voltage = 12 @property def voltage(self): return self._voltage 

O Python exige que o self seja obrigatório. Cada eu cria ou se refere a um atributo. Se ignorarmos, o Python simplesmente criará uma variável local em vez de um atributo.


A diferença na maneira como usamos self e isso em Python e Java se deve às principais diferenças entre as duas linguagens e à maneira como elas denominam variáveis ​​e atributos.


Métodos e funções


A diferença entre as linguagens em questão é que no Python existem funções, mas no Java elas não são.


No Python, o código a seguir funcionará sem problemas (e é usado em qualquer lugar):


 >>> def say_hi(): ... print("Hi!") ... >>> say_hi() Hi! 

Podemos chamar say_hi () de qualquer lugar na visibilidade. Esta função não contém uma referência a si mesmo, o que significa que é uma função global, não uma função de classe. Ela não poderá alterar ou salvar dados de nenhuma classe, mas poderá usar variáveis ​​locais e globais.


Por outro lado, todas as linhas que escrevemos em Java pertencem a uma classe. Uma função não existe fora da classe e, por definição, todas as funções Java são métodos. Em Java, a coisa mais próxima de uma função pura é um método estático:


 public class Utils { static void SayHi() { System.out.println("Hi!"); } } 

Utils. SayHi () é chamado de qualquer lugar sem primeiro criar uma instância da classe Utils. Como chamamos SayHi () sem criar um objeto, esse link não existe. No entanto, isso ainda não é uma função no sentido em que say_hi () está em Python.


Herança e polimorfismo


Herança e polimorfismo são dois conceitos fundamentais em POO. Graças ao primeiro, os objetos recebem (em outras palavras, herdam) os atributos e a funcionalidade de outros objetos, criando uma hierarquia de objetos mais gerais para objetos mais específicos. Por exemplo, as classes Car e Boat são tipos específicos da classe Vehicle. Ambos os objetos herdam o comportamento de um pai ou vários objetos pai. Nesse caso, eles são chamados de objetos filhos.


O polimorfismo, por sua vez, é a capacidade de trabalhar com objetos diferentes usando a mesma função ou método.


Ambos os conceitos fundamentais de OOP são implementados em Java e Python de maneiras completamente diferentes.


Herança


O Python suporta herança múltipla, ou seja, criar uma classe a partir de mais de um pai.


Para demonstrar isso, dividimos a classe Car em duas categorias: uma para veículos e outra para carros que usam eletricidade:


 class Vehicle: def __init__(self, color, model): self.color = color self.model = model class Device: def __init__(self): self._voltage = 12 class Car(Vehicle, Device): def __init__(self, color, model, year): Vehicle.__init__(self, color, model) Device.__init__(self) self.year = year @property def voltage(self): return self._voltage @voltage.setter def voltage(self, volts): print("Warning: this can cause problems!") self._voltage = volts @voltage.deleter def voltage(self): print("Warning: the radio will stop working!") del self._voltage 

A classe Vehicle define os atributos de cor e modelo. A classe Device possui o atributo _voltage. A classe Car deriva dessas duas classes, e os atributos color, model e _voltage agora fazem parte da nova classe.


O método init () da classe Car chama os métodos init () de ambas as classes pai para garantir que todos os dados sejam inicializados corretamente. Depois disso, podemos adicionar qualquer funcionalidade desejada à classe Car. Neste exemplo, adicionaremos o atributo year, assim como o getter e o setter para _voltage.


A funcionalidade da nova classe Car permanece a mesma. Podemos criar e usar objetos de classe, como fizemos alguns exemplos anteriores:


 >>> from car import * >>> my_car = Car("yellow", "beetle", 1969) >>> print(f"My car is {my_car.color}") My car is yellow >>> print(f"My car uses {my_car.voltage} volts") My car uses 12 volts >>> my_car.voltage = 6 Warning: this can cause problems! >>> print(f"My car now uses {my_car.voltage} volts") My car now uses 6 volts 

A linguagem Java, por sua vez, suporta apenas herança única, o que significa que as classes em Java podem herdar dados e comportamento de apenas uma classe pai. Mas em Java, a herança de várias interfaces é possível. As interfaces fornecem um grupo de métodos relacionados que precisam ser implementados, permitindo que as classes filho se comportem de maneira semelhante.


Para ver isso, dividimos a classe Car Java em sua classe e interface pai:


 public class Vehicle { private String color; private String model; public Vehicle(String color, String model) { this.color = color; this.model = model; } public String getColor() { return color; } public String getModel() { return model; } } public interface Device { int getVoltage(); } public class Car extends Vehicle implements Device { private int voltage; private int year; public Car(String color, String model, int year) { super(color, model); this.year = year; this.voltage = 12; } @Override public int getVoltage() { return voltage; } public int getYear() { return year; } } 

Não esqueça que cada classe e cada interface em Java devem ser colocadas em seu próprio arquivo.


Como no exemplo acima, com Python, criamos uma nova classe Vehicle para armazenar dados e funcionalidades comuns inerentes aos veículos. No entanto, para adicionar a funcionalidade do dispositivo, precisamos criar uma interface que defina o método para obter a voltagem do dispositivo.


A classe Car é criada herdando da classe Vehicle usando a palavra-chave extends e implementando a interface do dispositivo usando a palavra-chave implementements. No construtor da classe, chamamos o construtor pai com super (). Como existe apenas uma classe pai, nos referimos ao construtor da classe Vehicle. Para implementar a interface, redefinimos getVoltage () usando a anotação Override .


Em vez de reutilizar o código do Device, como é feito no Python, o Java exige que implementemos a mesma funcionalidade em cada classe que implementa a interface. As interfaces definem apenas métodos - elas não podem definir dados da instância de classe ou detalhes de implementação.


Então, por que isso está acontecendo com Java? .



Java . , Java- , , . , .


Java- charge(), Device. , Device, charge().


Rhino.java:


 public class Rhino { } 

Main.java charge() , Car Rhino.


 public class Main{ public static void charge(Device device) { device.getVoltage(); } public static void main(String[] args) throws Exception { Car car = new Car("yellow", "beetle", 1969); Rhino rhino = new Rhino(); charge(car); charge(rhino); } } 

    ,    : Information:2019-02-02 15:20 - Compilation completed with 1 error and 0 warnings in 4 s 395 ms Main.java Error:(43, 11) java: incompatible types: Rhino cannot be converted to Device 

Rhino Device, charge().


( — strict variable typing, , Python ) , Java, Python , : « , » ( : " , , , , " – . ). , Python .


Python:


 >>> def charge(device): ... if hasattr(device, '_voltage'): ... print(f"Charging a {device._voltage} volt device") ... else: ... print(f"I can't charge a {device.__class__.__name__}") ... >>> class Phone(Device): ... pass ... >>> class Rhino: ... pass ... >>> my_car = Car("yellow", "Beetle", "1966") >>> my_phone = Phone() >>> my_rhino = Rhino() >>> charge(my_car) Charging a 12 volt device >>> charge(my_phone) Charging a 12 volt device >>> charge(my_rhino) I can't charge a Rhino 

charge() _voltage. Device , - (Car Phone) , , , . , Device ( Rhino), , , , (rhino) .



Java Object, . , . Object :


 class Object { boolean equals(Object obj) { ... } int hashCode() { ... } String toString() { ... } } 

equals() , , hashCode() , . Java . , , , .


toString() . . , , , , System.out.println():


 Car car = new Car("yellow", "Beetle", 1969); System.out.println(car); 

car:


 Car@61bbe9ba 

, ? , toString(). Car:


 public String toString() { return "Car: " + getColor() + " : " + getModel() + " : " + getYear(); } 

, , :


 Car: yellow : Beetle : 1969 

Python (dunder — double underscore). Python- , , , .


Python : repr () str (). repr (), str () . hashcode() toString() Java.


Java, Python :


 >>> my_car = Car("yellow", "Beetle", "1966") >>> print(repr(my_car)) <car.Car object at 0x7fe4ca154f98> >>> print(str(my_car)) <car.Car object at 0x7fe4ca154f98> 

, str () Python- Car:


 def __str__(self): return f'Car {self.color} : {self.model} : {self.year}' 

:


 >>> my_car = Car("yellow", "Beetle", "1966") >>> print(repr(my_car)) <car.Car object at 0x7f09e9a7b630> >>> print(str(my_car)) Car yellow : Beetle : 1966 

. repr (), .


Python , , , .



Python . Python , Java .


Python- Car :


 class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year def __str__(self): return f'Car {self.color} : {self.model} : {self.year}' def __eq__(self, other): return self.year == other.year def __lt__(self, other): return self.year < other.year def __add__(self, other): return Car(self.color + other.color, self.model + other.model, int(self.year) + int(other.year)) 

, :


eq==Car?
lt<Car ?
add+Car

Python , , , .


Car:


 >>> my_car = Car("yellow", "Beetle", "1966") >>> your_car = Car("red", "Corvette", "1967") >>> print (my_car < your_car) True >>> print (my_car > your_car) False >>> print (my_car == your_car) False >>> print (my_car + your_car) Car yellowred : BeetleCorvette : 3933 

, , , Java.



– . Java, Python .



. Python type() isinstance () , :


 >>> my_car = Car("yellow", "Beetle", "1966") >>> print(type(my_car)) <class 'car.Car'> >>> print(isinstance(my_car, Car)) True >>> print(isinstance(my_car, Device)) True 

Java getClass() instanceof :


 Car car = new Car("yellow", "beetle", 1969); System.out.println(car.getClass()); System.out.println(car instanceof Car); 

:


 class com.realpython.Car true 


Python dir() , ( ). , getattr():


 >>> print(dir(my_car)) ['_Car__cupholders', '__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_voltage', 'color', 'model', 'voltage', 'wheels', 'year'] >>> print(getattr(my_car, "__format__")) <built-in method __format__ of Car object at 0x7fb4c10f5438> 

Java , , , .


getFields() . , Car , :


 Field[] fields = car.getClass().getFields(); 

Java , getDeclaredMethods(). get-, , , :


1) getDeclaredMethods()
2) :


  • true, :
    • get ;

    • void;

    • ;

  • false.

:


  1 public static boolean getProperty(String name, Object object) throws Exception { 2 3 Method[] declaredMethods = object.getClass().getDeclaredMethods(); 4 for (Method method : declaredMethods) { 5 if (isGetter(method) && 6 method.getName().toUpperCase().contains(name.toUpperCase())) { 7 return true; 8 } 9 } 10 return false; 11 } 12 13 // Helper function to get if the method is a getter method 14 public static boolean isGetter(Method method) { 15 if ((method.getName().startsWith("get") || 16 method.getParameterCount() == 0 ) && 17 !method.getReturnType().equals(void.class)) { 18 return true; 19 } 20 return false; 21 } 

getProperty() – . . true, , false.



Java, Python .
Java- true , , . , getDeclaredMethods() Method. Method invoke(), Method. 7 true, , method.invoke(object).


Python. , Python , , :


 >>> for method_name in dir(my_car): ... if callable(getattr(my_car, method_name)): ... print(method_name) ... __add__ __class__ __delattr__ __dir__ __eq__ __format__ __ge__ __getattribute__ __gt__ __init__ __init_subclass__ __le__ __lt__ __ne__ __new__ __reduce__ __reduce_ex__ __repr__ __setattr__ __sizeof__ __str__ __subclasshook__ 

Python , Java. str () :


 >>> for method_name in dir(my_car): ... attr = getattr(my_car, method_name) ... if callable(attr): ... if method_name == '__str__': ... print(attr()) ... Car yellow : Beetle : 1966 

, dir(). , getattr(), callable(), . , , str (), .

Source: https://habr.com/ru/post/pt455796/


All Articles