¿Cuál es el propósito de uno mismo?

¿Cuál es el propósito de la palabra self en Python? Entiendo que se refiere al objeto específico creado a partir de esa clase, pero no puedo ver por qué se debe agregar explícitamente a cada función como parámetro. Para ilustrar, en Ruby puedo hacer esto:

 class myClass def myFunc(name) @name = name end end 

Que entiendo, con bastante facilidad. Sin embargo, en Python necesito incluir self :

 class myClass: def myFunc(self, name): self.name = name 

¿Alguien puede hablarme a través de esto? No es algo que haya encontrado en mi experiencia (ciertamente limitada).

La razón por la que necesitas usar el self. es porque Python no usa la syntax de @ para referirse a los atributos de instancia. Python decidió hacer métodos de una manera que haga que la instancia a la que pertenece el método se pase automáticamente, pero no se reciba automáticamente: el primer parámetro de los métodos es la instancia a la que se llama el método. Eso hace que los métodos sean completamente iguales a las funciones, y deja que el nombre real se use para ti (aunque self es la convención, y la gente generalmente te frunce el ceño cuando usas otra cosa). self no es especial para el código, es simplemente otro objeto

Python podría haber hecho algo más para distinguir los nombres normales de los atributos (syntax especial como Ruby), o requerir declaraciones como C ++ y Java, o quizás algo más diferente, pero no fue así. Python es todo para hacer que las cosas sean explícitas, lo que lo hace obvio, y aunque no lo hace del todo en todas partes, lo hace por ejemplo, los atributos. Es por eso que asignar un atributo de instancia necesita saber a qué instancia asignar y por eso se necesita a self. .

Tomemos una clase simple de vectores:

 class Vector: def __init__(self, x, y): self.x = x self.y = y 

Queremos tener un método que calcule la longitud. ¿Cómo sería si quisiéramos definirlo dentro de la clase?

  def length(self): return math.sqrt(self.x ** 2 + self.y ** 2) 

¿Qué aspecto debería tener cuando lo definiéramos como un método / función global?

 def length_global(vector): return math.sqrt(vector.x ** 2 + vector.y ** 2) 

Así que toda la estructura se mantiene igual. ¿Cómo puedo hacer uso de esto? Si asumimos por un momento que no habíamos escrito un método de length para nuestra clase Vector , podríamos hacer esto:

 Vector.length_new = length_global v = Vector(3, 4) print(v.length_new()) # 5.0 

Esto funciona porque el primer parámetro de length_global puede reutilizarse como el parámetro self en length_new . Esto no sería posible sin un self explícito.


Otra forma de entender la necesidad de un self explícito es ver dónde Python agrega algo de azúcar sintáctico. Cuando se tiene en cuenta, básicamente, una llamada como

 v_instance.length() 

se transforma internamente a

 Vector.length(v_instance) 

es fácil ver dónde encaja el self . En realidad, no se escriben métodos de instancia en Python; lo que escribes son métodos de clase que deben tomar una instancia como primer parámetro. Y por lo tanto, tendrás que colocar el parámetro de instancia en algún lugar explícitamente.

Digamos que tiene una clase ClassA que contiene un método methodA definido como:

 def methodA(self, arg1, arg2): # do something 

y ObjectA es una instancia de esta clase.

Ahora, cuando se ObjectA.methodA(arg1, arg2) , python lo convierte internamente como:

 ClassA.methodA(ObjectA, arg1, arg2) 

La self variable se refiere al objeto en sí.

Cuando se crea una instancia de los objetos, el objeto en sí se pasa al parámetro auto.

introduzca la descripción de la imagen aquí

Debido a esto, los datos del objeto están vinculados al objeto. A continuación se muestra un ejemplo de cómo le gustaría visualizar qué aspecto podrían tener los datos de cada objeto. Observe cómo se reemplaza ‘self’ con el nombre de los objetos. No estoy diciendo que este diagtwig de ejemplo a continuación sea totalmente exacto, pero espero que sirva para un propósito en la visualización del uso del yo.

introduzca la descripción de la imagen aquí

El objeto se pasa al parámetro propio para que el objeto pueda mantener sus propios datos.

Si bien esto puede no ser del todo exacto, piense en el proceso de creación de instancias de un objeto como este: cuando se crea un objeto, utiliza la clase como plantilla para sus propios datos y métodos. Sin pasar su nombre propio en el parámetro auto, los atributos y métodos de la clase permanecerían como una plantilla general y no serían referenciados (pertenecerían a) al objeto. Por lo tanto, al pasar el nombre del objeto al parámetro auto, esto significa que si se crea una instancia de 100 objetos de una clase, todos pueden realizar un seguimiento de sus propios datos y métodos.

Vea la siguiente ilustración:

introduzca la descripción de la imagen aquí

Me gusta este ejemplo:

 class A: foo = [] a, b = A(), A() a.foo.append(5) b.foo ans: [5] class A: def __init__(self): self.foo = [] a, b = A(), A() a.foo.append(5) b.foo ans: [] 

Voy a demostrar con código que no utiliza clases :

 def state_init(state): state['field'] = 'init' def state_add(state, x): state['field'] += x def state_mult(state, x): state['field'] *= x def state_getField(state): return state['field'] myself = {} state_init(myself) state_add(myself, 'added') state_mult(myself, 2) print( state_getField(myself) ) #--> 'initaddedinitadded' 

Las clases son solo una forma de evitar pasar esta cosa de “estado” todo el tiempo (y otras cosas agradables como la inicialización, la composición de la clase, las metaclases que rara vez se necesitan y los métodos personalizados compatibles para anular a los operadores).

Ahora vamos a demostrar el código anterior usando la maquinaria de clase Python incorporada, para mostrar cómo es básicamente lo mismo.

 class State(object): def __init__(self): self.field = 'init' def add(self, x): self.field += x def mult(self, x): self.field *= x s = State() s.add('added') # self is implicitly passed in s.mult(2) # self is implicitly passed in print( s.field ) 

[migré mi respuesta de la pregunta cerrada duplicada]

Los siguientes extractos son de la documentación de Python sobre sí mismo :

Al igual que en Modula-3, no hay abreviaturas [en Python] para hacer referencia a los miembros del objeto desde sus métodos: la función del método se declara con un primer argumento explícito que representa el objeto, que la llamada proporciona de forma implícita.

A menudo, el primer argumento de un método se llama self. Esto no es más que una convención: el nombre self no tiene ningún significado especial para Python. Sin embargo, tenga en cuenta que al no seguir la convención, su código puede ser menos legible para otros progtwigdores de Python, y también es concebible que se pueda escribir un progtwig de navegador de clase que se base en dicha convención.

Para obtener más información, consulte el tutorial de documentación de Python sobre las clases .

Además de todas las otras razones ya establecidas, permite un acceso más fácil a los métodos anulados; puede llamar a Class.some_method(inst) .

Un ejemplo de donde es útil:

 class C1(object): def __init__(self): print "C1 init" class C2(C1): def __init__(self): #overrides C1.__init__ print "C2 init" C1.__init__(self) #but we still want C1 to init the class too 
 >>> C2() "C2 init" "C1 init" 

Su uso es similar al uso de this palabra clave en Java, es decir, para dar una referencia al objeto actual.

Python no es un lenguaje creado para Progtwigción Orientada a Objetos a diferencia de Java o C ++.

Al llamar a un método estático en Python, uno simplemente escribe un método con argumentos regulares dentro de él.

 class Animal(): def staticMethod(): print "This is a static method" 

Sin embargo, un método de objeto, que requiere que hagas una variable, que es un Animal, en este caso, necesita el argumento propio.

 class Animal(): def objectMethod(self): print "This is an object method which needs an instance of a class" 

El método propio también se usa para referirse a un campo variable dentro de la clase.

 class Animal(): #animalName made in constructor def Animal(self): self.animalName = ""; def getAnimalName(self): return self.animalName 

En este caso, self se refiere a la variable animalName de toda la clase. RECUERDE: si tiene una variable dentro de un método, no funcionará. Esa variable simplemente existe solo mientras se ejecuta ese método. Para definir campos (las variables de toda la clase), debe definirlos FUERA de los métodos de clase.

Si no entiende una sola palabra de lo que estoy diciendo, entonces “Progtwigción Orientada a Objetos” de Google. Una vez que entiendas esto, ni siquiera necesitarás hacer esa pregunta :).

Está ahí para seguir el zen de Python “explícito es mejor que implícito”. De hecho, es una referencia a su objeto de clase. En Java y PHP, por ejemplo, se llama this .

Si user_type_name es un campo en su modelo, puede acceder por self.user_type_name .

self es una referencia de objeto al objeto en sí, por lo tanto, son iguales. Los métodos de Python no se llaman en el contexto del objeto en sí. self en Python puede usarse para tratar con modelos de objetos personalizados o algo así.

En primer lugar, el yo es un nombre convencional, podría poner cualquier otra cosa (ser coherente) en su lugar.

Se refiere al objeto en sí, por lo que cuando lo está utilizando, está declarando que .name y .age son propiedades de los objetos de Student (nota, no de la clase de Student) que va a crear.

 class Student: #called each time you create a new Student instance def __init__(self,name,age): #special method to initialize self.name=name self.age=age def __str__(self): #special method called for example when you use print return "Student %s is %s years old" %(self.name,self.age) def call(self, msg): #silly example for custom method return ("Hey, %s! "+msg) %self.name #initializing two instances of the student class bob=Student("Bob",20) alice=Student("Alice",19) #using them print bob.name print bob.age print alice #this one only works if you define the __str__ method print alice.call("Come here!") #notice you don't put a value for self #you can modify attributes, like when alice ages alice.age=20 print alice 

El código está aquí

Me sorprende que nadie haya criado a Lua. Lua también usa la variable ‘self’, sin embargo, se puede omitir pero aún se puede usar. C ++ hace lo mismo con ‘esto’. No veo ninguna razón para tener que declarar “yo” en cada función, pero aún así debería poder usarlo como lo hace con lua y C ++. Para un lenguaje que se enorgullece de ser breve, es extraño que requiera que declare la variable propia.

Eche un vistazo al siguiente ejemplo, que explica claramente el propósito de self

 class Restaurant(object): bankrupt = False def open_branch(self): if not self.bankrupt: print("branch opened") #create instance1 >>> x = Restaurant() >>> x.bankrupt False #create instance2 >>> y = Restaurant() >>> y.bankrupt = True >>> y.bankrupt True >>> x.bankrupt False 

Se usa / necesita el self para distinguir entre instancias.

Es porque por la forma en que Python está diseñado, las alternativas difícilmente funcionarán. Python está diseñado para permitir que los métodos o funciones se definan en un contexto donde tanto this implícito (a-la Java / C ++) como explícito @ (a-la ruby) no funcionarán. Vamos a tener un ejemplo con el enfoque explícito con las convenciones de python:

 def fubar(x): self.x = x class C: frob = fubar 

Ahora la función fubar no funcionaría, ya que supondría que self es una variable global (y también en frob ). La alternativa sería ejecutar métodos con un scope global reemplazado (donde self es el objeto).

El enfoque implícito sería

 def fubar(x) myX = x class C: frob = fubar 

Esto significaría que myX se interpretaría como una variable local en fubar (y también en frob ). La alternativa aquí sería ejecutar métodos con un scope local reemplazado que se mantenga entre las llamadas, pero eso eliminaría la posibilidad de las variables locales del método.

Sin embargo, la situación actual funciona bien:

  def fubar(self, x) self.x = x class C: frob = fubar 

aquí cuando se llama como método, frob recibirá el objeto en el que se llama a través del parámetro self , y fubar todavía puede llamarse con un objeto como parámetro y funciona de la misma manera ( es lo mismo que C.frob , creo).

El uso del argumento, convencionalmente llamado self no es tan difícil de entender, ¿por qué es necesario? ¿O por qué lo mencionan explícitamente? Supongo que esa es una pregunta más importante para la mayoría de los usuarios que buscan esta pregunta o, de lo contrario, tendrán la misma pregunta a medida que avanzan en el aprendizaje de python. Les recomiendo leer estos dos blogs:

1: Uso de autoexplicación

Tenga en cuenta que no es una palabra clave.

El primer argumento de cada método de clase, incluido init, es siempre una referencia a la instancia actual de la clase. Por convención, este argumento siempre se llama self. En el método init, self se refiere al objeto recién creado; en otros métodos de clase, se refiere a la instancia cuyo método fue llamado. Por ejemplo, el código de abajo es el mismo que el código de arriba.

2: ¿Por qué lo tenemos de esta manera y por qué no podemos eliminarlo como un argumento, como Java, y tener una palabra clave en su lugar?

Otra cosa que me gustaría agregar es que un argumento self me permite declarar métodos estáticos dentro de una clase, al no escribir self .

Ejemplos de código:

 class MyClass(): def staticMethod(): print "This is a static method" def objectMethod(self): print "This is an object method which needs an instance of a class, and that is what self refers to" 

PD : esto funciona solo en Python 3.x.

En versiones anteriores, tiene que agregar explícitamente el decorador @staticmethod , de lo contrario, self argumento self es obligatorio.

En el método __init__ , self se refiere al objeto recién creado; en otros métodos de clase, se refiere a la instancia cuyo método fue llamado.

yo, como nombre, es solo una convención , llámalo como quieras! pero cuando lo usa, por ejemplo para eliminar el objeto, tiene que usar el mismo nombre: __del__(var) , donde se usó var en el __init__(var,[...])

También deberías echar un vistazo a cls , para tener una imagen más grande . Esta publicación podría ser útil.

Es una referencia explícita al objeto de instancia de clase.