【问题标题】:How can I explicitly see what 'self' does in python?我怎样才能明确地看到'self'在python中做了什么?
【发布时间】:2019-03-12 04:17:09
【问题描述】:

我在某处读到,在 Python 中使用“self”会转换 myobject.method (arg1, arg2) 进入MyClass.method(myobject, arg1, arg2)

有谁知道我如何证明这一点? 只有当我使用dis.dis查看字节码时才有可能吗?

【问题讨论】:

  • 转换不是由python进行的,而是由method对象本身进行的,它应该是一个用户定义的函数对象,或者实现适当的描述符协议,它返回一个“实例方法”类型的对象。该对象在调用时确实执行了您描述的替换。

标签: python python-3.x


【解决方案1】:

self 什么都不做。 self 只是 Python 类定义中方法的第一个参数的常规名称。这个参数将被传递一个类的实例。

本质上,要了解实际发生的情况,您必须了解 Python 描述符。最好的地方是官方docs 简而言之,描述符对象是实现__get____set____delete__ 的对象。这些方法拦截对象属性访问obj.x、对象属性赋值obj.x = 42和对象属性删除del obj.x

另外,查看HOWTO,他们在其中展示了 Python functions and methods are simply descriptors,并展示了 Python 实现示例(当然,在 CPython 中,这是在 C 中实现的):

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        if obj is None:
            return self
        return types.MethodType(self, obj)

我们可以“作弊”并创建我们自己的对象,该对象仅包装一个函数对象,并看到这是有效的。

import types
class Function:
    def __init__(self, func):
        self._func = func
    def __call__(self, *args, **kwargs):
        return self._func(*args, **kwargs)
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c https://docs.python.org/3/howto/descriptor.html#functions-and-methods"
        if obj is None:
            return self
        else:
            return types.MethodType(self, obj)

class Foo:
   def __init__(self):
       self.foo = 42
   bar = Function(lambda self:
       self.foo ** 2

和或,在 REPL 中:

>>> import types
>>>
>>> class Function:
...     def __init__(self, func):
...         self._func = func
...     def __call__(self, *args, **kwargs):
...         return self._func(*args, **kwargs)
...     def __get__(self, obj, objtype=None):
...         "Simulate func_descr_get() in Objects/funcobject.c https://docs.python.org/3/howto/descriptor.html#functions-and-methods"
...         if obj is None:
...             return self
...         else:
...             return types.MethodType(self, obj)
...
>>> class Foo:
...    def __init__(self):
...        self.foo = 42
...    bar = Function(lambda self:
...        self.foo ** 2
...    )
...
>>> Foo().bar()
1764

这向您展示了“self”背后的魔力仅仅是函数对象是描述符,它们实现了一个__get__ 方法,如果在没有实例的情况下调用该函数本身,或者返回一个绑定第一个参数的方法对象。

【讨论】:

    【解决方案2】:

    在 IDLE 中亲自尝试可以帮助您解决这个问题:

    class MyObject(object):
      def method(self, arg1, arg2):
         print(self)
    
      @staticmethod
      def static_method(arg1, arg2):
         print(arg1)
    
    my_object = MyObject()
    my_object.method(1, 2)
    >>> <MyObject at 0x1234>
    my_object.static_method(1, 2)
    >>> 1
    

    Python 不转换任何东西,它只是默默地将类实例作为第一个参数传递给类方法。上面你可以看到你是否将方法设为静态(通过@staticmethod 装饰器),你避免了那个额外的参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 2021-11-25
      • 2012-05-09
      • 2017-05-28
      • 1970-01-01
      • 2022-11-21
      相关资源
      最近更新 更多