我是一名python程序员,这是我与R一起工作的第一天.
我正在尝试用构造函数和三个方法编写一个类,我正在努力.
在python中,它很容易:
class MyClass:
def __init__(self):
self.variableA = 1
self.variableB = 2
def hello(self):
return "Hello"
def goodbye(self):
return "Goodbye"
def ohDear(self):
return "Have no clue"
Run Code Online (Sandbox Code Playgroud)
我找不到任何能告诉我如何在R中做这么简单的事情.如果有人能告诉我一种方法,我会很感激吗?
非常感谢
Ric*_*ton 31
R实际上有很多不同的面向对象的实现.三个原生的(如@jthetzel所述)是S3,S4和Reference Classes.
S3是一个轻量级系统,允许您根据第一个参数的类重载函数.
Reference Classes旨在更接近其他编程语言的类.他们或多或少取代了S4类,它们做同样的事情,但是以更笨拙的方式.
所述R.oo包提供了另一种系统,以及原包装允许面向原型的编程,它是像轻质OOP.OOP包中有第六个系统,但现在已经不存在了.最新的R6软件包"是R内置参考类的一种更简单,更快,更轻的替代品".
对于新项目,您通常只想使用S3和Reference类(或可能是R6).
python类最容易转换为引用类.它们是相对较新的(直到John Chambers完成他们的书),最好的参考是?ReferenceClasses页面.这是一个让你入门的例子.
要定义一个类,请调用setRefClass.第一个参数是类的名称,按照惯例,它应该与您为其分配结果的变量相同.您还需要将lists 传递给参数"fields"和"methods".
有一些怪癖.
initialize.<<-).这会创建一个类生成器:
MyClass <- setRefClass(
"MyClass",
fields = list(
x = "ANY",
y = "numeric",
z = "character"
),
methods = list(
initialize = function(x = NULL, y = 1:10, z = letters)
{
"This method is called when you create an instance of the class."
x <<- x
y <<- y
z <<- z
print("You initialized MyClass!")
},
hello = function()
{
"This method returns the string 'hello'."
"hello"
},
doubleY = function()
{
2 * y
},
printInput = function(input)
{
if(missing(input)) stop("You must provide some input.")
print(input)
}
)
)
Run Code Online (Sandbox Code Playgroud)
然后通过调用生成器对象来创建类的实例.
obj1 <- MyClass$new()
obj1$hello()
obj1$doubleY()
obj2 <- MyClass$new(x = TRUE, z = "ZZZ")
obj2$printInput("I'm printing a line!")
Run Code Online (Sandbox Code Playgroud)
进一步阅读:高级R 的OO现场指南章节
Cas*_*unn 11
我最近编写了python类和R S4类的比较,可以在以下位置找到:
http://practicalcomputing.org/node/80
R和python中的类非常不同,无论是如何声明它们,如何使用它们以及它们如何工作.
根据评论中的mbinette请求,这里是帖子的全文(减去大多数超链接,因为我只有两个权限):
对于任何使用python,C++,java或其他常见的面向对象语言编程的人来说,R中的面向对象编程可能会让人很困惑.遵循本书中Rosetta代码示例的精神,在这里我比较了在python中创建和使用类的代码,以及在R中创建和使用类的代码.
第一层混淆是R有几个不同的系统用于面向对象的编程 - S3,S4和R5.人们面临的第一个决定是选择哪一个来为你的项目选择.S3已经存在时间最长,并且被广泛使用.它的功能在某些关键方面受到限制,但程序员在如何编写类方面具有相当大的灵活性.S4是一个较新的系统,它解决了S3的一些局限性.编码有点复杂和僵化,但最终使用起来更强大.通常,人们在处理已有S3对象的现有代码时使用S3,而从头开始实现新代码则使用S4.例如,许多较新的生物传导器封装用S4编写.Hadley Wickham 对S3,S4和R5进行了精彩的总结在R的其他方面,这是一个很好的教育自己更多关于R中面向对象编程的地方.
在这里,我专注于S4系统.
下面是python中一个简单的Circle类的定义.它有一个__init__()构造函数方法,用于在创建新实例时设置值,一些设置值的方法,一些获取值的方法,以及通过从半径计算直径来修改类实例的方法.
class Circle:
## Contents
radius = None
diameter = None
## Methods
# Constructor for creating new instances
def __init__(self, r):
self.radius = r
# Value setting methods
def setradius(self, r):
self.radius = r
def setdiameter(self, d):
self.diameter = d
# Value getting methods
def getradius(self):
return(self.radius)
def getdiameter(self):
return(self.diameter)
# Method that alters a value
def calc_diameter(self):
self.diameter = 2 * self.radius
Run Code Online (Sandbox Code Playgroud)
创建此类后,创建和使用实例(在ipython中)如下所示:
In [3]: c = Circle()
In [4]: c.setradius(2)
In [5]: c.calc_diameter()
In [6]: c.getradius()
Out[6]: 2
In [7]: c.getdiameter()
Out[7]: 4
Run Code Online (Sandbox Code Playgroud)
该Circle()函数Circle使用由其定义的构造函数创建类的新实例__init__().我们使用该.setradius()方法设置半径值,以及.calc_diameter()从半径计算直径的方法,并更新类实例中的直径值.然后,我们使用我们构建的方法来获取半径和直径的值.我们当然也可以直接访问半径和直径值,使用我们用来调用函数的相同点符号:
In [8]: c.radius
Out[8]: 2
In [9]: c.diameter
Out[9]: 4
Run Code Online (Sandbox Code Playgroud)
与C++,java和许多其他常用语言一样,方法和数据变量都是类的属性.此外,方法具有对数据属性的直接读写访问权限.在这种情况下,该.calc_diameter()方法将直径值替换为新值,而无需更改有关类实例的任何其他内容.
现在对于R中的S4对象,它们非常非常不同.这是R中类似的Circle类:
setClass(
Class = "Circle",
representation = representation(
radius = "numeric",
diameter = "numeric"
),
)
# Value setting methods
# Note that the second argument to a function that is defined with setReplaceMethod() must be named value
setGeneric("radius<-", function(self, value) standardGeneric("radius<-"))
setReplaceMethod("radius",
"Circle",
function(self, value) {
self@radius <- value
self
}
)
setGeneric("diameter<-", function(self, value) standardGeneric("diameter<-"))
setReplaceMethod("diameter",
"Circle",
function(self, value) {
self@diameter <- value
self
}
)
# Value getting methods
setGeneric("radius", function(self) standardGeneric("radius"))
setMethod("radius",
signature(self = "Circle"),
function(self) {
self@radius
}
)
setGeneric("diameter", function(self) standardGeneric("diameter"))
setMethod("diameter",
signature(self = "Circle"),
function(self) {
self@diameter
}
)
# Method that calculates one value from another
setGeneric("calc_diameter", function(self) { standardGeneric("calc_diameter")})
setMethod("calc_diameter",
signature(self = "Circle"),
function(self) {
self@diameter <- self@radius * 2
self
}
)
Run Code Online (Sandbox Code Playgroud)
创建此类后,创建和使用实例(在R交互式控制台中)如下所示:
> a <- new("Circle")
> radius(a) <- 2
> a <- calc_diameter(a)
> radius(a)
[1] 2
> diameter(a)
[1] 4
Run Code Online (Sandbox Code Playgroud)
该new("Circle")调用创建了一个Circle类的新实例,我们将其分配给一个名为的变量a.该radius(a)<- 2行创建了对象a的副本,将radius的值更新为2,然后将a指向新的更新对象.这是通过radius<-上面定义的方法完成的.
我们定义calc_diameter()为Circle类的方法,但请注意,我们不要将它称为类的属性.也就是说,我们不使用类似的语法a.calc_diameter().相反,我们调用calc_diameter()就像任何其他独立函数一样,我们将对象作为第一个参数传递给方法.
另外,我们不只是打电话calc_diameter(a),我们将输出分配给a.这是因为R中的对象作为值传递给函数,而不是引用.该函数获取对象的副本,而不是原始对象.然后在函数内操作该副本,如果您想要修改的对象,则必须执行两项操作.首先,对象必须在函数的最后一行执行(因此self方法定义中的孤独行).在R中,这就像打电话一样return().其次,在调用方法时,必须将更新的值复制回对象变量.这就是全线的原因a <- calc_diameter(a).
在radius(a)和diameter(a)调用执行,我们返回这些值定义的方法.
您也可以像在python中的对象一样直接访问R中对象的数据属性.但是,不使用点符号,而是使用@符号:
> a@radius
[1] 2
> a@diameter
[1] 4
Run Code Online (Sandbox Code Playgroud)
在R中,数据属性称为"槽".在@语法,您可以访问这些数据属性.但是方法怎么样?与python不同,R中的方法不是对象的属性,它们通过setMethod()对特定对象进行操作来定义.方法作用的类由signature参数确定.但是,可以有多个具有相同名称的方法,每个方法都作用于不同的类.这是因为调用的方法不仅取决于方法的名称,还取决于参数的类型.一个熟悉的例子是方法plot().对于用户来说,它看起来有一个plot()函数,但实际上有许多plot()方法都是特定于特定类的.plot().
这到达setGeneric()了类定义中的行.如果使用已存在的名称(例如plot())定义新方法,则不需要它.这是因为setMethod()定义了现有方法的新版本.新版本采用不同的数据类型集,然后是同名的现有版本.但是,如果要使用新名称定义函数,则首先必须声明该函数.setGeneric()处理这个声明,创建一个本质上是一个占位符,然后你迅速覆盖.
python和R中的类之间的差异不仅仅是装饰性的,非常不同的事情发生在幕后,并且每种语言都以不同的方式使用类.但是,有一些事情在R中创建和使用类特别令人沮丧.在R中创建S4类需要更多的输入,其中大部分是冗余的(例如,在上面的示例中,每个方法名称必须指定三次).因为R方法只能通过复制整个对象来访问数据属性,所以一旦对象变大,即使是简单的操作,也会有很大的性能损失.对于修改对象的方法来说,这个问题更加复杂,因为数据必须在进入途中复制一次,然后在出路时复制一次.这些问题可能促成了近期用于数值分析的python工具(如pandas)的普及.也就是说,R仍然是一个强大的工具,它非常适合许多常见问题,而R库的丰富生态系统对于许多分析来说是不可或缺的.
| 归档时间: |
|
| 查看次数: |
4162 次 |
| 最近记录: |