【问题标题】:Do scala classes have "self" like Python?Scala 类有像 Python 一样的“自我”吗?
【发布时间】:2019-02-13 07:38:22
【问题描述】:

例如,如果我有

object Solution {
    class myClass(A: Array[Int]){
        val something: Int = A.length;
        val another: Int = something/2;
        val someName = "blah"
 ...
 ...

这些变量是仅“存在”于 myClass 的特定实例,还是在所有对象之间共享的“类范围”变量?如果是后者,如何使这些变量仅对象?

【问题讨论】:

标签: python scala class


【解决方案1】:

是的,它被实现为this,就像在 Java 或 C++ 中一样。您不必像在 python 中那样在方法调用时显式传递它。

那么您在示例中创建的是实例变量,也称为成员。它们属于类的实例,即它们在所有同一类的所有对象上共享(类变量)。对于后者,您可能需要使用the companion scheme

最后,您可能想阅读更多有关 scala 的信息,例如 this tutorial here,或 @IanAuld 提供的 one for python devs,或运行由 scala 的创建者提供的 scala course on coursera

顺便说一句,欢迎加入 Stack Overflow!


编辑:

所以我在 Scala 中设置它的方式是实例变量,而如果我在 Python 中使用相同的通用方法(在放置方面),它们会是类变量吗?还是说我必须在某处添加“this”才能使它们成为实例变量?

我知道你在哪里感到困惑。 Python 和 Scala 在面向对象编程的方法上非常不同。先说一下python吧:

蟒蛇

Python 的设计理念是类(和模块,顺便说一句)是 dict,在早期版本的 python 中,您甚至可以通过 myclass.__dict__ 成员访问类的成员,而今天,即使这样dict 被实现“隐藏”,它仍然可以通过getattrsetattr 访问。

这个想法是 python 如何处理类的核心,因为一切都是通过 monkey patching 完成的,即在运行时更改并实际定义类定义。

class Foo:
    pass
foo = Foo()
foo.bar = 1
print(foo.bar)

python 中的另一个基本特征是一切都是明确的。这就是为什么在声明方法时,显式将当前类的引用作为参数传递给方法:

class Foo:
    def foobar(self):
        self.bar = 1
print(foo.bar)

但这实际上相当于做:

class Foo:
    pass
def foobar(self):
    self.bar = 1
foo = Foo()
foobar(foo)
print(foo.bar)

以下行为很好地说明了猴子修补的含义:

class Foo:
    def foobar(self):
        print(self.bar)
foo = Foo()
foo.bar = 1
foo.foobar() # prints 1

因此,当您实际在 python 中定义成员时,您真正要做的是用新成员修补当前实例。

现在,当您执行 类实例 时,如果我们使用我告诉过您的 dict 表示,您所做的实际上是如下所示:

Foo = dict(a=1, b=[2]) # class definition with class variables
foo = Foo.copy()       # create instance
foo['b'].append(3)     # use a class variable's instance
print(Foo['b']) # prints: [2,3]

总而言之,python 对 OOP 有一种非常特殊的方法,它完全基于类的行为有点像 dict 并且它们应该被猴子修补来定义的想法(这就是为什么当你创建一个类时,约定是在构造函数中声明所有成员)。这就是为什么 Python 不被视为“纯”面向对象语言的原因(这只是语言的属性,而不是限定)。

斯卡拉

Scala 被定义为纯函数式和纯面向对象语言。语言的这两个属性使它与 python 非常非常不同。我不会深入解释函数式编程,但我强烈建议您学习一门课程并阅读有关它的书籍,并阅读 Scala 以掌握它。

因此,在 Scala 中,当您定义一个类时,您可以执行以下操作(示例由我链接的教程提供):

class Square {
    var x: Double = 0
    var y: Double = 0
    var width: Double = 0
    var height: Double = 0
    def area(): Double = width * height
}

所以你在这里定义了实例变量,你给它们一个“默认”值,这是你在__init__()构造函数中在python中定义的值。然后定义一个方法。

但是因为 scala 是函数式的,所以你可以在类定义处有另一种解读:

class Square(
    private var x: Double,
    private var y: Double,
    private var width: Double,
    private var height: Double
  ) {
    def area(): Double = width * height
  }

Square 是一个函数,它接受参数,并返回一个具有方法的实例,在该函数的范围内定义。那么,外部的“函数”实际上是一个构造函数,内部的函数是方法。

现在,scala 中不存在实际的类变量,为此,您可能更喜欢使用配套设计模式(参见关于它的 SO 答案链接)。

但顺便说一句,因为您在示例中使用的 someName 变量的属性:

class myClass(A: Array[Int]){
    val something: Int = A.length;
    val another: Int = something/2;
    val someName = "blah"

您的 someName 变量是不可变的。这意味着您不能在实例中修改它,因此对于所有实例都是相同的。所以不知何故,它看起来像类变量,即使不是,它们实际上是实例变量。

就像我在 python 中的 dict 示例一样,这并不完全准确,因为还有更多关于这些机制的知识 - 我什至没有在这里触及表面,但它的目的是展示 Scala 之间的巨大差异— 一种函数式/对象语言,而 python — 一种 ? 修补/对象语言。

现在从程序范式语言到函数式范式语言迈出了一大步,感觉就像再次学习开发,但这绝对值得,因为它会教你一种不同的方式思考你的程序,不仅可以学习一门新语言和新范式,还可以通过更好的实践和更关心打字,让你在已经知道的语言中发展得更好。

【讨论】:

  • 所以我在 Scala 中设置它的方式是实例变量,而如果我在 Python 中做了同样的通用方法(在放置方面),它们会是类变量吗?还是说我必须在某处添加“this”才能使它们成为实例变量?
  • 哇,答案真棒。我可能需要一些时间来阅读并吸收它,但这很棒。谢谢!
  • 提示:在scala上做coursera课程,很不错,我自己做过!
  • "这意味着您不能在实例中修改它们,因此它们对于您的所有实例都是相同的。"这不是真的。 somethinganother 取决于构造函数的参数 A,因此它们对于每个实例都可能不同(尽管是不可变的)。
  • and thus it is the same for all your instances: val x: myClass = new myClass(Array(1)){ override val someName = "not blah" }.
猜你喜欢
  • 2014-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多