我读过某个地方,在Python中使用“ 自我”会转换myobject.method (arg1, arg2)
进入MyClass.method(myobject, arg1, arg2)
。
有人知道我能证明这一点吗?
我只能使用dis.dis
查看字节码吗?
答案 0 :(得分:1)
自我不执行任何操作。 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
这向您展示了“自我”背后的魔力仅仅是函数对象是描述符,它们实现了__get__
方法,该方法可以在没有实例的情况下返回函数本身,或者返回绑定第一个参数的方法对象。
答案 1 :(得分:0)
在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
装饰器),可以避免使用该额外参数。