web-dev-qa-db-fra.com

Pourquoi utilisons-nous __init__ dans Python classes?

J'ai du mal à comprendre l'initialisation des classes.

À quoi servent-ils et comment savons-nous ce qu'il faut y inclure? Est-ce que l'écriture en classe nécessite un type de pensée différent de la création de fonctions (j'ai pensé que je pouvais simplement créer des fonctions, puis les envelopper dans une classe afin que je puisse les réutiliser. Cela fonctionnera-t-il?)

Voici un exemple:

class crawler:
  # Initialize the crawler with the name of database
  def __init__(self,dbname):
    self.con=sqlite.connect(dbname)

  def __del__(self):
    self.con.close()

  def dbcommit(self):
    self.con.commit()

Ou un autre exemple de code:

class bicluster:
  def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
    self.left=left
    self.right=right
    self.vec=vec
    self.id=id
    self.distance=distance

Il y a tellement de classes avec __init__ que je rencontre en essayant de lire le code d'autres personnes, mais je ne comprends pas la logique de leur création.

111
Lostsoul

D'après ce que vous avez écrit, il vous manque un élément essentiel de compréhension: la différence entre une classe et un objet. __init__ n'initialise pas une classe, il initialise une instance d'une classe ou d'un objet. Chaque chien a une couleur, mais les chiens en tant que classe n'en ont pas. Chaque chien a quatre pieds ou moins, mais pas la classe de chiens. La classe est un concept d'objet. Lorsque vous voyez Fido et Spot, vous reconnaissez leur ressemblance, leur doghood. C'est la classe.

Quand tu dis

class Dog:
    def __init__(self, legs, colour):
        self.legs = legs
        self.colour = colour

fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")

Vous dites que Fido est un chien brun à 4 pattes alors que Spot est un peu infirme et qu’il est principalement jaune. La fonction __init__ s'appelle un constructeur, ou un initialiseur, et est appelée automatiquement lorsque vous créez une nouvelle instance d'une classe. Dans cette fonction, l’objet nouvellement créé est affecté au paramètre self. La notation self.legs est un attribut appelé legs de l'objet dans la variable self. Les attributs sont un peu les mêmes que les variables, mais ils décrivent l'état d'un objet ou des actions (fonctions) particulières disponibles pour cet objet.

Cependant, notez que vous ne définissez pas colour pour le doghood lui-même - c'est un concept abstrait. Il y a des attributs qui ont du sens sur les classes. Par exemple, population_size en est un. Cela n'a pas de sens de compter le Fido, car Fido en est toujours un. Il est logique de compter les chiens. Disons qu'il y a 200 millions de chiens dans le monde. C'est la propriété de la classe Dog. Fido n'a rien à voir avec le chiffre 200 millions, pas plus que Spot. C'est ce qu'on appelle un "attribut de classe", par opposition aux "attributs d'instance" qui sont colour ou legs ci-dessus.

Passons maintenant à quelque chose de moins canin et plus lié à la programmation. Comme je l'écris ci-dessous, ajouter un cours en classe n'est pas judicieux - de quoi s'agit-il? Les classes dans Python constituent des collections de données différentes, qui se comportent de la même manière. La classe de chiens est composée de Fido et Spot et 199999999998 autres animaux semblables à eux, tous pissant sur des lampadaires. En quoi consiste la classe pour ajouter des choses? Par quelles données inhérentes diffèrent-ils? Et quelles actions partagent-ils?

Cependant, les chiffres ... ce sont des sujets plus intéressants. Dis, entiers. Il y en a beaucoup, beaucoup plus que des chiens. Je sais que Python a déjà des entiers, mais jouons à la stupide et "implémentons-les" à nouveau (en trichant et en utilisant les entiers de Python).

Donc, les entiers sont une classe. Ils ont des données (valeur) et des comportements ("ajoute-moi à cet autre nombre"). Montrons ceci:

class MyInteger:
    def __init__(self, newvalue)
        # imagine self as an index card.
        # under the heading of "value", we will write
        # the contents of the variable newvalue.
        self.value = newvalue
    def add(self, other):
        # when an integer wants to add itself to another integer,
        # we'll take their values and add them together,
        # then make a new integer with the result value.
        return MyInteger(self.value + other.value)

three = MyInteger(3)
# three now contains an object of class MyInteger
# three.value is now 3
five = MyInteger(5)
# five now contains an object of class MyInteger
# five.value is now 5
eight = three.add(five)
# here, we invoked the three's behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8

Ceci est un peu fragile (nous supposons que other sera un MyInteger), mais nous l'ignorerons maintenant. En code réel, nous ne le ferions pas; nous le testerions pour nous en assurer, et peut-être même le forcerions-nous ("vous n'êtes pas un entier? par zut, vous avez 10 nanosecondes pour le devenir! 9 ... 8 ....")

Nous pourrions même définir des fractions. Les fractions savent aussi comment s'ajouter.

class MyFraction:
    def __init__(self, newnumerator, newdenominator)
        self.numerator = newnumerator
        self.denominator = newdenominator
        # because every fraction is described by these two things
    def add(self, other):
        newdenominator = self.denominator * other.denominator
        newnumerator = self.numerator * other.denominator + self.denominator * other.numerator
        return MyFraction(newnumerator, newdenominator)

Il y a même plus de fractions que de nombres entiers (pas vraiment, mais les ordinateurs ne le savent pas). Faisons deux:

half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6

En fait, vous ne déclarez rien ici. Les attributs sont comme un nouveau type de variable. Les variables normales ont une seule valeur. Disons que vous écrivez colour = "grey". Vous ne pouvez pas avoir une autre variable nommée colour qui est "Fuchsia" - pas au même endroit dans le code.

Les tableaux résolvent cela dans une certaine mesure. Si vous dites colour = ["grey", "Fuchsia"], vous avez empilé deux couleurs dans la variable, mais vous les distinguez par leur position (0 ou 1, dans ce cas).

Les attributs sont des variables liées à un objet. Comme avec les tableaux, nous pouvons avoir beaucoup de variables colour, sur différents chiens . Donc, fido.colour est une variable, mais spot.colour en est une autre. Le premier est lié à l'objet dans la variable fido; le second, spot. Désormais, lorsque vous appelez Dog(4, "brown") ou three.add(five), il y aura toujours un paramètre invisible, qui sera attribué au paramètre supplémentaire pendant au début de la liste des paramètres. Il est conventionnellement appelé self, et obtiendra la valeur de l'objet devant le point. Ainsi, dans le __init__ (constructeur) du chien, self sera ce que le nouveau chien se révélera être; dans MyInteger 'add, self sera lié à l'objet dans la variable three. Ainsi, three.value sera la même variable en dehors de add, comme self.value à l'intérieur de add.

Si je dis the_mangy_one = fido, je commencerai par faire référence à l'objet appelé fido avec encore un autre nom. À partir de maintenant, fido.colour est exactement la même variable que the_mangy_one.colour.

Donc, les choses à l'intérieur du __init__. Vous pouvez penser à eux en notant des choses dans l'acte de naissance du chien. colour est en soi une variable aléatoire, peut contenir n'importe quoi. fido.colour ou self.colour est comme un champ de formulaire sur la fiche d'identité du chien; et __init__ est l’employé qui le remplit pour la première fois.

Plus clair?

EDIT: Développer le commentaire ci-dessous:

Vous voulez dire une liste de objets, n'est-ce pas?

Tout d'abord, fido n'est en réalité pas un objet. C'est une variable qui contient actuellement un objet, comme lorsque vous dites x = 5, x est une variable contenant actuellement le nombre cinq. Si vous changez d'avis par la suite, vous pouvez utiliser fido = Cat(4, "pleasing") (tant que vous avez créé une classe Cat), et fido "contiendra" par la suite un objet cat. Si vous faites fido = x, il contiendra alors le nombre cinq et pas un objet animal du tout.

Une classe en elle-même ne connaît pas ses instances sauf si vous écrivez spécifiquement du code pour en garder la trace. Par exemple:

class Cat:
    census = [] #define census array

    def __init__(self, legs, colour):
        self.colour = colour
        self.legs = legs
        Cat.census.append(self)

Ici, census est un attribut au niveau classe de Cat class.

fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that

Notez que vous n'obtiendrez pas [fluffy, sparky]. Ce ne sont que des noms de variables. Si vous voulez que les chats eux-mêmes aient des noms, vous devez créer un attribut distinct pour le nom, puis substituer la méthode __str__ pour renvoyer ce nom. Le but de cette méthode (c'est-à-dire une fonction liée à la classe, tout comme add ou __init__) est de décrire comment convertir l'objet en chaîne, comme lorsque vous l'imprimez.

269
Amadan

Pour contribuer mes 5 cents au explication approfondie d’Amadan .

Où classes sont une description "d'un type" de manière abstraite. Les objets sont leurs réalisations: la chose vivante qui respire. Dans le monde orienté objet, il y a des idées principales que vous pouvez presque appeler l'essence de tout. Elles sont:

  1. encapsulation (ne développera pas ceci)
  2. héritage
  3. polymorphisme

Les objets ont une ou plusieurs caractéristiques (= attributs) et comportements (= méthodes). Le comportement dépend principalement des caractéristiques. Les classes définissent ce que le comportement doit accomplir de manière générale, mais tant que la classe n'est pas réalisée (instanciée) en tant qu'objet, elle reste un concept abstrait de possibilité. Permettez-moi d'illustrer à l'aide de "héritage" et "polymorphisme".

    class Human:
        gender
        nationality
        favorite_drink
        core_characteristic
        favorite_beverage
        name
        age

        def love    
        def drink
        def laugh
        def do_your_special_thing                

    class Americans(Humans)
        def drink(beverage):
            if beverage != favorite_drink: print "You call that a drink?"
            else: print "Great!" 

    class French(Humans)
        def drink(beverage, cheese):
            if beverage == favourite_drink and cheese == None: print "No cheese?" 
            Elif beverage != favourite_drink and cheese == None: print "Révolution!"

    class Brazilian(Humans)
        def do_your_special_thing
            win_every_football_world_cup()

    class Germans(Humans)
        def drink(beverage):
            if favorite_drink != beverage: print "I need more beer"
            else: print "Lecker!" 

    class HighSchoolStudent(Americans):
        def __init__(self, name, age):
             self.name = name
             self.age = age

jeff = HighSchoolStudent(name, age):
hans = Germans()
ronaldo = Brazilian()
amelie = French()

for friends in [jeff, hans, ronaldo]:
    friends.laugh()
    friends.drink("cola")
    friends.do_your_special_thing()

print amelie.love(jeff)
>>> True
print ronaldo.love(hans)
>>> False

Certaines caractéristiques définissent les êtres humains. Mais chaque nationalité diffère quelque peu. Donc, les "types nationaux" sont un peu des humains avec des figurants. Les "Américains" sont un type d '"Humains" et héritent de caractéristiques humaines et de comportements abstraits du type humain (classe de base): c'est l'héritage. Ainsi, tous les humains peuvent rire et boire, donc toutes les classes d'enfants peuvent aussi! Héritage (2).

Mais comme ils sont tous du même genre (Type/base-class: Humans), vous pouvez les échanger parfois: voir la boucle for à la fin. Mais ils vont exposer une caractéristique individuelle, et c'est le polymorphisme (3).

Ainsi, chaque humain a son boisson favorite, mais chaque nationalité tend vers un type de boisson spécial. Si vous sous-classez une nationalité du type Humans, vous pouvez écraser le comportement hérité, comme je l'ai démontré ci-dessus avec la méthode drink(). Mais cela reste au niveau de la classe et à cause de cela, cela reste une généralisation.

hans = German(favorite_drink = "Cola")

instancie la classe German et j'ai "changé" une caractéristique par défaut au début. (Mais si vous appelez hans.drink ("Lait"), il continuerait à écrire "J'ai besoin de plus de bière" - un bogue évident ... ou peut-être que ce serait ce que j'appellerais une fonctionnalité si je serais un employé d'une plus grande entreprise. ;-)! )

La caractéristique d'un type, par exemple Les Allemands (hans) sont généralement définis par le constructeur (en python: __init__) au moment de l'instanciation. C'est le point où vous définissez une classe pour qu'elle devienne un objet. Vous pouvez dire insuffler la vie dans un concept abstrait (classe) en le remplissant de caractéristiques individuelles et en devenant un objet.

Mais comme chaque objet est une instance d'une classe, ils partagent tous certains types de caractéristiques de base et certains comportements. C'est un avantage majeur du concept orienté objet.

Pour protéger les caractéristiques de chaque objet que vous les encapsulez, cela signifie que vous essayez de coupler comportement et caractéristique et vous empêchez de le manipuler de l'extérieur. C'est l'encapsulation (1)

23
Don Question

Il suffit d'initialiser les variables de l'instance.

Par exemple. créez une instance crawler avec un nom de base de données spécifique (d'après votre exemple ci-dessus).

5
jldupont

Il semble que vous ayez besoin d'utiliser __init__ dans Python si vous souhaitez initialiser correctement les attributs modifiables de vos instances.

Voir l'exemple suivant:

>>> class EvilTest(object):
...     attr = []
... 
>>> evil_test1 = EvilTest()
>>> evil_test2 = EvilTest()
>>> evil_test1.attr.append('strange')
>>> 
>>> print "This is evil:", evil_test1.attr, evil_test2.attr
This is evil: ['strange'] ['strange']
>>> 
>>> 
>>> class GoodTest(object):
...     def __init__(self):
...         self.attr = []
... 
>>> good_test1 = GoodTest()
>>> good_test2 = GoodTest()
>>> good_test1.attr.append('strange')
>>> 
>>> print "This is good:", good_test1.attr, good_test2.attr
This is good: ['strange'] []

Ceci est assez différent dans Java où chaque attribut est automatiquement initialisé avec une nouvelle valeur:

import Java.util.ArrayList;
import Java.lang.String;

class SimpleTest
{
    public ArrayList<String> attr = new ArrayList<String>();
}

class Main
{
    public static void main(String [] args)
    {
        SimpleTest t1 = new SimpleTest();
        SimpleTest t2 = new SimpleTest();

        t1.attr.add("strange");

        System.out.println(t1.attr + " " + t2.attr);
    }
}

produit une sortie que nous attendons intuitivement:

[strange] []

Mais si vous déclarez attr comme static, il agira comme Python:

[strange] [strange]
4
alexpirine

Après avec votre voiture exemple: quand vous obtenez une voiture, vous n’obtenez pas une voiture au hasard, je veux dire, vous choisissez la couleur, la marque , nombre de places, etc. Et certaines choses sont aussi "initialiser" sans que vous le choisissiez, comme le nombre de roues ou le numéro d’immatriculation.

class Car:
    def __init__(self, color, brand, number_of_seats):
        self.color = color
        self.brand = brand
        self.number_of_seats = number_of_seats
        self.number_of_wheels = 4
        self.registration_number = GenerateRegistrationNumber()

Ainsi, dans la méthode __init__, vous définissez les attributs de l'instance que vous créez. Donc, si nous voulons une voiture Renault bleue, pour 2 personnes, nous initialiserions une instance de Car comme:

my_car = Car('blue', 'Renault', 2)

De cette façon, nous créons une instance de la classe Car. Le __init__ est celui qui gère nos attributs spécifiques (comme color ou brand) et génère les autres attributs, comme registration_number.

3
juliomalegria

Les classes sont des objets avec des attributs (état, caractéristiques) et des méthodes (fonctions, capacités) spécifiques à cet objet (comme la couleur blanche et les pouvoirs de vol, respectivement, pour un canard).

Lorsque vous créez une instance d'une classe, vous pouvez lui attribuer une personnalité initiale (état ou caractère tel que le nom et la couleur de sa robe pour un nouveau-né). Vous faites cela avec __init__.

__init__ définit les caractéristiques de l'instance automatiquement lorsque vous appelez instance = MyClass(some_individual_traits).

3
joaquin

La fonction __init__ configure toutes les variables membres de la classe. Ainsi, une fois votre bicluster créé, vous pouvez accéder au membre et obtenir une valeur:

mycluster = bicluster(...actual values go here...)
mycluster.left # returns the value passed in as 'left'

Consultez le Python Docs pour plus d’informations. Vous aurez envie de prendre un livre sur OO concepts pour continuer à apprendre.

2
AlG
class Dog(object):

    # Class Object Attribute
    species = 'mammal'

    def __init__(self,breed,name):
        self.breed = breed
        self.name = name

Dans l'exemple ci-dessus, nous utilisons les espèces comme globales, car elles seront toujours les mêmes (type de constante que vous pouvez dire). Lorsque vous appelez la méthode __init__, alors toute la variable à l'intérieur de __init__ sera lancée (par exemple: breed, name).

class Dog(object):
    a = '12'

    def __init__(self,breed,name,a):
        self.breed = breed
        self.name = name
        self.a= a

si vous imprimez l'exemple ci-dessus en appelant ci-dessous comme ceci

Dog.a
12

Dog('Lab','Sam','10')
Dog.a
10

Cela signifie qu'il ne sera initialisé que lors de la création de l'objet. de sorte que tout ce que vous voulez déclarer constant soit global et tout ce qui change utilise __init__

1
vedavyasa k