R语言基础:S3和S4 class

news/2024/11/8 16:45:23/

用R进行数据处理时,经常出现S4 class的数据类型,或在软件包的帮助文件中描述为S4 class,那么什么是S3和S4 class呢?

参考资源:R语言S3类的理解与构建 - ywliao - 博客园

                  R语言基础教程——第7章:面向对象编程(S4类)

一些程序员认为S3类不具有面向对象编程固有的安全性。例如,你可以任意修改S3类,哪怕是不合法的修改。相比而言,S4类更加安全。

想要更好理解S3和S4 class,最好先明白什么是“面向对象”,尝试了一下,然后就放弃了。。。。。。。

明面意思,class就是类的意思,但是“类”这个概念比较抽象,既包含类型type(S3类、S4类)又包含类名name(“类”的命名)。首先通过S3 class引入“类”的概念

S3 class

S3类数据创建简单,list命令即可创建,且可进行编辑

##创建person,包含name,age,gender等三种属性
> person<-list(name="xiao ming", age=16, gender="M")
> person
$name
[1] "xiao ming"
$age
[1] 16
$gender
[1] "M"##此时person的类名仅是“list”,也就是说仅属于“list”类
> class(person)
[1] "list"

通过append命令添加类名

##append命令添加类名“people”
> class(person) <- append(class(person), "people")
> person
$name
[1] "xiao ming"
$age
[1] 16
$gender
[1] "M"
attr(,"class")
[1] "list"   "people"##此时person同时属于“list”和“people”类
> class(person)
[1] "list"   "people"##数据类型是S3 class
> otype(person)
[1] "S3"

S3类属性访问(数据访问):S3和S4的一大区别就是S3通过$访问不同属性,而S4通过@访问

> person$weight
[1] "75kg"
> person$height
[1] 180

S4 class

S4类的创建

setClass(Class, representation, prototype, contains=character(),validity, access, where, version, sealed, package,S3methods = FALSE, slots)Class: 定义类名
slots: 定义属性和属性类型
prototype: 定义属性的默认值
contains=character(): 定义父类,继承关系
validity: 定义属性的类型检查
where: 定义存储空间
sealed: 如果设置TRUE,则同名类不能被再次定义
package: 定义所属的包

创建一个S4对象实例(ps个人理解:对象等同于“类”,实例等同“变量”,就是将类与变量联系起来)

##pryr包作为辅助工具
install.packages("pryr")
library(pryr)##定义一个S4对象,这个Person类中同时包含name和age两种属性
> setClass("Person",slots=list(name="character",age="numeric"))##实例化为一个Person对象
##new,Generate an Object from a Class
> father<-new("Person",name="F",age=44)
> father
An object of class "Person"
Slot "name":
[1] "F"
Slot "age":
[1] 44##类名
> class(father)
[1] "Person"
attr(,"package")
[1] ".GlobalEnv"
##S4类
> otype(father)
[1] "S4"

访问对象的属性

> setClass("Person",slots=list(name="character",age="numeric"))
> a<-new("Person",name="a")
##访问S4对象的属性
> a@name
[1] "a"
> slot(a, "name")
[1] "a"
> # 错误的属性访问
> a$name
> a[1]
> a[1]

创建一个有继承关系的S4对象

##创建一个S4对象Person,包含name和age两种属性
> setClass("Person",slots=list(name="character",age="numeric"))
##创建Person的子类Son,这个子类中同时包含father,mother,name和age四种属性
> setClass("Son",slots=list(father="Person",mother="Person"),contains="Person")##实例化Person对象(father,mother和son)
> father<-new("Person",name="F",age=44)
> father
An object of class "Person"
Slot "name":
[1] "F"
Slot "age":
[1] 44> mother<-new("Person",name="M",age=39)
> mother
An object of class "Person"
Slot "name":
[1] "M"
Slot "age":
[1] 39##实例化一个Son对象,son中同时包含father,mother,name,age四种属性
> son<-new("Son",name="S",age=16,father=father,mother=mother)
> son
An object of class "Son"
Slot "father":
An object of class "Person"
Slot "name":
[1] "F"
Slot "age":
[1] 44Slot "mother":
An object of class "Person"
Slot "name":
[1] "M"
Slot "age":
[1] 39Slot "name":
[1] "S"
Slot "age":
[1] 16
##son属于Son类
> class(son)
[1] "Son"
attr(,"package")
[1] ".GlobalEnv"

查看对象属性

> # 查看son对象的name属性
> son@name
[1] "S"> # 查看son对象的age属性
> son@age
[1] 16> # 查看son对象的father属性
> son@father
An object of class "Person"
Slot "name":
[1] "F"
Slot "age":
[1] 44> ##可进一步查看son@father中的name和age属性
> son@father@name
[1] "F"##查看son的属性类型,S4类
> otype(son)
[1] "S4"##检查son@name属性类型
> otype(son@name)
[1] "base"##检查son@father属性类型,father为S4类
> otype(son@father)
[1] "S4"##用isS4(),检查S4对象的类型
> isS4(son)
[1] TRUE
> isS4(son@name)
[1] FALSE
> isS4(son@mother)
[1] TRUE

son的数据结构

S4对象的默认值

##创建S4对象
> setClass("Person",slots=list(name="character",age="numeric"))
##属性age为空
> a<-new("Person",name="a")
> a
An object of class "Person"
Slot "name":
[1] "a"Slot "age":
numeric(0)   ##无age属性##设置属性age的默认值20
> setClass("Person",slots=list(name="character",age="numeric"),prototype = list(age = 20))
##属性age为空
> b<-new("Person",name="b")
> b
An object of class "Person"
Slot "name":
[1] "b"Slot "age":
[1] 20      ##默认值20

S4对象的类型检查,检查是否符合类的设定

> setClass("Person",slots=list(name="character",age="numeric"))
##传入错误的age类型
> bad<-new("Person",name="bad",age="abc")
Error in validObject(.Object) : invalid class “Person” object: invalid object for slot "age" in class "Person": got class "character", should be or extend class "numeric"
##设置age的非负检查
> setValidity("Person",function(object) {
+        if (object@age <= 0) stop("Age is negative.")
+    })
Class "Person" [in ".GlobalEnv"]Slots:Name:       name       age
Class: character   numeric
##传入小于0的年龄
> bad2<-new("Person",name="bad",age=-1)Error in validityMethod(object) : Age is negative. 

从一个已经实例化的对象中创建新对象

S4对象,还支持从一个已经实例化的对象中创建新对象,创建时可以覆盖旧对象的值

> setClass("Person",slots=list(name="character",age="numeric"))
##创建一个对象实例n1
> n1<-new("Person",name="n1",age=19);n1
An object of class "Person"
Slot "name":
[1] "n1"
Slot "age":
[1] 19##从实例n1中,创建实例n2,并修改name的属性值
> n2<-initialize(n1,name="n2")
> n2
An object of class "Person"
Slot "name":
[1] "n2"
Slot "age":
[1] 19##从实例n1中,创建实例n3,并修改age的属性值
> n3<-initialize(n1,age=99)
> n3
An object of class "Person"
Slot "name":
[1] "n1"
Slot "age":
[1] 99

S4的泛型函数

S4的泛型函数实现有别于S3的实现,S4分离了方法的定义和实现,如在其他语言中我们常说的接口和实现分离。通过setGeneric()来定义接口,通过setMethod()来定义现实类。这样可以让S4对象系统,更符合面向对象的特征。

通过S4对象系统,把原来的函数定义和调用2步,为成了4步进行:

(1)定义数据对象类型

(2)定义接口函数

(3)定义实现函数

(4)把数据对象以参数传入到接口函数,执行实现函数

通过S4对象系统,是一个结构化的,完整的面向对象实现。

##普通函数的定义和调用
work<-function(x) cat(x, "is working")
work('Conan')##定义Person对象
setClass("Person",slots=list(name="character",age="numeric"))
##定义泛型函数work,即接口
setGeneric("work",function(object) standardGeneric("work"))
##定义work的现实,并指定参数类型为Person对象
setMethod("work", signature(object = "Person"), function(object) cat(object@name , "is working") )##创建一个Person对象a
a<-new("Person",name="Conan",age=16)
##把对象a传入work函数
work(a)
Conan is working

查看S4对象的函数:当我们使用S4对象进行面向对象封装后,我们还需要能查看到S4对象的定义和函数定义。

# 检查work的类型ftype(work)
# 直接查看work函数
work
# 查看work函数的现实定义showMethods(work)
# 查看Person对象的work函数现实
getMethod("work", "Person")
selectMethod("work", "Person")
# 检查Person对象有没有work函数existsMethod("work", "Person")hasMethod("work", "Person")


http://www.ppmy.cn/news/477318.html

相关文章

LQB,手打,at24C02,S7按键保留char数据,S6按键读取char数据,S5存入int数据,S4读取int数据

任务&#xff0c; 将提供的i2c.c和i2c.h文件复制到工程目录路径中&#xff1b; 修改i2c.c和i2c。h的头文件&#xff0c;改为stc15.h 将i2c头文件&#xff0c;延时时间&#xff0c;修改成15单片机的时间&#xff0c;需要乘以10倍以上才行&#xff0c; 不然时序不对 在i2c.h文件…

S4——数组

目录 1. 一维数组的创建和初始化 1.2 一维数组的使用 1.3 一维数组在内存中的存储 2. 二维数组的创建和初始化 2.2 二维数组的使用 2.3 二维数组在内存中的存储 3. 数组越界 4. 数组作为函数参数 4.1 冒泡排序 4.2 数组名是什么&#xff1f; 1. 一维数组的创建 …

Atcoder Beginner Contest 269(A-G)

Atcoder Beginner Contest 269 A - Anyway Takahashi 题目太水了&#xff0c;一年级小朋友都可以做 #include<bits/stdc.h> using namespace std; int main(){int a,b,c,d;cin>>a>>b>>c>>d;cout<<(ab)*(c-d)<<endl;cout<<&…

S4语法整理

1. VALUE type( ... )&#xff0c;DATA(WA) 临时定义类型并且赋值给构造 TYPES:BEGIN OF TY_TAB,ZCHAR1 TYPE C LENGTH 10,ZCHAR2 TYPE C LENGTH 10,ZCHAR3 TYPE C LENGTH 10,ZCHAR4 TYPE C LENGTH 10,END OF TY_TAB.DATA(WA) VALUE TY_TAB( ZCHAR1 1 ZCHAR2 2 ZCHAR3 3 Z…

S4 MIGO屏幕增强

1.创建结构和表 结构&#xff1a;ZSMIGO_ITEM 表类型&#xff1a; 表 &#xff1a;ZTMIGO_ITEM&#xff08;用来保存增强字段的值&#xff09; 2.创建函数组 TOP里的代码&#xff1a; FUNCTION-POOL zfg_migo. "MESSAGE-ID ..* INCLUDE LZFG_MIGOD..…

三星性能测试软件,13款软件压力测试 Galaxy S4性能体验

第1页:前言 第2页:第一轮测试&#xff1a;检阅综合性能 第3页:第二轮测试&#xff1a;考验CPU单元 第4页:第三轮测试&#xff1a;考验GPU单元(一) 第5页:第四轮测试&#xff1a;考验GPU单元(二) 第四轮测试&#xff1a;考验GPU单元(二) 除了这些国内用户耳熟能详的工具外&#…

S4 BP详解

ECC中客户和供应商是分开管理的&#xff0c;这种模式具有部分局限性&#xff1a; 客户和供应商不能是同一实体关系&#xff0c;建两个主数据会造成数据的冗余 客户/供应商只能有一个地址 属性无时间相关性 S4中使用BP业务伙伴模型解决这个问题(代替了传统的FD01/VD01/FK01/…

AntV G6 的坑之——从卡掉渣到满帧需要几步

AntV G6 是一款图可视化与分析开源引擎。《AntV G6 的坑之——XXX》系列文章持续更新中&#xff0c;总结常见问题及神坑解决方案。任何问题可在 GitHub Issue 中提问&#xff0c;求 GitHub Star ⭐️https://github.com/antvis/g6 原文链接&#xff1a;https://g6.antv.antgrou…