Ruby 的 self 与 Python 的 self
可能重复的问题:
Ruby和Python中“self”的区别是什么?
Ruby和Python是两种相似的编程语言,它们都有一个叫做self
的关键词,在不同的情况下会用到。那么在这两种语言中,self
是什么意思呢?它们之间有什么区别呢?
3 个回答
在Python中,my_instance.a_method(an_argument)
其实就是在简化写法,等同于MyClass.a_method(my_instance, an_argument)
。所以,MyClass.a_method
的定义需要接受两个参数:
class MyClass(object):
def a_method(self, an_argument):
print self # self (the instance) is available in the method
正如pst所说,使用变量名self
只是一个约定。你也可以用其他名字,比如:
class MyClass(object):
def a_method(this_instance, an_argument):
print this_instance
这样写一切也能正常工作……不过最好还是不要这样做。
Ruby和Python其实是非常不同的语言(虽然它们有很多相似之处),即使Ruby的语法可以写得像Python(比如用到end
这个关键词);-)
Ruby是基于消息的(它受到了SmallTalk-80的很大影响),在Ruby中,“消息”是发送给对象的。Ruby支持一个隐式接收者(明确来说就是self
),这个接收者在特定的范围内使用。在Ruby中,self
不是一个变量,而是一个表达式,它代表当前对象的上下文。
而Python是基于属性的(因为没有更好的词来形容),所以它更像SELF和JavaScript,因为函数是直接执行的(而不是通过传递消息)。Python没有self
这个关键词,self
只是约定俗成的用法,作为方法第一个参数的名字来使用——这就是Python如何传递当前对象上下文的方式。
祝你编码愉快。
关于Python,我可以告诉你一些基本的知识。这里的self
是作为方法的第一个参数传递的,这是一种约定,就像pst说的那样。来自Python文档
通常,方法的第一个参数叫做self。这只是一种约定:self这个名字对Python没有特别的意义。不过,如果不遵循这个约定,你的代码可能会让其他Python程序员读起来不太容易理解。而且,有可能会有一些工具是依赖这种约定来工作的。
CRuby(或称'MRI')在底层也有类似的东西。每个C扩展可以通过以下方式在Ruby类上定义(模块/类/单例)方法:
- rb_define_method(实例)
- rb_define_singleton_method(单例类)
- rb_define_module_function(类/模块)
这些实际的实现函数总是将VALUE self
作为第一个参数,这与Python的用法类似。在这些情况下,self
指的是接收到特定消息的对象实例,也就是说,如果你有:
person = Person.new
person.do_sth
而do_sth恰好是用C实现的,那么就会有一个对应的C函数:
VALUE
person_do_sth(VALUE self) {
//do something
return self;
}
每个这样的实现必须返回一个VALUE
(Ruby对象的C表示),这是因为在Ruby中,每次方法调用或发送消息(为了保持与Smalltalk的术语一致)都有返回值。Ruby中没有void
函数。
虽然我们在底层的C代码中需要来回传递self
,但在Ruby代码中你不需要这样做,Ruby会为你处理这些。当前self
的值会在执行的当前线程上下文中被内部存储,因此self
的存在是有保障的,消息“self”总是会被评估为某个对象。
由于Ruby的动态特性,self
所引用的对象的实际值会随着当前解释的代码的作用域而变化。你可以运行这个代码来亲自看看:
puts "#{self} - declared in global scope" # the 'top self' aka 'main'
class << self
puts "#{self} - 'main's singleton class" # main's singleton or 'eigenclass'
end
puts "Starting to interpret class A code"
class A
puts "#{self} - When do I get executed!?" # self is class A
class << self
puts "#{self} - And me!?" # now A's singleton class
def a # declaring method in class's singleton class results in class method
puts "#{self} - declared in singleton class" # it's A
end
end
def self.b
puts "#{self} - declared in class method" # self is class A again -> class method
class << self
puts "#{self} - declared in Class A's singleton class" # now it's Class A's singleton class
end
end
def c
puts "#{self} - declared in instance method" # self is instance of A
class << self
puts "#{self} - declared in instance's singleton class" # now it's the A instance's singleton class
end
end
end
puts "All so far has happened simply by interpreting A's code"
a = A.new
A.a
A.b
a.c
如果你想从任何上下文调用方法/发送消息给self
,你可以明确地这样做(例如self.method
),或者你可以省略self
作为接收者——这样,根据约定,消息的隐式接收者将是self
。
有趣的是,Ruby对private
方法的解释与Java的private
概念不同。Ruby的私有方法只能通过使用self
作为隐式接收者来发送消息调用,也就是说:
class A
def a
b
end
private
def b
puts "I'm private"
end
end
a = A.new
a.a # => I'm private
这样可以工作,而将方法a替换为:
def a
self.b
end
则会引发异常。这意味着在Java中很常见的事情
class A {
private boolean compareUs(A a1, A a2) { ... }
public boolean equals(A a1, A a2) {
return (a1.compareUs() == a2.compareUs());
}
}
在Ruby中是行不通的。虽然这个例子有点傻,但只是为了说明这一点:在Java中,我们可以访问同一类的其他实例的私有方法,而在Ruby中这是不可能的,因为我们只能访问当前self
的私有方法。
最后,为了让事情变得更复杂一些,instance_eval
和class_eval
函数在执行过程中也会改变self
的值。