Ruby 的 self 与 Python 的 self

11 投票
3 回答
2360 浏览
提问于 2025-04-16 21:23

可能重复的问题:
Ruby和Python中“self”的区别是什么?

Ruby和Python是两种相似的编程语言,它们都有一个叫做self的关键词,在不同的情况下会用到。那么在这两种语言中,self是什么意思呢?它们之间有什么区别呢?

3 个回答

9

在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

这样写一切也能正常工作……不过最好还是不要这样做。

14

Ruby和Python其实是非常不同的语言(虽然它们有很多相似之处),即使Ruby的语法可以写得像Python(比如用到end这个关键词);-)

Ruby是基于消息的(它受到了SmallTalk-80的很大影响),在Ruby中,“消息”是发送给对象的。Ruby支持一个隐式接收者(明确来说就是self),这个接收者在特定的范围内使用。在Ruby中,self 不是一个变量,而是一个表达式,它代表当前对象的上下文。

而Python是基于属性的(因为没有更好的词来形容),所以它更像SELF和JavaScript,因为函数是直接执行的(而不是通过传递消息)。Python没有self这个关键词,self只是约定俗成的用法,作为方法第一个参数的名字来使用——这就是Python如何传递当前对象上下文的方式。

祝你编码愉快。

9

关于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_evalclass_eval函数在执行过程中也会改变self的值。

撰写回答