R——面向对象编程
在本文中,我们将讨论 R 编程语言中的面向对象编程 (OOP)。我们将讨论 S3 和 S4 类、这些类中的继承以及这些类提供的方法。
在 R 编程中,OOP 提供类和对象作为降低和管理程序复杂性的关键工具。 R 是一种使用 OOP 概念的函数式语言。我们可以把一个类想象成一辆汽车的草图。它包含有关 model_name、model_no、engine 等的所有详细信息。根据这些描述,我们选择一辆车。汽车是对象。每个汽车对象都有自己的特点和特点。对象也称为类的实例,创建此对象的过程称为实例化。在 R 中,S3 和 S4 类是面向对象编程的两个最重要的类。但在讨论这些类之前,让我们先简要介绍一下类和对象。
类和对象
类是通过封装数据成员和函数来制作对象的蓝图或原型。对象是一种数据结构,其中包含一些作用于其属性的方法。
S3 级
S3 类没有预定义的定义并且能够调度。在这个类中,泛型函数调用该方法。 S3 的简单实现是可能的,因为它不同于实现面向对象消息传递的传统编程语言Java、C++ 和 C#。
创建 S3 类
要创建此类的对象,我们将创建一个包含所有类成员的列表。然后这个列表作为参数传递给 class() 方法。
句法:
variable_name <- list(attribute1, attribute2, attribute3….attributeN)
例子:
在下面的代码中,定义了一个 Student 类。给出具有属性学生姓名和卷号的适当班级名称。然后创建并调用学生类的对象。
R
# List creation with its attributes name
# and roll no.
a < - list(name="Adam", Roll_No=15)
# Defining a class "Student"
class(a) < - "Student"
# Creation of object
a
R
methods(print)
R
# List creation with its attributes name
# and roll no.
a = list(name="Adam", Roll_No=15)
# Defining a class "Student"
class(a) = "Student"
# Creation of object
print(a)
R
print.Student <- function(obj){
cat("name: " ,obj$name, "\n")
cat("Roll No: ", obj$Roll_No, "\n")
}
print(a)
R
attributes(a)
R
attr(a, "age")<-c(18)
attributes(a)
R
# student function with argument
# name(n) and roll_no(r)
student < - function(n, r) {
value < - list(name=n, Roll=r)
attr(value, "class") < - "student"
value
}
R
# 'print.student' method created
print.student < - function(obj) {
# 'cat' function is used to concatenate
# strings
cat("Name:", obj$name, "\n")
cat("Roll", obj$roll, "\n")}
R
s < - list(name="Kesha", Roll=21, country="India")
# child class 'Student' inherits
# parent class 'student'
class(s) < - c("Student", "student")
s
R
# 'Student' class object is passed
# in the function of class 'student'
print.student < - function(obj) {
cat(obj$name, "is from", obj$country, "\n")
}
s
R
# Function setClass() command used
# to create S4 class containing list of slots.
setClass("Student", slots=list(name="character",
Roll_No="numeric"))
# 'new' keyword used to create object of
# class 'Student'
a <- new("Student", name="Adam", Roll_No=20)
# Calling object
a
R
stud <- setClass("Student", slots=list(name="character",
Roll_No="numeric"))
# Calling object
stud
R
stud(name="Adam", Roll_No=15)
R
# Define S4 class
setClass("student",
slots=list(name="character",
age="numeric", rno="numeric")
)
# Defining a function to display object details
setMethod("show", "student",
function(obj){
cat(obj@name, "\n")
cat(obj@age, "\n")
cat(obj@rno, "\n")
}
)
# Inherit from student
setClass("InternationalStudent",
slots=list(country="character"),
contains="student"
)
# Rest of the attributes will be inherited from student
s < - new("InternationalStudent", name="Adam",
age=22, rno=15, country="India")
show(s)
输出:
$name
[1] "Adam"
$Roll_No
[1] 15
attr(, "class")
[1] "Student"
通用函数
泛型函数是多态性的一个很好的例子。要理解泛型函数的概念,请考虑 print()函数。 print()函数是为 R 编程语言中的不同数据类型和数据结构创建的各种打印函数的集合。它根据作为参数传递的对象类型调用适当的函数。我们可以使用 methods()函数查看打印函数的各种实现。
示例:查看不同类型的打印函数
R
methods(print)
输出:
现在让我们创建一个我们自己的通用函数。我们将为我们的类创建打印函数,它将以我们指定的格式打印所有成员。但在创建打印函数之前,让我们先创建打印函数对我们的类所做的事情。
例子:
R
# List creation with its attributes name
# and roll no.
a = list(name="Adam", Roll_No=15)
# Defining a class "Student"
class(a) = "Student"
# Creation of object
print(a)
输出:
$name
[1] "Adam"
$Roll_No
[1] 15
attr(,"class")
[1] "Student"
现在让我们以我们指定的格式打印所有成员。考虑下面的例子——
例子:
R
print.Student <- function(obj){
cat("name: " ,obj$name, "\n")
cat("Roll No: ", obj$Roll_No, "\n")
}
print(a)
输出:
name: Adam
Roll No: 15
属性
对象的属性不影响对象的值,但它们是用于处理对象的一条额外信息。函数attributes() 可用于查看对象的属性。
示例:创建 S3 对象并显示其属性。
R
attributes(a)
输出:
$names
'name''Roll_No'
$class
'Student'
此外,您可以使用 attr 向对象添加属性。
R
attr(a, "age")<-c(18)
attributes(a)
输出:
$names
'name''Roll_No'
$class
'Student'
$age
18
S3 类中的继承
继承是OOP(面向对象编程)中的一个重要概念,它允许一个类派生另一个类的特性和功能。此功能有助于代码的可重用性。
R 编程语言中的 S3 类没有正式和固定的定义。在 S3 对象中,具有其类属性的列表设置为类名。 S3 类对象仅从其基类继承方法。
例子:
在下面的代码中,继承是使用 S3 类完成的,首先创建的对象是类 student。
R
# student function with argument
# name(n) and roll_no(r)
student < - function(n, r) {
value < - list(name=n, Roll=r)
attr(value, "class") < - "student"
value
}
然后,定义该方法以打印学生的详细信息。
R
# 'print.student' method created
print.student < - function(obj) {
# 'cat' function is used to concatenate
# strings
cat("Name:", obj$name, "\n")
cat("Roll", obj$roll, "\n")}
现在,通过执行class(obj) <- c(child, parent)创建另一个类时完成继承。
R
s < - list(name="Kesha", Roll=21, country="India")
# child class 'Student' inherits
# parent class 'student'
class(s) < - c("Student", "student")
s
输出:
Name: Kesha
Roll: 21
以下代码覆盖了班级学生的方法。
R
# 'Student' class object is passed
# in the function of class 'student'
print.student < - function(obj) {
cat(obj$name, "is from", obj$country, "\n")
}
s
输出:
Kesha is from India
S4班
S4 类有一个预定义的定义。它包含用于定义方法和泛型的函数。它使多次调度变得容易。此类包含用于定义方法和泛型的辅助函数。
创建 S4 类和对象
setClass()命令用于创建 S4 类。以下是 setclass 命令的语法,它表示带有包含名称和 rollno 的插槽的 myclass。
句法:
setClass(“myclass”, slots=list(name=”character”, Roll_No=”numeric”))
new()函数用于创建 S4 类的对象。在这个函数中,我们将传递类名以及插槽的值。
例子:
R
# Function setClass() command used
# to create S4 class containing list of slots.
setClass("Student", slots=list(name="character",
Roll_No="numeric"))
# 'new' keyword used to create object of
# class 'Student'
a <- new("Student", name="Adam", Roll_No=20)
# Calling object
a
输出:
Slot "name":
[1] "Adam"
Slot "Roll_No":
[1] 20
从生成器函数创建 S4 对象
setClass() 返回一个生成器函数,它有助于创建对象,它充当构造函数。
例子:
R
stud <- setClass("Student", slots=list(name="character",
Roll_No="numeric"))
# Calling object
stud
输出:
new(“classGeneratorFunction”, .Data = function (…)
new(“Student”, …), className = structure(“Student”, package = “.GlobalEnv”),
package = “.GlobalEnv”)
现在上面创建的 stud函数将充当 Student 类的构造函数。它将表现为 new()函数。
例子:
R
stud(name="Adam", Roll_No=15)
输出:
An object of class "Student"
Slot "name":
[1] "Adam"
Slot "Roll_No":
[1] 15
S4类中的继承
R 编程中的 S4 类具有适当的定义,派生类将能够从其基类继承属性和方法。为此,我们将首先创建一个具有适当插槽的基类,并为该类创建一个通用函数。然后我们将创建一个派生类,该派生类将使用 contains 参数进行继承。派生类将继承基类的成员和函数。
例子:
R
# Define S4 class
setClass("student",
slots=list(name="character",
age="numeric", rno="numeric")
)
# Defining a function to display object details
setMethod("show", "student",
function(obj){
cat(obj@name, "\n")
cat(obj@age, "\n")
cat(obj@rno, "\n")
}
)
# Inherit from student
setClass("InternationalStudent",
slots=list(country="character"),
contains="student"
)
# Rest of the attributes will be inherited from student
s < - new("InternationalStudent", name="Adam",
age=22, rno=15, country="India")
show(s)
输出:
Adam
22
15
同时定义 S3 和 S4 类的原因如下:
- 如果直接调用 S3 泛型函数,则不会单独看到 S4 类。例如,如果某个函数从一个包中调用unique() ,而该包没有使该函数成为 S4 泛型,就会出现这种情况。
- 但是,原始函数和运算符是例外:当且仅当对象是 S4 对象时,内部 C 代码才会查找 S4 方法。 S4 方法分派将用于分派任何一个操作数是 S4 对象的二元运算符调用。
- 如果有任何符合条件的非默认 S4 方法,则不会单独调用 S3 类。
因此,如果一个包为 S4 类定义了唯一的 S3 方法,但另一个包为该类的超类定义了 S4 方法,则将选择超类方法,可能不是预期的。