Expert Python
- référence de fixation de nez – Test Python
- Épisode 238 Science des données en collaboration avec Gigantum
- Comment voir les polices utilisées par un site Web • WPShout
- Notre deuxième webinaire en direct sur les questions et réponses pour les acheteurs actifs • WPShout
- Comment créer des pages de produits WooCommerce personnalisées
Les programmeurs Java qui passent à Python ont souvent des difficultés avec l’approche de Python en matière de programmation orientée objet (OOP). L'approche utilisée pour utiliser des objets, des types de variable et d'autres fonctionnalités de langage prises par Python et Java est très différente. Cela peut rendre la commutation entre les deux langues très déroutante.
Cet article compare et contraste la prise en charge de la programmation orientée objet dans Python et Java. À la fin, vous pourrez appliquer vos connaissances en programmation orientée objet à Python, comprendre comment réinterpréter votre compréhension des objets Java vers Python et utiliser les objets de manière Python.
Au cours de cet article, vous allez:
- Construire une classe de base à la fois en Java et en Python
- Explorer le fonctionnement des attributs d'objet dans Python vs Java
- Comparez et contrastez les méthodes Java et les fonctions Python
- Découvrez les mécanismes d'héritage et de polymorphisme dans les deux langues
- Enquêter sur la réflexion entre Python et Java
- Appliquer tout dans une implémentation de classe complète dans les deux langues
Cet article n’est pas une introduction à la programmation orientée objet. Au lieu de cela, il compare les fonctionnalités et les principes orientés objet de Python par rapport à Java. Les lecteurs doivent avoir une bonne connaissance de Java et se familiariser avec le codage Python. Si vous n'êtes pas familier avec la programmation orientée objet, consultez Intro à la programmation orientée objet (OOP) en Python. Tous les exemples Python fonctionneront avec Python 3.6 ou version ultérieure.
Exemples de classes en Python vs Java
Pour commencer, vous allez implémenter la même petite classe en Python et en Java pour illustrer leurs différences. Vous allez les modifier au fur et à mesure de la progression de l'article.
Tout d'abord, supposons que vous ayez les éléments suivants Voiture
définition de classe en Java:
1 Publique classe Voiture
2 privé Chaîne Couleur;
3 privé Chaîne modèle;
4 privé int année;
5
6 Publique Voiture(Chaîne Couleur, Chaîne modèle, int année)
7 ce.Couleur = Couleur;
8 ce.modèle = modèle;
9 ce.année = année;
dix
11
12 Publique Chaîne getColor()
13 revenir Couleur;
14
15
16 Publique Chaîne getModel()
17 revenir modèle;
18
19
20 Publique int getYear()
21 revenir année;
22
23
Les classes Java sont définies dans des fichiers portant le même nom que la classe. Donc, vous devez enregistrer cette classe dans un fichier nommé Car.java
. Une seule classe peut être définie dans chaque fichier.
Un petit similaire Voiture
class est écrit en Python comme suit:
1 classe Voiture:
2 def __init__(soi, Couleur, modèle, année):
3 soi.Couleur = Couleur
4 soi.modèle = modèle
5 soi.année = année
En Python, vous pouvez déclarer une classe n'importe où, dans n'importe quel fichier, à tout moment. Enregistrer cette classe dans le fichier voiture.py
.
En utilisant ces classes comme base, vous pouvez explorer les composants de base des classes et des objets.
Attributs d'objet
Tous les langages orientés objet ont un moyen de stocker des données sur l'objet. En Java et Python, les données sont stockées dans les attributs, qui sont des variables associées à des objets spécifiques.
L'une des différences les plus significatives entre Python et Java réside dans la manière dont ils définissent et gèrent les attributs de classe et d'objet. Certaines de ces différences proviennent de contraintes imposées par les langues, tandis que d’autres découlent des meilleures pratiques.
Déclaration et initialisation
En Java, vous déclarez des attributs dans le corps de la classe, en dehors de toute méthode, avec un type défini. Vous devez définir les attributs de classe avant de les utiliser:
1 Publique classe Voiture {
2 privé Chaîne Couleur;
3 privé Chaîne modèle;
4 privé int année;
En Python, vous déclarez et définissez des attributs dans la classe. __init __ ()
, qui est l’équivalent du constructeur de Java:
1 def __init__(soi, Couleur, modèle, année):
2 soi.Couleur = Couleur
3 soi.modèle = modèle
4 soi.année = année
En préfixant les noms de variables avec soi
, vous dites à Python que ce sont des attributs. Chaque instance de la classe aura une copie. Toutes les variables en Python sont typées de manière vague, et ces attributs ne font pas exception.
Vous pouvez également créer des variables d'instance en dehors de .__ init __ ()
, mais ce n’est pas une bonne pratique car leur portée est souvent source de confusion. Si elles ne sont pas utilisées correctement, les variables d’instance créées en dehors de .__ init __ ()
peut conduire à des bugs subtils difficiles à trouver. Par exemple, vous pouvez ajouter un nouvel attribut .roues
à un Voiture
objet comme ceci:
1 >>> importation voiture
2 >>> ma voiture = voiture.Voiture("jaune", "scarabée", 1967)
3 >>> impression(F"Ma voiture est ma_car.color")
4 Ma voiture est jaune
5
6 >>> ma voiture.roues = 5
7 >>> impression(F"Roues: my_car.wheels")
8 Roues: 5
Cependant, si vous oubliez le my_car.wheels = 5
sur la ligne 6, alors Python affiche une erreur:
1 >>> importation voiture
2 >>> ma voiture = voiture.Voiture("jaune", "scarabée", 1967)
3 >>> impression(F"Ma voiture est ma_car.color")
4 Ma voiture est jaune
5
6 >>> impression(F"Roues: my_car.wheels")
7 Traceback (dernier appel le plus récent):
8 Fichier "" , ligne 1, dans
9 AttributeError: L'objet 'voiture' n'a pas d'attribut 'roues'
En Python, lorsque vous déclarez une variable en dehors d’une méthode, elle est traitée comme une variable de classe. Mettre à jour le Voiture
classe comme suit:
1 classe Voiture:
2
3 roues = 0
4
5 def __init__(soi, Couleur, modèle, année):
6 soi.Couleur = Couleur
7 soi.modèle = modèle
8 soi.année = année
Cela change votre façon d'utiliser la variable roues
. Au lieu de s'y référer à l'aide d'un objet, vous vous y référez en utilisant le nom de la classe:
1 >>> importation voiture
2 >>> ma voiture = voiture.Voiture("jaune", "scarabée", 1967)
3 >>> impression(F"Ma voiture est ma_car.color")
4 Ma voiture est jaune
5
6 >>> impression(F"Il a car.Car.wheels roues")
7 Il a 0 roues
8
9 >>> impression(F"Il a my_car.wheels roues")
dix Il a 0 roues
Remarque: En Python, vous faites référence à une variable de classe en utilisant la syntaxe suivante:
- Le nom du fichier contenant la classe, sans le
.py
extension - Un point
- Le nom de la classe
- Un point
- Le nom de la variable
Depuis que vous avez enregistré le Voiture
classe dans le fichier voiture.py
, vous vous référez à la variable de classe roues
sur la ligne 6 comme voiture. roues
.
Vous pouvez vous référer à mes roues
ou voiture. roues
, mais fais attention. Changer la valeur de la variable d'instance mes roues
ne changera pas la valeur de la variable de classe voiture. roues
:
1 >>> de voiture importation *
2 >>> ma voiture = voiture.Voiture("jaune", "Scarabée", "1966")
3 >>> mon_autre_car = voiture.Voiture("rouge", "corvette", "1999")
4
5 >>> impression(F"Ma voiture est ma_car.color")
6 Ma voiture est jaune
7 >>> impression(F"Il a my_car.wheels roues")
8 Il a 0 roues
9
dix >>> impression(F"Mon autre voiture est my_other_car.color")
11 Mon autre voiture est rouge
12 >>> impression(F"Il a my_other_car.wheels roues")
13 Il a 0 roues
14
15 >>> # Changer la valeur de la variable de classe
16 ... voiture.Voiture.roues = 4
17
18 >>> impression(F"Ma voiture a my_car.wheels roues")
19 Ma voiture a 4 roues
20 >>> impression(F"Mon autre voiture a my_other_car.wheels roues")
21 Mon autre voiture a 4 roues
22
23 >>> # Changer la valeur de la variable d'instance pour my_car
24 ... ma voiture.roues = 5
25
26 >>> impression(F"Ma voiture a my_car.wheels roues")
27 Ma voiture a 5 roues
28 >>> impression(F"Mon autre voiture a my_other_car.wheels roues")
29 Mon autre voiture a 4 roues
Vous définissez deux Voiture
objets sur les lignes 2 et 3:
ma voiture
mon_autre_car
Au début, les deux ont zéro roues. Lorsque vous définissez la variable de classe à l'aide de car.Car.wheels = 4
sur la ligne 16, les deux objets ont maintenant quatre roues. Cependant, lorsque vous définissez la variable d’instance à l’aide de my_car.wheels = 5
à la ligne 24, seul cet objet est affecté.
Cela signifie qu'il existe maintenant deux copies différentes du roues
attribut:
- Une variable de classe qui s'applique à tous
Voiture
objets - Une variable d'instance spécifique applicable à la
ma voiture
objet seulement
Il n’est pas difficile de se référer accidentellement au mauvais et d’introduire des bugs subtils.
L’équivalent de Java à un attribut de classe est un statique
attribut:
Publique classe Voiture
privé Chaîne Couleur;
privé Chaîne modèle;
privé int année;
privé statique int roues;
Publique Voiture(Chaîne Couleur, Chaîne modèle, int année)
ce.Couleur = Couleur;
ce.modèle = modèle;
ce.année = année;
Publique statique int getWheels()
revenir roues;
Publique statique vide setWheels(int compter)
roues = compter;
Normalement, vous faites référence à des variables statiques à l'aide du nom de la classe Java. Vous pouvez faire référence à une variable statique via une instance de classe telle que Python, mais ce n’est pas une pratique recommandée.
Votre classe Java devient longue. L'une des raisons pour lesquelles Java est plus détaillé que Python est la notion de méthodes et d'attributs publics et privés.
Publique et privée
Java contrôle l’accès aux méthodes et aux attributs en différenciant les Publique données et privé Les données.
En Java, les attributs sont censés être déclarés comme privé
, ou protégé
si les sous-classes doivent y avoir un accès direct. Cela limite l'accès à ces attributs à partir du code en dehors de la classe. Donner accès à privé
attributs, vous déclarez Publique
méthodes qui définissent et récupèrent des données de manière contrôlée (plus sur cela plus tard).
Rappelez-vous de votre classe Java ci-dessus que le Couleur
la variable a été déclarée comme privé
. Par conséquent, ce code Java affichera une erreur de compilation à la ligne en surbrillance:
Voiture ma voiture = Nouveau Voiture("bleu", "Gué", 1972)
// peindre la voiture
ma voiture.Couleur = "rouge";
Si vous ne spécifiez pas de niveau d'accès, l'attribut est défini par défaut sur paquet protégé, ce qui limite l’accès aux classes du même package. Vous devez marquer l'attribut comme Publique
si vous voulez que ce code fonctionne.
Toutefois, la déclaration d'attributs publics n'est pas considérée comme une pratique recommandée en Java. Vous devez déclarer les attributs comme privé
, et utilise Publique
méthodes d'accès, telles que le .getColor ()
et .getModel ()
indiqué dans le code.
Python n’a pas la même notion de privé
ou protégé
données que Java fait. Tout en Python est Publique
. Ce code fonctionne parfaitement avec votre classe Python existante:
>>> ma voiture = voiture.Voiture("bleu", "Gué", 1972)
>>> # Peindre la voiture
... ma voiture.Couleur = "rouge"
Au lieu de privé
, Python a la notion de non public variable d'instance. Toute variable commençant par un caractère de soulignement est définie comme non publique. Cette convention de nommage rend plus difficile l’accès à une variable, mais c’est seulement une convention de nommage, et vous pouvez toujours accéder directement à la variable.
Ajoutez la ligne suivante à votre Python Voiture
classe:
classe Voiture:
roues = 0
def __init__(soi, Couleur, modèle, année):
soi.Couleur = Couleur
soi.modèle = modèle
soi.année = année
soi._cupholders = 6
Vous pouvez accéder au ._cupholders
variable directement:
>>> importation voiture
>>> ma voiture = voiture.Voiture("jaune", "Scarabée", "1969")
>>> impression(F"Ce fut construit en mon_car.année")
Il a été construit en 1969
>>> ma voiture.année = 1966
>>> impression(F"Ce fut construit en mon_car.année")
Il a été construit en 1966
>>> impression(F"Il a my_car._cupholders porte-gobelets ")
Il a 6 porte-gobelets.
Python vous permet d'accéder ._cupholders
, mais des IDE tels que VS Code peuvent émettre un avertissement via des linters prenant en charge PEP 8. Pour plus d’informations sur PEP 8, lisez Comment écrire un code Python magnifique avec PEP 8.
Voici le code dans VS Code, avec un avertissement en surbrillance et affiché:
Python reconnaît en outre l’utilisation de caractères de soulignement double devant une variable pour dissimuler un attribut en Python. Lorsque Python voit une variable à double trait de soulignement, il modifie le nom de la variable en interne pour rendre l'accès direct difficile. Ce mécanisme évite les accidents mais n’empêche pas l’accès aux données.
Pour montrer ce mécanisme en action, changez le code Python Voiture
classe à nouveau:
classe Voiture:
roues = 0
def __init__(soi, Couleur, modèle, année):
soi.Couleur = Couleur
soi.modèle = modèle
soi.année = année
soi.__cupholders = 6
Maintenant, lorsque vous essayez d'accéder à la .__ porte-gobelets
variable, vous voyez l'erreur suivante:
>>> importation voiture
>>> ma voiture = voiture.Voiture("jaune", "Scarabée", "1969")
>>> impression(F"Ce fut construit en mon_car.année")
Il a été construit en 1969
>>> ma voiture.année = 1966
>>> impression(F"Ce fut construit en mon_car.année")
Il a été construit en 1966
>>> impression(F"Il a mon_car .__ porte-gobelets porte-gobelets ")
Traceback (dernier appel le plus récent):
Fichier "" , ligne 1, dans
AttributeError: L'objet 'Car' n'a pas d'attribut '__cupholders'
Alors pourquoi ne pas le .__ porte-gobelets
attribut existe?
Lorsque Python voit un attribut avec des traits de soulignement doubles, il le modifie en préfixant le nom d'origine de l'attribut d'un trait de soulignement, suivi du nom de la classe. Pour utiliser l'attribut directement, vous devez également modifier le nom que vous utilisez:
>>> impression(F"Il a my_car._Car__cupholders porte-gobelets ")
Il a 6 porte-gobelets
Lorsque vous utilisez des traits de soulignement doubles pour dissimuler un attribut à l'utilisateur, Python modifie le nom de manière bien documentée. Cela signifie qu'un développeur déterminé peut toujours accéder directement à l'attribut.
Donc, si vos attributs Java sont déclarés privé
et vos attributs Python sont précédés de doubles soulignements. Comment pouvez-vous fournir et contrôler l’accès aux données qu’ils stockent?
Contrôle d'accès
En Java, vous accédez à privé
attributs en utilisant les setters et Getters. Pour permettre aux utilisateurs de peindre leurs voitures, ajoutez le code suivant à votre classe Java:
Publique Chaîne getColor()
revenir Couleur;
Publique Chaîne setColor(Chaîne Couleur)
ce.Couleur = Couleur;
Puisque .getColor ()
et .setColor ()
sont Publique
, tout le monde peut les appeler pour changer ou récupérer la couleur de la voiture. Les meilleures pratiques de Java en matière d’utilisation privé
attributs accessibles avec Publique
Getters et les setters C’est l’une des raisons pour lesquelles le code Java a tendance à être plus détaillé que Python.
Comme vous l'avez vu ci-dessus, vous accédez aux attributs directement en Python. Puisque tout est Publique
, vous pouvez accéder à tout, à tout moment et de n’importe où. Vous définissez et obtenez les valeurs d'attribut directement en vous référant à leurs noms. Vous pouvez même supprimer des attributs en Python, ce qui n’est pas possible en Java:
>>> ma voiture = Voiture("jaune", "scarabée", 1969)
>>> impression(F"Ma voiture a été construite en mon_car.année")
Ma voiture a été construite en 1969
>>> ma voiture.année = 1966
>>> impression(F"Ce fut construit en mon_car.année")
Il a été construit en 1966
>>> del ma voiture.année
>>> impression(F"Ce fut construit en mon_car.année")
Traceback (dernier appel le plus récent):
Fichier "" , ligne 1, dans
AttributeError: L'objet 'voiture' n'a pas d'attribut 'année'
Cependant, il peut arriver que vous souhaitiez contrôler l'accès à un attribut. Dans ce cas, vous pouvez utiliser les propriétés Python.
En python, Propriétés fournit un accès contrôlable aux attributs de classe à l'aide de la syntaxe Python Decorator. (Vous pouvez en apprendre davantage sur les décorateurs dans le cours vidéo Python Decorators 101.) Les propriétés permettent de déclarer des fonctions dans des classes Python analogues aux méthodes Java getter et setter, avec l'avantage supplémentaire de vous permettre également de supprimer des attributs.
Vous pouvez voir le fonctionnement des propriétés en en ajoutant un à votre Voiture
classe:
1 classe Voiture:
2 def __init__(soi, Couleur, modèle, année):
3 soi.Couleur = Couleur
4 soi.modèle = modèle
5 soi.année = année
6 soi._Tension = 12
7
8 @propriété
9 def Tension(soi):
dix revenir soi._Tension
11
12 @Tension.setter
13 def Tension(soi, volts):
14 impression("Attention: cela peut causer des problèmes!")
15 soi._Tension = volts
16
17 @Tension.déleter
18 def Tension(soi):
19 impression("Attention: la radio cessera de fonctionner!")
20 del soi._Tension
Ici, vous développez la notion de Voiture
inclure les véhicules électriques. Vous déclarez le ._Tension
attribut de maintenir la tension de la batterie sur la ligne 6.
Pour fournir un accès contrôlé, vous définissez une fonction appelée Tension()
renvoyer la valeur privée sur les lignes 9 et 10. En utilisant le @propriété
décoration, vous le marquez comme un getter auquel tout le monde peut accéder directement.
De même, vous définissez une fonction de définition sur les lignes 13 à 15, également appelée Tension()
. Cependant, vous décorez cette fonction avec @ tension.setter
. Enfin, vous utilisez @ tension.deleter
décorer un tiers Tension()
lignes 18 à 20, ce qui permet une suppression contrôlée de l'attribut.
Les noms des fonctions décorées sont tous identiques, indiquant qu'ils contrôlent l'accès au même attribut. Les noms de fonction deviennent également le nom de l'attribut que vous utilisez pour accéder à la valeur. Voici comment ces propriétés fonctionnent dans la pratique:
1 >>> de voiture importation *
2 >>> ma voiture = Voiture("jaune", "scarabée", 1969)
3
4 >>> impression(F"Ma voiture utilise mon_car.voltage volts ")
5 Ma voiture utilise 12 volts
6
7 >>> ma voiture.Tension = 6
8 Attention: cela peut causer des problèmes!
9
dix >>> impression(F"Ma voiture utilise maintenant mon_car.voltage volts ")
11 Ma voiture utilise maintenant 6 volts
12
13 >>> del ma voiture.Tension
14 Attention: la radio cessera de fonctionner!
Notez que vous utilisez .Tension
dans les lignes en surbrillance ci-dessus, non ._Tension
. Cela indique à Python d'utiliser les fonctions de propriété que vous avez définies:
- Lorsque vous imprimez la valeur de
mon_car.voltage
sur la ligne 4, appels Python.Tension()
décoré avec@propriété
. - Lorsque vous attribuez une valeur à
mon_car.voltage
sur la ligne 7, appels Python.Tension()
décoré avec@ tension.setter
. - Lorsque vous supprimez
mon_car.voltage
à la ligne 13, appels Python.Tension()
décoré avec@ tension.deleter
.
le @propriété
, @.setter
, et @ .deleter
les décorations permettent de contrôler l'accès aux attributs sans obliger les utilisateurs à utiliser différentes méthodes. Vous pouvez même donner l’impression que les attributs sont des propriétés en lecture seule en omettant le mot @.setter
et @ .deleter
fonctions décorées.
soi
et ce
En Java, une classe se réfère à elle-même avec ce
référence:
Publique Chaîne setColor(Chaîne Couleur)
ce.Couleur = Couleur;
ce
est implicite dans le code Java: il n’est normalement pas nécessaire de l’écrire, sauf s’il peut y avoir confusion entre deux variables portant le même nom.
Vous pouvez écrire le même setter de cette façon:
Publique Chaîne setColor(Chaîne nouvelle couleur)
Couleur = nouvelle couleur;
Puisque Voiture
a un attribut nommé .Couleur
, et il n’ya pas d’autre variable dans la portée portant le même nom, une référence à ce nom fonctionne. Nous avons utilisé ce
dans le premier exemple, pour différencier l'attribut et le paramètre nommés Couleur
.
En Python, le mot clé soi
sert un but similaire. C’est ainsi que vous vous référez aux variables membres, mais contrairement à Java ce
, c’est Champs obligatoires si vous voulez créer ou faire référence à un attribut membre:
classe Voiture:
def __init__(soi, Couleur, modèle, année):
soi.Couleur = Couleur
soi.modèle = modèle
soi.année = année
soi._Tension = 12
@propriété
def Tension(soi):
revenir soi._Tension
Python nécessite chacun soi
dans le code ci-dessus. Chacun crée ou fait référence aux attributs. Si vous les omettez, alors Python créera une variable locale au lieu d'un attribut.
La différence entre comment vous utilisez soi
et ce
en Python et Java est due aux différences sous-jacentes entre les deux langages et à la façon dont ils nomment les variables et les attributs.
Méthodes et fonctions
Cette différence entre Python et Java réside dans le fait que Python a des fonctions et que Java n’en a pas.
En Python, le code suivant est parfaitement correct (et très commun):
>>> def dis salut():
... impression("Salut!")
...
>>> dis salut()
Salut!
Tu peux appeler dis salut()
de partout, il est visible Cette fonction n'a aucune référence à soi
qui indique qu’il s’agit d’une fonction globale et non d’une fonction de classe. Il ne peut ni modifier ni stocker de données dans aucune classe, mais peut utiliser des variables locales et globales.
En revanche, chaque ligne de code Java que vous écrivez appartient à une classe. Les fonctions ne peuvent pas exister en dehors d’une classe et, par définition, toutes les fonctions Java sont des méthodes. En Java, le plus proche d’une fonction pure est d’utiliser une méthode statique:
Publique classe Utils
statique vide Dis salut()
Système.en dehors.imprimer("Salut!")
Utils.SayHi ()
est appelable de n’importe où sans avoir au préalable créé une instance de Utils
. Puisque vous pouvez appeler Dis salut()
sans créer d’objet d’abord, le ce
référence n'existe pas. Cependant, cela n’est toujours pas une fonction dans le sens où dis salut()
est en Python.
Héritage et Polymorphisme
L'héritage et le polymorphisme sont deux concepts fondamentaux de la programmation orientée objet.
L'héritage permet aux objets de dériver des attributs et des fonctionnalités d'autres objets, créant ainsi une hiérarchie allant d'objets plus généraux à plus spécifiques. Par exemple, un Voiture
et un Bateau
sont les deux types spécifiques de Véhicules
. Les objets peuvent hériter de leur comportement d'un seul objet parent ou de plusieurs objets parents. Ils sont alors appelés objets enfants.
Le polymorphisme permet à deux objets ou plus de se comporter comme un autre, ce qui leur permet d'être utilisés de manière interchangeable. Par exemple, si une méthode ou une fonction sait comment peindre un Véhicule
objet, alors il peut aussi peindre un Voiture
ou Bateau
objet, car ils héritent de leurs données et comportement de la Véhicule
.
Ces concepts fondamentaux de POO sont implémentés de manière tout à fait différente dans Python et Java.
Héritage
Python prend en charge l'héritage multiple ou la création de classes qui héritent du comportement de plusieurs classes parentes.
Pour voir comment cela fonctionne, mettez à jour le Voiture
classe en la divisant en deux catégories, une pour les véhicules et une pour les appareils utilisant l’électricité:
classe Véhicule:
def __init__(soi, Couleur, modèle):
soi.Couleur = Couleur
soi.modèle = modèle
classe Dispositif:
def __init__(soi):
soi._Tension = 12
classe Voiture(Véhicule, Dispositif):
def __init__(soi, Couleur, modèle, année):
Véhicule.__init__(soi, Couleur, modèle)
Dispositif.__init__(soi)
soi.année = année
@propriété
def Tension(soi):
revenir soi._Tension
@Tension.setter
def Tension(soi, volts):
impression("Attention: cela peut causer des problèmes!")
soi._Tension = volts
@Tension.déleter
def Tension(soi):
impression("Attention: la radio cessera de fonctionner!")
del soi._Tension
UNE Véhicule
est défini comme ayant .Couleur
et .modèle
les attributs. Puis un Dispositif
est défini pour avoir un ._Tension
attribut. Depuis l'original Voiture
objet avait ces trois attributs, il peut être redéfini pour hériter à la fois du Véhicule
et Dispositif
Des classes. le Couleur
, modèle
, et _Tension
les attributs feront partie de la nouvelle Voiture
classe.
dans le .__ init __ ()
pour Voiture
, vous appelez le .__ init __ ()
méthodes pour les deux classes parentes pour s’assurer que tout est initialisé correctement. Une fois terminé, vous pouvez ajouter toute autre fonctionnalité souhaitée à votre Voiture
. Dans ce cas, vous ajoutez un .année
attribut spécifique à Voiture
objets, et méthodes getter et setter pour .Tension
.
Fonctionnellement, le nouveau Voiture
la classe se comporte comme elle l’a toujours fait. Vous créez et utilisez Voiture
objets comme avant:
>>> de voiture importation *
>>> ma voiture = Voiture("jaune", "scarabée", 1969)
>>> impression(F"Ma voiture est ma_car.color")
Ma voiture est jaune
>>> impression(F"Ma voiture utilise mon_car.voltage volts ")
Ma voiture utilise 12 volts
>>> ma voiture.Tension = 6
Attention: cela peut causer des problèmes!
>>> impression(F"Ma voiture utilise maintenant mon_car.voltage volts ")
Ma voiture utilise maintenant 6 volts
En revanche, Java ne prend en charge qu'un seul héritage, ce qui signifie que les classes en Java peuvent hériter des données et du comportement d'une seule classe parente. Cependant, les objets Java peuvent hériter du comportement de nombreuses interfaces différentes. Les interfaces fournissent un groupe de méthodes associées qu'un objet doit implémenter et permettent à plusieurs classes enfant de se comporter de la même manière.
Pour voir cela en action, divisez le fichier Java Voiture
classe dans une classe parent et un interface
:
Publique classe Véhicule
privé Chaîne Couleur;
privé Chaîne modèle;
Publique Véhicule(Chaîne Couleur, Chaîne modèle)
ce.Couleur = Couleur;
ce.modèle = modèle;
Publique Chaîne getColor()
revenir Couleur;
Publique Chaîne getModel()
revenir modèle;
Publique interface Dispositif
int getVoltage();
Publique classe Voiture s'étend Véhicule met en oeuvre Dispositif
privé int Tension;
privé int année;
Publique Voiture(Chaîne Couleur, Chaîne modèle, int année)
super(Couleur, modèle)
ce.année = année;
ce.Tension = 12;
@Passer outre
Publique int getVoltage()
revenir Tension;
Publique int getYear()
revenir année;
Rappelez-vous que chaque classe
et interface
doit vivre dans son propre fichier.
Comme vous l'avez fait avec Python, vous créez une nouvelle classe appelée Véhicule
contenir les données et les fonctionnalités plus générales relatives au véhicule. Cependant, pour ajouter le Dispositif
fonctionnalité, vous devez créer un interface
au lieu. Ce interface
définit une méthode unique pour renvoyer la tension du Dispositif
.
Redéfinir le Voiture
la classe vous oblige à hériter de Véhicule
en utilisant étendre
et mettre en œuvre le Dispositif
interface utilisant met en oeuvre
. Dans le constructeur, vous appelez le constructeur de la classe parent à l’aide de la commande intégrée. super()
. Puisqu'il n'y a qu'une seule classe parente, elle ne peut faire référence qu'à la Véhicule
constructeur. Mettre en œuvre le interface
, vous écrivez getVoltage ()
en utilisant le @Passer outre
annotation.
Plutôt que d’obtenir la réutilisation du code de Dispositif
comme Python l’a fait, Java exige que vous implémentiez la même fonctionnalité dans chaque classe qui implémente la interface
. Les interfaces définissent uniquement les méthodes – elles ne peuvent pas définir de données d'instance ni de détails d'implémentation.
Alors, pourquoi est-ce le cas pour Java? Tout se résume aux types.
Types et polymorphisme
La vérification de type stricte de Java est ce qui motive sa interface
conception.
Chaque classe
et interface
en Java est un type. Par conséquent, si deux objets Java implémentent le même interface
, alors ils sont considérés comme étant du même type par rapport à celui interface
. Ce mécanisme permet d'utiliser différentes classes de manière interchangeable, ce qui constitue la définition du polymorphisme.
Vous pouvez implémenter la charge de périphérique pour vos objets Java en créant un .charge()
cela prend un Dispositif
charger. Tout objet qui implémente le Dispositif
l'interface peut être passée à .charge()
. Cela signifie également que les classes qui ne mettent pas en œuvre Dispositif
va générer une erreur de compilation.
Créez la classe suivante dans un fichier nommé Rhino.java
:
Maintenant, vous pouvez créer un nouveau Main.java
implémenter .charge()
et explorer comment Voiture
et Rhinocéros
les objets diffèrent:
Publique classe Principale
Publique statique vide charge(Dispositif dispositif)
dispositif.getVoltage();
Publique statique vide principale(Chaîne[] args) jette Exception
Voiture voiture = Nouveau Voiture("jaune", "scarabée", 1969)
Rhinocéros rhinocéros = Nouveau Rhinocéros();
charge(voiture)
charge(rhinocéros)
Voici ce que vous devriez voir lorsque vous essayez de générer ce code:
Information: 2019-02-02 15:20 - Compilation complétée avec
1 erreur et 0 avertissements en 4 secondes 395 ms
Main.java
Erreur: (43, 11) java: types incompatibles: Rhino ne peut pas être converti en périphérique.
Depuis le Rhinocéros
classe n'implémente pas le Dispositif
interface, il ne peut pas être passé dans .charge()
.
Contrairement au typage strict des variables Java, Python utilise un concept appelé frappe de canardCela signifie en gros que si une variable «marche comme un canard et que les charlatans sont comme un canard, c’est un canard». Au lieu d’identifier les objets par type, Python examine leur comportement. Vous pouvez en apprendre davantage sur le système de types Python et la frappe à l'aide de canards dans le Guide ultime de la vérification des types Python.
Vous pouvez explorer la dactylographie à l'aide de canards en implémentant des fonctionnalités de chargement de périphérique similaires pour votre Python. Dispositif
classe:
>>> def charge(dispositif):
... si hasattr(dispositif, '_Tension'):
... impression(F"Charge un device._voltage appareil volt ")
... autre:
... impression(F"Je ne peux pas charger un device .__ class __.__ name__")
...
>>> classe Téléphone(Dispositif):
... passer
...
>>> classe Rhinocéros:
... passer
...
>>> ma voiture = Voiture("jaune", "Scarabée", "1966")
>>> mon téléphone = Téléphone()
>>> mon_rhino = Rhinocéros()
>>> charge(ma voiture)
Chargement d'un appareil 12 volts
>>> charge(mon téléphone)
Chargement d'un appareil 12 volts
>>> charge(mon_rhino)
Je ne peux pas charger un rhinocéros
charge()
doit vérifier l'existence du ._Tension
attribut dans l’objet passé. Depuis le Dispositif
classe définit cet attribut, toute classe qui en hérite (telle que Voiture
et Téléphone
) aura cet attribut et montrera donc qu'ils chargent correctement. Classes qui n'héritent pas de Dispositif
(comme Rhinocéros
) n’aura peut-être pas cet attribut et ne pourra pas charger (ce qui est bien, car charger des rhinocéros peut être dangereux).
Méthodes par défaut
Toutes les classes Java descendent du Objet
class, qui contient un ensemble de méthodes héritées de toutes les autres classes. Les sous-classes peuvent les remplacer ou conserver les valeurs par défaut. le Objet
La classe définit les méthodes suivantes:
classe Objet
booléen équivaut à(Objet obj) ...
int hashCode() ...
Chaîne toString() ...
Par défaut, équivaut à()
compare les adresses du courant Objet
avec une seconde Objet
passé, et hashcode ()
calcule un identifiant unique qui utilise également l'adresse du courant Objet
. Ces méthodes sont utilisées dans de nombreux contextes différents en Java. Par exemple, les classes utilitaires, telles que les collections qui trient les objets en fonction de la valeur, ont besoin des deux.
toString ()
renvoie un Chaîne
représentation de la Objet
. Par défaut, il s'agit du nom de la classe et de l'adresse. Cette méthode est appelée automatiquement quand un Objet
est passé à une méthode qui nécessite un Chaîne
argument, tel que System.out.println ()
:
Voiture voiture = Nouveau Voiture("jaune", "Scarabée", 1969)
Système.en dehors.imprimer(voiture)
L'exécution de ce code utilisera la valeur par défaut .toString ()
pour montrer le voiture
objet:
Pas très utile, non? Vous pouvez améliorer cela en remplaçant la valeur par défaut. .toString ()
. Ajouter cette méthode à votre Java Voiture
classe:
Publique Chaîne toString()
revenir "Voiture: " + getColor() + ":" + getModel() + ":" + getYear();
Lorsque vous exécutez le même exemple de code, les éléments suivants s’affichent:
Voiture: jaune: coléoptère: 1969
Python fournit des fonctionnalités similaires avec un ensemble de méthodes courantes dunder (abréviation de «double soulignement»). Chaque classe Python hérite de ces méthodes et vous pouvez les remplacer pour modifier leur comportement.
Pour les représentations sous forme de chaîne d'un objet, Python fournit __repr __ ()
et __str __ ()
, que vous pouvez en apprendre davantage sur la conversion de chaîne de programmation Pythonic OOP: __repr__
contre __str__
. La représentation non ambiguë d’un objet est renvoyée par __repr __ ()
, tandis que __str __ ()
renvoie une représentation lisible par l'homme. Ce sont à peu près analogues à .hashcode ()
et .toString ()
en Java.
Comme Java, Python fournit des implémentations par défaut de ces méthodes dunder:
>>> ma voiture = Voiture("jaune", "Scarabée", "1966")
>>> impression(repr(ma voiture))
>>> impression(str(ma voiture))
Vous pouvez améliorer ce résultat en remplaçant .__ str __ ()
, l'ajoutant à votre Python Voiture
classe:
def __str__(soi):
revenir F'Voiture self.color : self.model : self.year'
Cela vous donne un bien meilleur résultat:
>>> ma voiture = Voiture("jaune", "Scarabée", "1966")
>>> impression(repr(ma voiture))
>>> impression(str(ma voiture))
Voiture jaune: Coléoptère: 1966
Déroger à la méthode dunder nous a donné une représentation plus lisible de votre Voiture
. Vous voudrez peut-être remplacer le .__ repr __ ()
aussi, comme il est souvent utile pour le débogage.
Python offre beaucoup plus de méthodes de décompression. À l'aide des méthodes dunder, vous pouvez définir le comportement de votre objet lors de l'itération, de la comparaison, de l'ajout ou de la possibilité d'appeler directement un objet, entre autres.
Surcharge de l'opérateur
La surcharge d'opérateurs consiste à redéfinir le fonctionnement des opérateurs Python lorsqu'ils opèrent sur des objets définis par l'utilisateur. Les méthodes dunder de Python vous permettent d’implémenter la surcharge d’opérateurs, ce que Java ne propose pas du tout.
Modifiez votre Python Voiture
classe avec les méthodes supplémentaires suivantes dunder:
classe Voiture:
def __init__(soi, Couleur, modèle, année):
soi.Couleur = Couleur
soi.modèle = modèle
soi.année = année
def __str__(soi):
revenir F'Voiture self.color : self.model : self.year'
def __eq__(soi, autre):
revenir soi.année == autre.année
def __lt__(soi, autre):
revenir soi.année < autre.année
def __ajouter__(soi, autre):
revenir Voiture(soi.Couleur + autre.Couleur,
soi.modèle + autre.modèle,
int(soi.année) + int(autre.année))
Le tableau ci-dessous montre la relation entre ces méthodes dunder et les opérateurs Python qu’elles représentent:
Méthode Dunder | Opérateur | Objectif |
---|---|---|
__eq__ |
== |
Est-ce que ces Voiture les objets ont la même année? |
__lt__ |
< |
Lequel Voiture est un modèle antérieur? |
__ajouter__ |
+ |
Ajouter deux Voiture objets d'une manière absurde |
Lorsque Python voit une expression contenant des objets, il appelle toutes les méthodes dunder définies qui correspondent aux opérateurs de l'expression. Le code ci-dessous utilise ces nouveaux opérateurs arithmétiques surchargés sur quelques Voiture
objets:
>>> ma voiture = Voiture("jaune", "Scarabée", "1966")
>>> ta voiture = Voiture("rouge", "Corvette", "1967")
>>> impression (ma voiture < ta voiture)
Vrai
>>> impression (ma voiture > ta voiture)
Faux
>>> impression (ma voiture == ta voiture)
Faux
>>> impression (ma voiture + ta voiture)
Voiture yellowred: BeetleCorvette: 3933
Il existe de nombreux autres opérateurs que vous pouvez surcharger à l’aide des méthodes dunder. Elles offrent un moyen d’enrichir le comportement de votre objet de la même manière que les méthodes par défaut de la classe de base commune de Java.
Réflexion
La réflexion consiste à examiner un objet ou une classe à partir de l'objet ou de la classe. Java et Python offrent tous deux des moyens d'explorer et d'examiner les attributs et les méthodes d'une classe.
Examiner le type d’un objet
Les deux langues disposent de méthodes pour tester ou vérifier le type d'un objet.
En Python, vous utilisez type()
pour afficher le type d'une variable, et isinstance ()
pour déterminer si une variable donnée est une instance ou un enfant d'une classe spécifique:
>>> ma voiture = Voiture("jaune", "Scarabée", "1966")
>>> impression(type(ma voiture))
>>> impression(isinstance(ma voiture, Voiture))
Vrai
>>> impression(isinstance(ma voiture, Dispositif))
Vrai
En Java, vous interrogez l'objet de son type à l'aide de .getClass ()
et utiliser le exemple de
opérateur pour vérifier une classe spécifique:
Voiture voiture = Nouveau Voiture("jaune", "scarabée", 1969)
Système.en dehors.imprimer(voiture.getClass());
Système.en dehors.imprimer(voiture exemple de Voiture)
Ce code génère les éléments suivants:
classe com.realpython.Car
vrai
Examiner les attributs d’un objet
En Python, vous pouvez afficher tous les attributs et fonctions contenus dans n’importe quel objet (y compris toutes les méthodes dunder) en utilisant dir ()
. Pour obtenir les détails spécifiques d'un attribut ou d'une fonction donnés, utilisez getattr ()
:
>>> impression(dir(ma voiture))
['_Car__cupholders''__add__''__class__''__delattr__''__dict__'['_Car__cupholders''__add__''__class__''__delattr__''__dict__'['_Car__cupholders''__add__''__class__''__delattr__''__dict__'['_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', 'couleur', 'modèle', 'tension', 'roues', 'année']
>>> impression(getattr(ma voiture, "__format__"))
Java dispose de fonctionnalités similaires, mais le contrôle d’accès et la sécurité de type du langage compliquent la récupération.
.getFields ()
récupère une liste de tous les attributs accessibles au public. Cependant, aucun des attributs de Voiture
sont Publique
, ce code retourne un tableau vide:
Champ[] des champs = voiture.getClass()getFields();
Java traite les attributs et les méthodes comme des entités distinctes, donc Publique
les méthodes sont récupérées en utilisant .getDeclaredMethods ()
. Puisque Publique
les attributs auront un correspondant .obtenir
méthode, un moyen de déterminer si une classe contient une propriété spécifique pourrait ressembler à ceci:
- Utilisation
.getFields ()
générer un tableau de toutes les méthodes. - Boucle à travers toutes les méthodes retournées:
- Pour chaque méthode découverte, renvoie true si la méthode:
- Commence avec le mot
obtenir
OU accepte zéro argument - ET ne revient pas
vide
- ET inclut le nom de la propriété
- Commence avec le mot
- Sinon, retourne false.
- Pour chaque méthode découverte, renvoie true si la méthode:
Voici un exemple simple et rapide:
1 Publique statique booléen getProperty(String prénom, Objet objet) jette Exception
2
3 Method[] declaredMethods = objet.getClass().getDeclaredMethods();
4 pour (Method méthode : declaredMethods)
5 si (isGetter(méthode) &&
6 méthode.getName().toUpperCase().contient(prénom.toUpperCase()))
7 revenir vrai;
8
9
dix revenir faux;
11
12
13 // Helper function to get if the method is a getter method
14 Publique statique booléen isGetter(Method méthode)
15 si ((méthode.getName().startsWith("get")
getProperty()
is your entry point. Call this with the name of an attribute and an object. It returns vrai
if the property is found, and faux
if not.
Calling Methods Through Reflection
Both Java and Python provide mechanisms to call methods through reflection.
In the Java example above, instead of simply returning vrai
if the property was found, you could call the method directly. Recall that getDeclaredMethods()
returns an array of Method
objets. le Method
object itself has a method called .invoke()
, which will call the Method
. Instead of returning vrai
when the correct method is found on line 7 above, you can return method.invoke(object)
au lieu.
This capability exists in Python as well. However, since Python doesn’t differentiate between functions and attributes, you have to look specifically for entries that are appelable
:
>>> pour method_name dans dir(my_car):
... si appelable(getattr(my_car, method_name)):
... impression(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 methods are simpler to manage and call than in Java. Adding the ()
operator (and any required arguments) is all you need to do.
The code below will find an object’s .__str__()
and call it through reflection:
>>> pour method_name dans dir(my_car):
... attr = getattr(my_car, method_name)
... si appelable(attr):
... si method_name == '__str__':
... impression(attr())
...
Car yellow : Beetle : 1966
Here, every attribute returned by dir()
est vérifié. You get the actual attribute object using getattr()
, and check if it’s a callable function using callable()
. If so, you then check if its name is __str__()
, and then call it.
Conclusion
Throughout the course of this article, you learned how object-oriented principles differ in Python vs Java. As you read, you:
- Built a basic class in both Java and Python
- Explored how object attributes work in Python vs Java
- Compared and contrasted Java methods and Python functions
- Discovered inheritance and polymorphism mechanisms in both languages
- Investigated reflection across Python vs Java
- Applied everything in a complete class implementation in both languages
If you want to learn more about OOP in Python, be sure to read Object-Oriented Programming (OOP) in Python 3.
Understanding the differences in Python vs Java when handling objects, and the syntax choices each language makes, will help you apply best practices and make your next project smoother.
In order to compare some concrete examples side by side, you can download our sample code to get the complete commented object definitions for the Java Voiture
, Device
, et Véhicule
classes, as well as the complete commented definitions for the Python Voiture
et Véhicule
classes:
[ad_2]