¿Cuál es el propósito del yo?


¿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é necesita agregarse explícitamente a cada función como un parámetro. Para ilustrar, en Ruby puedo hacer esto:

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

Lo cual entiendo, muy fácilmente. Sin embargo, en Python necesito incluir self:

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

¿Puede alguien hablarme de esto? No es algo que me haya encontrado en mi (ciertamente limitada) experiencia.

Author: kmario23, 2010-04-26

19 answers

La razón por la que necesita usar self. es porque Python no usa la sintaxis @ para referirse a atributos de instancia. Python decidió hacer métodos de manera que la instancia a la que pertenece el método sea pasada automáticamente, pero no recibida 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 lo use usted (aunque self es la convención, y la gente generalmente frunce el ceño cuando usas otra cosa.) self no es especial para el código, es solo otro objeto.

Python podría haber hecho algo más para distinguir nombres normales de atributos syntax sintaxis especial como Ruby tiene, o requiriendo declaraciones como C++ y Java hacer, o tal vez algo aún más diferente but pero no lo hizo. Python es todo para hacer las cosas explícitas, haciendo obvio qué es qué, y aunque no lo hace del todo en todas partes, lo hace por ejemplo atributos. Es por eso que asignar a un atributo de instancia necesita saber a qué instancia asignar, y es por eso que necesita self..

 600
Author: Thomas Wouters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-27 23:01:28

Tomemos una clase vectorial simple:

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

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

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

¿Cómo debería ser cuando debiéramos definirlo 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 permanece igual. ¿Cómo puedo hacer uso de esto? Si asumimos por un momento que no habíamos escrito un método 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 ser reutilizado 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 lo explícito self es ver dónde Python agrega algo de azúcar sintáctica. Cuando se tiene en cuenta, que 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 escribes 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á que colocar el parámetro de instancia en algún lugar explícitamente.

 386
Author: Debilski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-15 06:40:38

Digamos que tienes 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 llama ObjectA.methodA(arg1, arg2), python lo convierte internamente para usted como:

ClassA.methodA(ObjectA, arg1, arg2)

La variable self se refiere al objeto en sí.

 292
Author: Arjun Sreedharan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-18 16:10:51

Cuando se instancian objetos, el objeto en sí se pasa al parámetro self.

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 lo que podrían ser los datos de cada objeto. Observe cómo 'self' se reemplaza con el nombre de los objetos. No estoy diciendo que este diagrama de ejemplo a continuación sea totalmente preciso, pero espero que sirva a un propósito en la visualización del uso del yo.

introduzca la descripción de la imagen aquí

El Objeto es pasado al parámetro self para que el objeto pueda mantener sus propios datos.

Aunque esto puede no ser totalmente exacto, piense en el proceso de instanciación de un objeto como este: Cuando se crea un objeto, utiliza la clase como una plantilla para sus propios datos y métodos. Sin pasar su propio nombre en el parámetro self, los atributos y métodos de la clase permanecerían como una plantilla general y no serían referenciados (pertenecerían) al objeto. Pasando el nombre del objeto en el parámetro self significa que si se instancian 100 objetos de la clase one, todos pueden realizar un seguimiento de sus propios datos y métodos.

Ver la siguiente ilustración:

introduzca la descripción de la imagen aquí

 157
Author: sw123456,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-28 05:47:02

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: []
 65
Author: kame,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-26 16:02:48

Demostraré con código que no usa 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 manera de evitar pasar en este "estado" todo el tiempo (y otras cosas buenas como inicialización, composición de clases, las metaclases rara vez necesarias, y el apoyo a los métodos personalizados para anular los operadores).

Ahora vamos a demostrar el código anterior utilizando la maquinaria de clase python incorporada, para mostrar cómo es básicamente la misma cosa.

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 del duplicado pregunta cerrada]

 33
Author: ninjagecko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 00:27:23

Así como todas las otras razones ya mencionadas, permite un acceso más fácil a los métodos reemplazados; puede llamar a Class.some_method(inst).

Un ejemplo de dónde 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"
 17
Author: Ponkadoodle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-24 22:23:49

Los siguientes extractos son de la documentación de Python sobre self :

Como en Modula-3, no hay abreviaturas [en Python] para hacer referencia a los miembros del objeto desde sus métodos: la función method se declara con un primer argumento explícito que representa el objeto, que es proporcionado implícitamente por la llamada.

A menudo, el primer argumento de un método se llama self. Esto no es más que una convención: el nombre de sí mismo no tiene absolutamente ninguna especial significado de Python. Tenga en cuenta, sin embargo, que al no seguir la convención, su código puede ser menos legible para otros programadores de Python, y también es concebible que se escriba un programa 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 clases.

 16
Author: Matthew Rankin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-26 14:09:29

Python no es un lenguaje construido para la Programación Orientada a Objetos a diferencia de Java o C++.

Cuando se llama 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 self

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

El método self 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 animalName variable de toda la clase. RECUERDE: Si tiene una variable dentro de un método, self no funcionará. Esa variable simplemente existe solo mientras ese método se está ejecutando. Para definir campos (las variables de toda la clase), debe definirlos FUERA de los métodos de la clase.

Si usted no entiende una sola palabra de lo que estoy diciendo, entonces Google "Programación orientada a objetos."Una vez que entiendas esto, ni siquiera necesitarás hacer esa pregunta :).

 11
Author: ytpillai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-21 18:39:06

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

 10
Author: Gaurav Nishant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-27 09:47:48

Está ahí para seguir el zen de Python "lo explícito es mejor que lo 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 a él mediante self.user_type_name.

 7
Author: dan-klasson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-24 22:24:58

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

 4
Author: Ming-Tang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-25 20:26:35

Me sorprende que nadie haya mencionado a Lua. Lua también utiliza la variable 'self', sin embargo, puede ser omitida, pero todavía se utiliza. C++ hace lo mismo con 'esto'. No veo ninguna razón para tener que declarar 'self' en cada función, pero aún así debería poder usarlo como puede con lua y C++. Para un lenguaje que se enorgullece de ser breve, es extraño que requiera declarar la variable self.

 3
Author: user441521,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-12 18:10:32

Es porque por la forma en que python está diseñado las alternativas difícilmente funcionarían. Python está diseñado para permitir que los métodos o funciones se definan en un contexto donde tanto implícito this (a-la Java/C++) o explícito @ (a-la ruby) no funcionarían. Veamos 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 asumiría que self es una variable global (y en frob también). La alternativa sería ejecutar métodos con un ámbito 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 en frob también). La alternativa aquí sería ejecutar métodos con un ámbito local reemplazado que se conserva entre llamadas, pero eso eliminaría la posibilidad de variables locales de métodos.

Sin embargo, la situación actual funciona bien:

 def fubar(self, x)
     self.x = x

 class C:
     frob = fubar

Aquí cuando called as a method frob recibirá el objeto en el que se llama a través del parámetro self, y fubartodavía se puede llamar con un objeto como parámetro y trabajar de la misma manera ( es lo mismo que C.frob creo).

 2
Author: skyking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-27 07:31:02

En primer lugar, self es un nombre convencional, podrías poner cualquier otra cosa (siendo coherente) en su lugar.

Se refiere al objeto en sí, por lo que cuando lo estás usando, estás declarando eso .name y .age son propiedades de los objetos de Student (nota, no de la clase Student) que vas 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í

 2
Author: harrypotter0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-12 04:45:25

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.

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

Usted debe echar un vistazo a cls también, para tener el panorama general. Este post podría ser útil.

 1
Author: TheEnglishMe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:30

Echa 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  

self se usa / se necesita para distinguir entre instancias.

 1
Author: kmario23,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-15 07:54:27

El uso del argumento, convencionalmente llamado self no es tan difícil de entender, como es por qué es necesario? ¿O por qué mencionarlo explícitamente? Eso, supongo, es una pregunta más grande para la mayoría de los usuarios que buscan esta pregunta, o si no lo es, seguramente tendrán la misma pregunta a medida que avanzan aprendiendo python. Les recomiendo leer este par de blogs:

1: Uso de la autoexplicación

Tenga en cuenta que no es una palabra clave.

La primera el argumento de cada método de clase, incluyendo 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 siguiente código es el mismo que el código anterior.

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 añadir es, un argumento opcional 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"

PS:Esto solo funciona en Python 3.x.

En versiones anteriores, hay que añadir explícitamente @staticmethod decorador, de lo contrario self argumento es obligatorio.

 1
Author: Bugs Buggy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-12 10:20:06

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

 -2
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-25 20:24:57