为什么你需要在Python方法中明确地拥有“自我”的参数?
在Python中定义一个类的方法时,它看起来像这样:
class MyClass(object): def __init__(self, x, y): self.x = x self.y = y
但是在其他一些语言中,比如C#,你可以引用方法与“this”关联的对象,而不是在方法原型中声明它作为参数。
这是Python中的一个有意的语言devise决策,还是有一些实现细节需要传递“self”作为参数?
我想引用彼得斯的Python的禅宗。 “明确比隐含更好”
在Java和C ++中, this.
'可以被推断出来,除非你有可变的名字,这是不可能的。 所以你有时需要它,有时不需要。
Pythonselect这样做是明确的,而不是基于规则。
另外,由于没有任何暗示或假定,所以部分实现是暴露的。 self.__class__
, self.__dict__
和其他“内部”结构可以通过一种明显的方式获得。
这是为了尽量减less方法和function之间的差异。 它允许您轻松地在元类中生成方法,或者在运行时将方法添加到预先存在的类中。
例如
>>> class C(object): ... 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! >>>
它也(据我所知)使python运行时的实现更容易。
我build议你应该阅读关于这个主题的Guido van Rossum的博客 – 为什么明确的自我必须留下 。
当一个方法定义被修饰时,我们不知道是否自动给它一个“self”参数:修饰器可以把这个函数变成一个静态方法(它没有“self”),或者一个类方法有一个有趣的自我,指的是一个类,而不是一个实例),或者它可以做一些完全不同的事情(编写一个在纯Python中实现'@classmethod'或'@staticmethod'的装饰器是微不足道的)。 如果不知道装饰器是否用隐式的“self”参数赋予方法,那就没有办法了。
我拒绝像特殊框架“@classmethod”和“@staticmethod”这样的黑客。
Python不会强迫你使用“self”。 你可以给它任何你想要的名字。 您只需要记住方法定义头中的第一个参数是对该对象的引用。
也可以这样做:(简而言之,调用Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5)
将会返回12,但是会以最疯狂的方式这样做。
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
当然,这在Java和C#等语言中很难想象。 通过使自引用明确,您可以自由引用任何对象的自引用。 另外,在运行时使用类的这种方式在更多的静态语言中很难做到 – 不一定是好的或坏的。 这只是明确的自我允许所有这些疯狂存在。
此外,想象一下:我们想定制方法的行为(用于分析,或者一些疯狂的黑魔法)。 这可以引导我们思考:如果我们有一个类可以覆盖或控制行为的Method
呢?
那么这里是:
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()
现在: InnocentClass().magic_method()
将按照预期行事。 该方法将与InnocentClass
的innocent_self
参数绑定,并以magic_self
与MagicMethod实例绑定。 怪怪的? 这就像在Java和C#语言中有2个关键字this1
和this1
。 这样的魔法可以让框架做些本来更加冗长的事情。
再次,我不想评论这个东西的道德。 我只是想展示一些没有明确的自我引用就难以做到的事情。
我认为除了“Python的禅”之外,真正的原因是函数是Python中的一等公民。
这基本上使他们成为一个对象。 现在的基本问题是,如果你的函数是对象,那么在面向对象的范例中,当消息本身是对象时,你将如何发送消息给对象?
看起来像一个鸡蛋问题,为了减less这个悖论,唯一可能的方法是将执行的上下文传递给方法或检测它。 但是由于python可以嵌套函数,所以不可能这样做,因为执行的上下文会改变内部函数。
这意味着唯一可能的解决scheme是显式传递“self”(执行的上下文)。
所以我相信这是一个执行问题,禅晚了。
我认为这与PEP 227有关:
类范围中的名称不可访问。 名称在最内层的封闭函数范围中parsing。 如果在嵌套作用域链中出现类定义,则parsing过程将跳过类定义。 这个规则防止了类属性和局部variables访问之间的奇怪的交互。 如果在类定义中发生名称绑定操作,则会在生成的类对象上创build一个属性。 要在一个方法中或嵌套在一个方法中的函数中访问这个variables,必须使用一个属性引用,通过self或者通过类的名字。
还有一个非常简单的答案:根据python的禅意 ,“显性比隐性好”。