¿Por qué usamos __init__ en las clases de Python?

Estoy teniendo problemas para entender la inicialización de las clases.

¿Cuál es el punto de ellos y cómo sabemos qué incluir en ellos? ¿La escritura en las clases requiere un tipo diferente de pensamiento frente a la creación de funciones (pensé que podría crear funciones y luego envolverlas en una clase para poder reutilizarlas? ¿Funcionará?)

Aquí hay un ejemplo:

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() 

U otro ejemplo de código:

 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 

Hay tantas clases con __init__ que encuentro cuando bash leer el código de otras personas, pero no entiendo la lógica al crearlas.

Por lo que escribiste, te falta una pieza crítica de comprensión: la diferencia entre una clase y un objeto. __init__ no inicializa una clase, inicializa una instancia de una clase o un objeto. Cada perro tiene color, pero los perros como clase no. Cada perro tiene cuatro pies o menos, pero la clase de perros no. La clase es un concepto de un objeto. Cuando ves a Fido y Spot, reconoces su similitud, su doghood. Esa es la clase.

Cuando tu dices

 class Dog: def __init__(self, legs, colour): self.legs = legs self.colour = colour fido = Dog(4, "brown") spot = Dog(3, "mostly yellow") 

Estás diciendo que Fido es un perro marrón con 4 patas, mientras que Spot es un poco lisiado y en su mayoría es amarillo. La función __init__ se llama constructor, o inicializador, y se llama automáticamente cuando crea una nueva instancia de una clase. Dentro de esa función, el objeto recién creado se asigna al parámetro self . La notación self.legs es un atributo llamado legs del objeto en la variable self . Los atributos son similares a las variables, pero describen el estado de un objeto, o acciones particulares (funciones) disponibles para el objeto.

Sin embargo, tenga en cuenta que no configura el colour para el doghood en sí, es un concepto abstracto. Hay atributos que tienen sentido en las clases. Por ejemplo, el tamaño de la population_size es uno de ellos, no tiene sentido contar el Fido porque Fido siempre es uno. Tiene sentido contar perros. Digamos que hay 200 millones de perros en el mundo. Es propiedad de la clase de perros. Fido no tiene nada que ver con el número 200 millones, ni tiene Spot. Se llama “atributo de clase”, en oposición a los “atributos de instancia” que son de colour o legs arriba.

Ahora, a algo menos canino y más relacionado con la progtwigción. Como escribo a continuación, la clase para agregar cosas no es sensata. ¿De qué es una clase? Las clases en Python se componen de colecciones de datos diferentes, que se comportan de manera similar. La clase de perros está formada por Fido y Spot y 199999999998 otros animales similares a ellos, todos ellos orinando en las farolas. ¿En qué consiste la clase para agregar cosas? ¿Por qué datos inherentes a ellos difieren? ¿Y qué acciones comparten?

Sin embargo, los números … esos son temas más interesantes. Di, los enteros. Hay muchos de ellos, mucho más que perros. Sé que Python ya tiene enteros, pero seamos tontos y los “implementemos” de nuevo (haciendo trampa y usando los enteros de Python).

Entonces, los enteros son una clase. Tienen algunos datos (valor) y algunos comportamientos (“agregarme a este otro número”). Vamos a mostrar esto:

 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 

Esto es un poco frágil (asumimos que other será un MyInteger), pero lo ignoraremos ahora. En código real, no lo haríamos; lo probamos para asegurarnos, y tal vez incluso lo coaccionemos (“¿no eres un entero? Por cierto, ¡tienes 10 nanosegundos para convertirte en uno! 9 … 8 …”)

Incluso podríamos definir fracciones. Las fracciones también saben sumrse.

 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) 

Hay incluso más fracciones que enteros (no realmente, pero las computadoras no lo saben). Hagamos dos:

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

En realidad no estás declarando nada aquí. Los atributos son como un nuevo tipo de variable. Las variables normales solo tienen un valor. Digamos que usted escribe colour = "grey" . No puede tener otra variable llamada colour que sea "fuchsia" , no en el mismo lugar en el código.

Las matrices resuelven eso hasta cierto punto. Si dice colour = ["grey", "fuchsia"] , ha astackdo dos colores en la variable, pero los distingue por su posición (0 o 1, en este caso).

Los atributos son variables que están vinculadas a un objeto. Al igual que con las matrices, podemos tener muchas variables de colour , en diferentes perros . Entonces, fido.colour es una variable, pero spot.colour es otra. El primero está vinculado al objeto dentro de la variable fido ; El segundo, spot . Ahora, cuando llama a Dog(4, "brown") , o three.add(five) , siempre habrá un parámetro invisible, que se asignará al extra que cuelga al principio de la lista de parámetros. Se llama convencionalmente ” self y obtendrá el valor del objeto delante del punto. Por lo tanto, dentro del __init__ (constructor) del Perro, el self será lo que el nuevo Perro se convertirá en; dentro de la MyInteger de MyInteger , self se vinculará al objeto en la variable three . Por lo tanto, three.value será la misma variable fuera del add , como self.value dentro del add .

Si digo the_mangy_one = fido , comenzaré a referirme al objeto conocido como fido con otro nombre. A partir de ahora, fido.colour es exactamente la misma variable que the_mangy_one.colour .

Entonces, las cosas dentro del __init__ . Puedes pensar en ellos como anotar cosas en el certificado de nacimiento del perro. colour por sí mismo es una variable aleatoria, podría contener cualquier cosa. fido.colour o self.colour es como un campo de formulario en la hoja de identidad del Perro; y __init__ es el empleado que lo completa por primera vez.

¿Algo más claro?

EDITAR : Ampliando el comentario a continuación:

Te refieres a una lista de objetos , ¿no?

En primer lugar, fido realidad no es un objeto. Es una variable, que actualmente contiene un objeto, al igual que cuando dices x = 5 , x es una variable que actualmente contiene el número cinco. Si luego cambia de opinión, puede hacer fido = Cat(4, "pleasing") (siempre y cuando haya creado una clase Cat ), y fido desde ese momento “contendrá” un objeto cat. Si haces fido = x , entonces contendrá el número cinco, y no un objeto animal en absoluto.

Una clase por sí misma no conoce sus instancias a menos que usted escriba específicamente un código para realizar un seguimiento de ellas. Por ejemplo:

 class Cat: census = [] #define census array def __init__(self, legs, colour): self.colour = colour self.legs = legs Cat.census.append(self) 

Aquí, el census es un atributo de nivel de clase de la clase Cat .

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

Tenga en cuenta que no obtendrá [fluffy, sparky] . Esos son solo nombres de variables. Si desea que los propios gatos tengan nombres, debe crear un atributo separado para el nombre y, a continuación, anular el método __str__ para devolver este nombre. El propósito de este método (es decir, la función vinculada a la clase, como add o __init__ ) es describir cómo convertir el objeto en una cadena, como cuando lo imprimes.

Contribuir mis 5 centavos a la explicación completa de Amadan .

Donde las clases son una descripción “de un tipo” de una manera abstracta. Los objetos son sus realizaciones: la cosa viva que respira. En el mundo orientado a objetos, hay ideas principales que casi se pueden llamar la esencia de todo. Son:

  1. encapsulamiento (no explicaré esto)
  2. herencia
  3. polymorphism

Los objetos tienen una o más características (= Atributos) y comportamientos (= Métodos). El comportamiento depende principalmente de las características. Las clases definen lo que el comportamiento debe lograr de una manera general, pero mientras la clase no se realice (ejemplifique) como un objeto, sigue siendo un concepto abstracto de una posibilidad. Permítanme ilustrar con la ayuda de “herencia” y “polymorphism”.

  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 

Algunas características definen a los seres humanos. Pero cada nacionalidad difiere un poco. Así que los “tipos nacionales” son humanos con extras. Los “estadounidenses” son un tipo de “humanos” y heredan algunas características y comportamientos abstractos del tipo humano (clase base): eso es herencia. ¡Así que todos los Humanos pueden reír y beber, por lo tanto, todas las clases de niños también pueden! Herencia (2).

Pero como todos son del mismo tipo (Tipo / clase base: Humanos), a veces se pueden intercambiar: ver el for-loop al final. Pero expondrán una característica individual, y eso es el polymorphism (3).

Entonces, cada humano tiene una bebida favorita, pero cada nacionalidad tiende a tomar un tipo especial de bebida. Si subclasifica una nacionalidad del tipo de Humanos, puede sobrescribir el comportamiento heredado como lo he demostrado anteriormente con el Método de la drink() . Pero eso sigue siendo a nivel de clase y debido a esto sigue siendo una generalización.

 hans = German(favorite_drink = "Cola") 

crea una instancia de la clase alemana y “cambié” una característica predeterminada al principio. (Pero si llama a hans.drink (‘Leche’), aún imprimirá “Necesito más cerveza”: un error obvio … o tal vez eso es lo que llamaría una característica si fuera un empleado de una compañía más grande. ;-)! )

Las características de un tipo, por ejemplo, los alemanes (hans) se definen generalmente a través del constructor (en python: __init__ ) en el momento de la __init__ de instancias. Este es el punto donde se define una clase para convertirse en un objeto. Podría decirse que respire la vida en un concepto abstracto (clase) llenándolo con características individuales y convirtiéndose en un objeto.

Pero como cada objeto es una instancia de una clase, comparten algunos tipos característicos básicos y algún comportamiento. Esta es una gran ventaja del concepto orientado a objetos.

Para proteger las características de cada objeto, encapsúlelos: significa que intenta unir el comportamiento y las características y dificulta su manipulación desde fuera del objeto. Eso es encapsulación (1)

Es solo para inicializar las variables de la instancia.

Por ejemplo, cree una instancia de crawler con un nombre de base de datos específico (de su ejemplo anterior).

Siguiendo con su ejemplo de automóvil : cuando obtiene un automóvil, simplemente no obtiene un automóvil aleatorio, quiero decir, usted elige el color, la marca, el número de asientos, etc. Y algunas cosas también se “inicializan” sin que usted elija Por ello, como número de ruedas o número de matrícula.

 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() 

Entonces, en el método __init__ usted define los atributos de la instancia que está creando. Entonces, si queremos un automóvil Renault azul, para 2 personas, podríamos inicializar o instancia de Car como:

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

De esta manera, estamos creando una instancia de la clase Car . El __init__ es el que maneja nuestros atributos específicos (como el color o la brand ) y está generando los otros atributos, como el número de registration_number .

  • Más sobre clases en Python
  • Más sobre el método __init__

Parece que necesitas usar __init__ en Python si quieres inicializar correctamente los atributos mutables de tus instancias.

Vea el siguiente ejemplo:

 >>> 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'] [] 

Esto es bastante diferente en Java, donde cada atributo se inicializa automáticamente con un nuevo valor:

 import java.util.ArrayList; import java.lang.String; class SimpleTest { public ArrayList attr = new ArrayList(); } 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); } } 

produce una salida que intuitivamente esperamos:

 [strange] [] 

Pero si declara attr como static , actuará como Python:

 [strange] [strange] 

Las clases son objetos con atributos (estado, característica) y métodos (funciones, capacidades) que son específicos para ese objeto (como el color blanco y los poderes de vuelo, respectivamente, para un pato).

Cuando creas una instancia de una clase, puedes darle cierta personalidad inicial (estado o carácter como el nombre y el color de su vestido para un recién nacido). Haces esto con __init__ .

Básicamente, __init__ establece las características de la instancia automáticamente cuando llama a instance = MyClass(some_individual_traits) .

La función __init__ está configurando todas las variables miembro en la clase. Así que una vez que se crea su bicluster, puede acceder al miembro y obtener un valor de retorno:

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

Echa un vistazo a los documentos de Python para obtener información. Usted querrá recoger un libro sobre conceptos OO para continuar aprendiendo.

 class Dog(object): # Class Object Attribute species = 'mammal' def __init__(self,breed,name): self.breed = breed self.name = name 

En el ejemplo anterior, utilizamos las especies como globales, ya que siempre serán las mismas (se puede decir de alguna forma constante). cuando llame __init__ método __init__ , entonces se __init__ toda la variable dentro de __init__ (por ejemplo, raza, nombre).

 class Dog(object): a = '12' def __init__(self,breed,name,a): self.breed = breed self.name = name self.a= a 

Si imprime el ejemplo anterior llamando a continuación como este

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

Eso significa que solo se inicializará durante la creación del objeto. por lo tanto, cualquier cosa que desee declarar como constante la hace global y cualquier cambio que use __init__