在Python中定义类的方法,看起来像这样:
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
但在其他一些编程语言中,例如C#,在方法原型中没有声明“this”关键字作为参数,你就可以引用该方法绑定到的对象。
Python中这种需要传递"self"作为参数的行为是有意为之的语言设计决策还是由于某些实现细节需要?
在Python中定义类的方法,看起来像这样:
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
但在其他一些编程语言中,例如C#,在方法原型中没有声明“this”关键字作为参数,你就可以引用该方法绑定到的对象。
Python中这种需要传递"self"作为参数的行为是有意为之的语言设计决策还是由于某些实现细节需要?
我想引用彼得斯的Python禅宗:“显式优于隐式。”
在Java和C++中,'this.
'可以被推断出来,除非你有一些无法推断的变量名称。 因此,有时需要使用它,有时不需要。
Python选择使这些东西明确而不是基于规则。
此外,由于没有暗示或假设,一些实现细节是公开的。 self.__class__
,self.__dict__
和其他“内部”结构以明显的方式可用。
这是为了最小化方法和函数之间的差异。它允许您在元类中轻松生成方法,或在运行时向预先存在的类添加方法。
例如:
>>> 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!
>>>
据我所知,它还使得 Python 运行时的实现更加容易。
self
关键词(但请注意,这可能会引起困惑,因为JavaScript有一些非常棘手的this
绑定语义)。 - Jonathan Benn我建议大家阅读Guido van Rossum的博客关于这个主题的文章-为什么必须保留明确的 self?
当一个方法定义被装饰时,我们不知道是否要自动给它加上 'self' 参数:装饰器可以把函数变成静态方法(没有 'self'),或者类方法(有一种有趣的 self 引用类而不是实例),或者完全做其他事情(在纯 Python 中编写实现 '@classmethod' 或 '@staticmethod' 的装饰器非常简单)。如果不知道装饰器所做的工作,就无法确定正在定义的方法是否具有隐式的 'self' 参数。
我拒绝像特殊处理 '@classmethod' 和 '@staticmethod' 这样的 hack。
Python不强制使用"self"。你可以给它任何你想要的名字。你只需要记住,方法定义头中的第一个参数是对象的引用。
@staticmethod
就不是这样。 - MarkOuter(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
另外,想象一下:我们想要定制方法的行为(用于分析或一些疯狂的黑魔法)。这会让我们思考:如果我们有一个可以重写或控制其行为的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
参数,并绑定到MagicMethod实例的magic_self
。很奇怪,对吧?这就像在Java和C#等语言中有2个关键字this1
和this2
。这种神奇的功能使得框架能够执行本应更加冗长的任务。
再次说明,我不想评论这些内容的伦理道德。我只是想展示一些没有显式self引用更难实现的事情。
OuterClass.this
来获取外部类的实例,但仍然可以使用this
作为对自身的引用;这与你在Python中所做的非常相似。对于我来说,想象这个过程并不困难,也许这取决于一个人对所涉及语言的熟练程度? - klaarObject self1 = this;
(可以使用Object或其他不太通用的类型)。然后,如果您可以在更高的作用域中访问该变量,则可以访问self1
,self2
,... selfn
。我认为这些应该声明为final或类似的东西,但这可能有效。 - vlad-ardelean任何像obj.meth(args)这样的东西都会变成Class.meth(obj, args)。调用过程是自动的,而接收过程不是(它是显式的)。这就是为什么类中函数的第一个参数必须是对象本身的原因。
class Point(object):
def __init__(self,x = 0,y = 0):
self.x = x
self.y = y
def distance(self):
"""Find distance from origin"""
return (self.x**2 + self.y**2) ** 0.5
调用:
>>> p1 = Point(6,8)
>>> p1.distance()
10.0
init()定义了三个参数,但我们只传递了两个(6和8)。同样,distance()需要一个参数,但没有传递任何参数。
为什么Python不会抱怨这种参数数量不匹配?
通常情况下,当我们用一些参数调用一个方法时,相应的类函数是通过将方法的对象放在第一个参数之前来调用的。所以,任何像obj.meth(args)这样的东西都变成了Class.meth(obj, args)。调用过程是自动的,而接收过程则不是(它是显式的)。
这就是为什么类中函数的第一个参数必须是对象本身的原因。将此参数写为self只是一种惯例。它不是关键字,在Python中没有特殊含义。我们可以使用其他名称(如this),但我强烈建议你不要这样做。大多数开发人员都不赞成使用self以外的名称,并且会降低代码的可读性(“可读性很重要”)。
...
在第一个示例中,self.x是一个实例属性,而x是一个局部变量。它们不相同,位于不同的命名空间中。
自引用是必须的
许多人提议在Python中将self作为关键字,就像C++和Java一样。这将消除方法形式参数列表中显式self的冗余使用。虽然这个想法似乎很有前途,但它不会发生。至少在短期内不会发生。主要原因是向后兼容性。这是Python创始人的博客,解释为什么需要保留显式self。
'self'参数保存当前调用的对象。
class class_name:
class_variable
def method_name(self,arg):
self.var=arg
obj=class_name()
obj.method_name()
在这里,self参数持有对象obj。因此,语句self.var表示obj.var。