¿Por qué es necesario tener explícitamente el argumento "self" en un método de Python? [duplicar]

Resuelto readonly asked hace 16 años • 10 respuestas

Al definir un método en una clase en Python, se ve así:

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

Pero en algunos otros lenguajes, como C#, tienes una referencia al objeto al que está vinculado el método con la palabra clave "this" sin declararlo como argumento en el prototipo del método.

¿Fue esta una decisión intencional de diseño del lenguaje en Python o hay algunos detalles de implementación que requieren pasar "self" como argumento?

readonly avatar Sep 16 '08 07:09 readonly
Aceptado

Me gusta citar el Zen de Python de Peters. "Lo explícito es mejor que lo implícito".

En Java y C++, ' this.' se puede deducir, excepto cuando tenga nombres de variables que hagan imposible la deducción. Así que a veces lo necesitas y otras no.

Python elige hacer cosas como esta explícitas en lugar de basarlas en una regla.

Además, como no se implica ni se asume nada, se exponen partes de la implementación. self.__class__, self.__dict__y otras estructuras "internas" están disponibles de forma obvia.

S.Lott avatar Sep 16 '2008 00:09 S.Lott

Es para minimizar la diferencia entre métodos y funciones. Le permite generar fácilmente métodos en metaclases o agregar métodos en tiempo de ejecución a clases preexistentes.

p.ej

>>> class C:
...     def foo(self):
...         print("Hi!")
...
>>>
>>> def bar(self):
...     print("Bork bork bork!")
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

También (hasta donde yo sé) facilita la implementación del tiempo de ejecución de Python.

Ryan avatar Sep 16 '2008 00:09 Ryan

Sugiero que uno debería leer el blog de Guido van Rossum sobre este tema: Por qué el yo explícito tiene que permanecer .

Cuando se adorna la definición de un método, no sabemos si darle automáticamente un parámetro 'self' o no: el decorador podría convertir la función en un método estático (que no tiene 'self') o en un método de clase (que tiene un tipo divertido de yo que se refiere a una clase en lugar de una instancia), o podría hacer algo completamente diferente (es trivial escribir un decorador que implemente '@classmethod' o '@staticmethod' en Python puro). No hay forma de dotar al método que se define de un argumento "propio" implícito o no sin saber qué hace el decorador.

Rechazo trucos como '@classmethod' y '@staticmethod' con mayúsculas especiales.

bhadra avatar Nov 21 '2008 06:11 bhadra

También te permite hacer esto: (en resumen, invocar Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5)devolverá 12, pero lo hará de la forma más loca.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Por supuesto, esto es más difícil de imaginar en lenguajes como Java y C#. Al hacer explícita la autorreferencia, eres libre de referirte a cualquier objeto mediante esa autorreferencia. Además, esta forma de jugar con clases en tiempo de ejecución es más difícil de hacer en los lenguajes más estáticos; no es que sea necesariamente buena o mala. Es sólo que el yo explícito permite que exista toda esta locura.

Además, imagine esto: nos gustaría personalizar el comportamiento de los métodos (para crear perfiles o alguna magia negra loca). Esto puede llevarnos a pensar: ¿y si tuviéramos una clase Methodcuyo comportamiento pudiéramos anular o controlar?

Bueno aquí está:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

Y ahora: InnocentClass().magic_method()actuará como se esperaba. El método estará vinculado con el innocent_selfparámetro InnocentClassy con magic_selfla instancia de MagicMethod. ¿Qué raro? Es como tener 2 palabras clave this1y this2en lenguajes como Java y C#. Magia como esta permite que los marcos hagan cosas que de otro modo serían mucho más detalladas.

Nuevamente, no quiero comentar sobre la ética de estas cosas. Sólo quería mostrar cosas que serían más difíciles de hacer sin una autorreferencia explícita.

vlad-ardelean avatar Jul 12 '2015 11:07 vlad-ardelean