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


¿Cuál es el propósito de la self palabra en Python? Entiendo que se refiere al objeto específico creado a partir de esa clase, pero no veo por qué debe agregarse 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

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

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

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


883
2018-04-25 20:22


origen


Respuestas:


La razón por la que necesitas usar self. es porque Python no usa el @ sintaxis para referirse a atributos de instancia. Python decidió hacer los métodos de una manera que hace que la instancia a la que pertenece el método sea pasado automáticamente, pero no recibido automáticamente: el primer parámetro de métodos es la instancia en la que se llama al método. Eso hace que los métodos sean completamente iguales a las funciones, y deja el nombre real a su altura (aunque self es la convención, y las personas generalmente te fruncen 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 los nombres normales de los atributos: sintaxis especial como Ruby, o requerir declaraciones como C ++ y Java, o quizás algo aún más diferente, pero no fue así. Python es todo para hacer que las cosas sean explícitas, lo que hace obvio qué es qué, y aunque no lo hace en todas partes, sí lo hace, por ejemplo, atributos. Es por eso que la asignación a un atributo de instancia necesita saber a qué instancia asignar, y es por eso que necesita self..


584
2018-04-25 20:25



Tomemos una clase de vector simple:

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

Queremos tener un método que calcula la longitud. ¿Qué aspecto tendrí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 definimos como un método / función global?

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

Entonces toda la estructura permanece igual. ¿Cómo puedo hacer uso de esto? Si asumimos por un momento que no habíamos escrito una length método para nuestro Vector clase, 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 self parámetro en length_new. Esto no sería posible sin un explícito self.


Otra forma de entender la necesidad de lo explícito self es ver donde Python agrega algo de azúcar sintáctica. Cuando lo recuerdas, básicamente, una llamada como

v_instance.length()

se transforma internamente a

Vector.length(v_instance)

es fácil ver dónde está el self encaja. En realidad, no escribe 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, deberá colocar el parámetro de instancia en algún lugar explícitamente.


382
2018-04-28 00:03



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

ClassA.methodA(ObjectA, arg1, arg2)

los self variable se refiere al objeto en sí.


283
2018-01-26 17:31



Cuando los objetos son instanciados, el objeto mismo pasa al parámetro self.

enter image description here

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 los datos de cada objeto. Observe cómo 'self' se reemplaza con el nombre de los objetos. No digo que este diagrama de ejemplo a continuación sea totalmente exacto, pero espero que sirva para visualizar el uso del yo.

enter image description here

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

Aunque 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 propio nombre al parámetro auto, los atributos y métodos de la clase permanecerían como una plantilla general y no se haría referencia a (pertenecer a) el objeto. Por lo tanto, al pasar el nombre del objeto al parámetro auto, significa que si se crean instancias de 100 objetos de una clase, todos pueden realizar un seguimiento de sus propios datos y métodos.

Vea la ilustración a continuación:

enter image description here


151
2018-06-28 05:47



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
2018-04-26 16:02



Voy a demostrar con un 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 forma de evitar pasar todo el tiempo en este estado de "estado" (y otras cosas agradables como inicialización, composición de clases, las metaclases raramente necesarias y métodos de soporte personalizados para anular operadores).

Ahora vamos a demostrar el código anterior usando la maquinaria incorporada de la clase python, 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 una pregunta cerrada duplicada]


33
2018-06-22 00:27



Además de todas las otras razones ya indicadas, permite un acceso más fácil a los métodos anulados; Puedes llamar 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
2018-04-25 20:31



Los siguientes extractos son de Documentación de Python sobre uno mismo:

Como en Modula-3, no hay shorthands [en Python] para hacer referencia a los miembros del objeto desde sus métodos: la función de método se declara con un primer argumento explícito que representa el objeto, que se proporciona 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 sí mismo 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 programadores de Python, y también es concebible que se escriba un programa de navegador de clases que dependa de dicha convención.

Para más información, vea el Tutorial de documentación de Python en las clases.


16
2018-04-25 20:29