[Программирование, Data Mining, ООП, R, Data Engineering] ООП в языке R (часть 2): R6 классы
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В прошлой публикации мы разобрали S3 классы, которые являются наиболее популярными в языке R.
Теперь разберёмся с R6 классами, которые максимально приближённые к классическому объектно ориентированному программированию.
Содержание
Если вы интересуетесь анализом данных возможно вам будут интересны мои telegram и youtube каналы. Большая часть контента которых посвящены языку R.
- Введение
- Правила именования
- Создаём собственный класс
- Цепочка методов
- Методы $initialize() и $print()
- Добавление новых свойств и методов в класс после его определение, метод $set()
- Наследование
- Приватные методы и свойства
- Активные методы
- Финализатор класса
- Добавление R6 классов в пакет
- Полезные ссылки
- Заключение
Введение
В этой статье мы не будем останавливать на определении термина объектно — ориентированное программирование, и на его принципах, т.е. наследовании, инкапсуляции и полиморфизме.
R6 будут наиболее понятны пользователям Python, и тем кто привык к классическому ООП. В отличие от S3 классов, у R6 методы привязаны к самим объектам, в то время как у S3 всё строится на обобщённых (generic) функциях.
Итак, всё-таки небольшой глоссарий по ООП я предоставлю:
- Класс — это шаблон, по которому мы можем создавать некоторые объекты. Например, классом может быть кот, собака, автомобиль и так далее.
- Экземпляр класса — если класс это шаблон, в нашем случае пусть это будет кот, то экземпляр класса это конкретный объект созданный по шаблону. Т.е. мы можем создать любое количество котов, по созданному ранее шаблону.
- Свойства класса — это переменные которые хранят информацию о каждом отдельном экземпляре класса, например кличка и порода кота.
- Методы класса — это функции которые хранятся внутри класса, ну к примеру кот может есть, играться и так далее, всё это будут его методы.
Для работы с R6 классами вам необходимо изначально установить и подключить одноимённый пакет R6.
install.packages("R6")
library(R6)
Правила именования
Вам необязательно придерживаться данных правил, но они являются общепринятыми:
- Имена классов задаются в UpperCamelCase.
- Имена методов объектов, и его свойства задаются в snake_case.
Так же как и в Python, методы класса могут получить доступ к другим его методам и свойствам через конструкцию self$method().
Создаём собственный класс
Из пакета R6 вы будете использовать всего одну функцию R6Class(). Основные её аргументы:
- classname — имя класса, должно соответствовать переменной, в которую вы записываете класс;
- public — принимает список (list()) с публичными свойствами и методами класса.
library(R6)
# создаём класс Cat
Cat <- R6Class(classname = "Cat",
public = list(
name = "Tom",
breed = "Persian",
age = 3,
rename = function(name = NULL) {
self$name <- name
invisible(self)
},
add_year = function(ages = 1) {
self$age <- age + ages
invisible(self)
}
)
)
Мы создали класс Cat, с тремя свойствами name, breed и age, и двумя методами $rename() и $add_year(). Метод $rename() меняет свойство name, как я писал ранее к свойству метод может обращаться через self$name, а метод $add_year() увеличивает возраст кота на заданное количество лет.
Для создания экземпляра класса необходимо использовать встроенный метод $new():
# инициализируем объект класса Cat
tom <- Cat$new()
# смотрим результат
tom
<Cat>
Public:
add_year: function (ages = 1)
age: 3
breed: Persian
clone: function (deep = FALSE)
name: Tom
rename: function (name = NULL)
Используем метод $rename():
# используем метод rename
tom$rename('Tommy')
# смотрим результат
tom
<Cat>
Public:
add_year: function (ages = 1)
age: 3
breed: Persian
clone: function (deep = FALSE)
name: Tommy
rename: function (name = NULL)
Как видите объекты созданные с помощью R6 классов меняют свои компоненты на лету, т.е. нет необходимости создавать копии этих объектов.
Т.к. мы создали класс с публичными методами и свойствами то мы имеем к ним доступ вне класса, и соответственно можем их изменять.
# меняем свойство
tom$name <- 'Tom'
# смотрим результат
tom
<Cat>
Public:
add_year: function (ages = 1)
age: 3
breed: Persian
clone: function (deep = FALSE)
name: Tom
rename: function (name = NULL)
Цепочка методов
Если вы обратили внимание, то при создании методов мы всегда скрываем объект self с помощью оператора invisible(self). Это делается для того, что бы мы могли использовать цепочку методов:
# используем цепочку методов
tom$add_year(1)$add_year(3)
# смотрим результат
tom
<Cat>
Public:
add_year: function (ages = 1)
age: 7
breed: Persian
clone: function (deep = FALSE)
name: Tom
rename: function (name = NULL)
Опять же такой подход хорошо знаком пользователям Python и JavaScript.
Методы $initialize() и $print()
Важные методы, которые вы наверняка будете использовать при создании R6 классов это методы $initialize() и $print().
Метод $initialize() переопределяет стандартное поведение метода $new(), т.е. используя его вы можете отдельно прокидывать в создаваемый экземпляр класса данные, например имя, породу и возраст кота.
$print() переопределяет метод печати объекта в консоли.
# создаём класс Cat
Cat <- R6Class(classname = "Cat",
public = list(
name = NA,
breed = NA,
age = 0,
initialize = function(name, breed, age) {
self$name <- name
self$breed <- breed
self$age <- age
},
print = function(...) {
cat("<Cat>: \n")
cat(" Name: ", self$name, "\n", sep = "")
cat(" Age: ", self$age, "\n", sep = "")
cat(" Breed: ", self$breed, "\n", sep = "")
invisible(self)
},
rename = function(name = NULL) {
self$name <- name
invisible(self)
},
add_year = function(ages = 1) {
self$age <- self$age + ages
invisible(self)
}
)
)
# создаём экземпляр класса
tom <- Cat$new(name = 'Tom',
breed = 'Scottish fold',
age = 1)
# смотрим результат
tom
<Cat>:
Name: Tom
Age: 1
Breed: Scottish fold
Добавление новых свойств и методов в класс после его определение, метод $set()
Даже после определения класса вы в любой момент можете добавить в него свойства или методы, используя метод $set() и указав уровень приватности.
Ниже приведён пример кода, в котором мы сначала создаём класс с основными методами, после чего через метод $set() добавляем методы $rename() и $add_year().
# создаём класс Cat
Cat <- R6Class(classname = "Cat",
public = list(
name = NA,
breed = NA,
age = 0,
initialize = function(name, breed, age) {
self$name <- name
self$breed <- breed
self$age <- age
},
print = function(...) {
cat("<Cat>: \n")
cat(" Name: ", self$name, "\n", sep = "")
cat(" Age: ", self$age, "\n", sep = "")
cat(" Breed: ", self$breed, "\n", sep = "")
invisible(self)
}
)
)
# добавляем метод rename
Cat$set( 'public',
'rename',
function(name = NULL)
{
self$name <- name
invisible(self)
})
# добавляем метод add_year
Cat$set( 'public',
'add_year',
function(ages = 1) {
self$age <- self$age + ages
invisible(self)
})
При этом, добавленные методы никак не изменят созданные до их добавления экземпляры класса, а будут распространяться лишь на те экземпляры класса, которые будут созданы после их добавления в класс.
Так же вы можете запретить переопределение методов класса, используя при его создании аргумент lock_class = TRUE. В дальнейшем это поведение можно изменить, и разблокировать класс методом $unlock(), и опять заблокировать методом $lock().
# Создаём класс с блокировкой переопределения методов
Simple <- R6Class("Simple",
public = list(
x = 1,
getx = function() self$x
),
lock_class = TRUE
)
# При попытке переопределить метод мы получим ошибку
Simple$set("public", "y", 2)
# Разблокируем класс
Simple$unlock()
# Теперь мы можем переопределять существующие свойства и методы класса
Simple$set("public", "y", 2)
# Повторно блокируем класс
Simple$lock()
Пример кода взят из официальной документации к пакету R6, автор Winston Chang
Наследование
R6 классы поддерживают механизм наследования, т.е. вы можете создавать супер классы и подклассы, которые будут наследовать от супер классов методы и свойства. При необходимости вы можете переопределять методы супер класса.
На изображении класс "Животные" является главным супер классом, его подклассом являются "Домашние животные" и "Дикие животные", т.е. они наследуют все свойства и методы класса (шаблона) животные, но могут их переопределять, а так же могут иметь свои дополнительные методы и свойства.
Далее мы создаём подклассы "Кот" и "Собака", для которых класс "Домашние животные" уже будет родительским, т.е. супер классом. Так же мы создаём классы "Олень" и "Медведь", для которых супер классом будет "Дикие животные".
Эту цепочку можно было продолжить породами котов, собак, оленей и медведей.
Для реализации наследования в R6 классах необходимо использовать аргумент inherit.
library(R6)
# создаём супер класс Cat
Cat <- R6Class(classname = "Cat",
public = list(
name = NA,
breed = NA,
age = 3,
initialize = function(name, breed, age) {
self$name <- name
self$breed <- breed
self$age <- age
},
rename = function(name = NULL) {
self$name <- name
invisible(self)
},
add_year = function(ages = 1) {
self$age <- self$age + ages
invisible(self)
}
)
)
# создаём подкласс ScottishCat
ScottishCat <- R6Class("ScottishCat",
inherit = Cat,
public = list(
breed = "Scottish Fold",
add_year = function() {
cat("Увеличили возраст ", self$name, " на 1 год", sep = "")
super$add_year(ages = 1)
},
initialize = function(name, age, breed = "Scottish Fold") {
self$name <- name
self$breed <- breed
self$age <- age
}
)
)
# создаём экземпляр класса
scottish <- ScottishCat$new(name = 'Arnold', age = 1)
# используем метод подкласса
scottish$add_year()
В данном примере мы создали супер класс Cat, и подкласс ScottishCat. В подклассе мы переопредели метод $add_year(), тем не менее, мы можем внутри подкласса использовать унаследованные от супер класса методы обращаясь к ним через super$method().
Приватные методы и свойства
В аргумент public функции R6Class() мы передаём методы и свойства класса с общим доступом, т.е. эти методы и свойства доступны как внутри класса, так и за его пределами.
Так же вы можете создавать приватные свойства и методы, которые будут доступны исключительно внутри класса. Такие свойства и методы необходимо передавать в аргумент private, внутри класса доступ к приватным методам и свойствам осуществляется через private$methode_name.
library(R6)
# создаём класс
User <- R6Class('User',
public = list(
name = NA,
initialize = function(name, password, credits = 100) {
self$name <- name
private$password <- password
private$credits <- credits
},
print = function(...) {
cat("<User>: ", self$name, sep='')
},
get_credits = function() {
cat(private$credits)
}
),
private = list(
password = NULL,
credits = NULL
)
)
# экземпляр класса
user_1 <- User$new('Alex', 'secretpwd')
# метод который использует приватное свойство
user_1$get_credits()
100
В данном случае мы получили значение приватного свойства credits через специальный метод. Но если мы напрямую попробуем обратиться к данному свойству, то у нас ничего не получится:
# обращение к приватному свойству вне класса
user_1$credits
NULL
Активные методы
Активные методы для пользователя выглядят как свойства, но при обращении к ним они выполняют заданную функцию.
При каждом обращении к активному методу будет выполняться определённая функция, это удобно к примеру для запуска генератора случайных чисел, или выбора случайного значения из вектора.
Давайте вернёмся к нашему коту, и напишем класс, в котором будет свойство dictionary, в котором будет вектор звуков, которые может воспроизводить кот. И активный метод $say(), который случайным образом будет выводить одну из заданных фраз.
library(R6)
# создаём класс Cat
Cat <- R6Class(classname = "Cat",
public = list(
name = NA,
breed = NA,
dictionary = NA,
initialize = function(name, breed, dictionary) {
self$name <- name
self$breed <- breed
self$dictionary <- dictionary
}
),
active = list(
say = function(value) {
if (missing(value)) {
return(paste0(self$name, ' say ', sample(self$dictionary, size = 1)))
} else {
self$dictionary <- value
}
}
)
)
# создаём экземпляр класса
cat <- Cat$new('Tom',
'Persian',
c('meow', 'mrrr', 'frrr'))
# запускаем активный метод
cat$say
[1] "Tom say meow"
Как видите к активным методам мы обращаемся как к свойствам, т.е. без скобок и аргументов, но при этом выполняется функция say.
В функции мы реализовали проверку if (missing(value)), т.е. мы проверяем если идёт обращение к активному методу, то мы просто выводим случайную фразу из self$dictionary. Если в активный метод передать значение, то будет выполняться условие else, в нашем случае переопределение self$dictionary.
# переопределяем свойство
cat$say <- c('grrr', 'waw', 'chfw')
# используем активный метод
cat$say
"Tom say grrr"
Финализатор класса
Вы можете добавить в класс специальный метод $finalize, который будет запускаться после удаления объекта при завершении R сессии.
Это полезно в тех случаях когда ваш класс работает с файлами или базами данных, тогда вы можете написать финализатор для того, что бы быть уверенным, что соединение с файлом или базой будет разорвано.
TemporaryFile <- R6Class("TemporaryFile", list(
path = NULL,
initialize = function() {
self$path <- tempfile()
},
finalize = function() {
message("Cleaning up ", self$path)
unlink(self$path)
}
))
Пример кода взят из книги Advanced R, автор Hadley Wickham
Добавление R6 классов в пакет
Ещё одно отличие R6 классов от S3 заключается в том, что вам не надо прописывать ваши R6 классы в фале NAMESPACE. Достаточно просто включить пакет R6 в поле Imports файла DESCRIPTION.
Полезные ссылки
Данная статья не является свободным переводом какой-либо англоязычной публикации, но при её написании я пользовался следующими источниками:
Заключение
Как вы убедились R6 классы это реализация классического объектно ориентированного программирования в языке R.
Тем не менее данные класс используется в R достаточно редко, т.к. родной, и общепринятой реализацией ООП в R по-прежнему считаются S3 классы.
Подписывайтесь на мой канал R4marketing в Telegram и YouTube.
===========
Источник:
habr.com
===========
Похожие новости:
- [Управление разработкой, Управление проектами, Управление продуктом] Delivery Club x GIST
- [Информационная безопасность, Big Data, Data Engineering] Модели угроз в дифференциальной приватности (перевод)
- [.NET, Конференции] Программа DotNext: архитектура, Мигель де Икаса, традиции коренных народов Севера
- [IT-инфраструктура, DevOps, Микросервисы] Деплой на стороне разработчиков: как мы создавали Heroku для внутренних нужд
- Релиз фреймворка для создания установщиков Calamares 3.2.33
- Атака NAT slipstreaming для отправки запросов на внутренний IP
- [Разработка веб-сайтов, JavaScript, Программирование] Пример практического использования модулей
- [Информационная безопасность, Управление разработкой, Управление продуктом, Софт] Жизнь до и после Scrum в разработке B2B продуктов
- [IT-инфраструктура, Управление продажами, Управление персоналом] ТОП-4 зависимости между KPI входящей линии контакт-центра, которые должен знать каждый руководитель
- [Информационная безопасность, Системное администрирование, Сетевые технологии, Сетевое оборудование] Fortinet Security Fabric на практике. Часть 1. Общий обзор
Теги для поиска: #_programmirovanie (Программирование), #_data_mining, #_oop (ООП), #_r, #_data_engineering, #_r, #_oop (ООП), #_jazyk_r (язык R), #_klassy (классы), #_r6_klassy (R6 классы), #_programmirovanie (
Программирование
), #_data_mining, #_oop (
ООП
), #_r, #_data_engineering
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 23:25
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В прошлой публикации мы разобрали S3 классы, которые являются наиболее популярными в языке R. Теперь разберёмся с R6 классами, которые максимально приближённые к классическому объектно ориентированному программированию. Содержание Если вы интересуетесь анализом данных возможно вам будут интересны мои telegram и youtube каналы. Большая часть контента которых посвящены языку R.
Введение В этой статье мы не будем останавливать на определении термина объектно — ориентированное программирование, и на его принципах, т.е. наследовании, инкапсуляции и полиморфизме. R6 будут наиболее понятны пользователям Python, и тем кто привык к классическому ООП. В отличие от S3 классов, у R6 методы привязаны к самим объектам, в то время как у S3 всё строится на обобщённых (generic) функциях. Итак, всё-таки небольшой глоссарий по ООП я предоставлю:
Для работы с R6 классами вам необходимо изначально установить и подключить одноимённый пакет R6. install.packages("R6")
library(R6) Правила именования Вам необязательно придерживаться данных правил, но они являются общепринятыми:
Так же как и в Python, методы класса могут получить доступ к другим его методам и свойствам через конструкцию self$method(). Создаём собственный класс Из пакета R6 вы будете использовать всего одну функцию R6Class(). Основные её аргументы:
library(R6)
# создаём класс Cat Cat <- R6Class(classname = "Cat", public = list( name = "Tom", breed = "Persian", age = 3, rename = function(name = NULL) { self$name <- name invisible(self) }, add_year = function(ages = 1) { self$age <- age + ages invisible(self) } ) ) Мы создали класс Cat, с тремя свойствами name, breed и age, и двумя методами $rename() и $add_year(). Метод $rename() меняет свойство name, как я писал ранее к свойству метод может обращаться через self$name, а метод $add_year() увеличивает возраст кота на заданное количество лет. Для создания экземпляра класса необходимо использовать встроенный метод $new(): # инициализируем объект класса Cat
tom <- Cat$new() # смотрим результат tom <Cat>
Public: add_year: function (ages = 1) age: 3 breed: Persian clone: function (deep = FALSE) name: Tom rename: function (name = NULL) Используем метод $rename(): # используем метод rename
tom$rename('Tommy') # смотрим результат tom <Cat>
Public: add_year: function (ages = 1) age: 3 breed: Persian clone: function (deep = FALSE) name: Tommy rename: function (name = NULL) Как видите объекты созданные с помощью R6 классов меняют свои компоненты на лету, т.е. нет необходимости создавать копии этих объектов. Т.к. мы создали класс с публичными методами и свойствами то мы имеем к ним доступ вне класса, и соответственно можем их изменять. # меняем свойство
tom$name <- 'Tom' # смотрим результат tom <Cat>
Public: add_year: function (ages = 1) age: 3 breed: Persian clone: function (deep = FALSE) name: Tom rename: function (name = NULL) Цепочка методов Если вы обратили внимание, то при создании методов мы всегда скрываем объект self с помощью оператора invisible(self). Это делается для того, что бы мы могли использовать цепочку методов: # используем цепочку методов
tom$add_year(1)$add_year(3) # смотрим результат tom <Cat>
Public: add_year: function (ages = 1) age: 7 breed: Persian clone: function (deep = FALSE) name: Tom rename: function (name = NULL) Опять же такой подход хорошо знаком пользователям Python и JavaScript. Методы $initialize() и $print() Важные методы, которые вы наверняка будете использовать при создании R6 классов это методы $initialize() и $print(). Метод $initialize() переопределяет стандартное поведение метода $new(), т.е. используя его вы можете отдельно прокидывать в создаваемый экземпляр класса данные, например имя, породу и возраст кота. $print() переопределяет метод печати объекта в консоли. # создаём класс Cat
Cat <- R6Class(classname = "Cat", public = list( name = NA, breed = NA, age = 0, initialize = function(name, breed, age) { self$name <- name self$breed <- breed self$age <- age }, print = function(...) { cat("<Cat>: \n") cat(" Name: ", self$name, "\n", sep = "") cat(" Age: ", self$age, "\n", sep = "") cat(" Breed: ", self$breed, "\n", sep = "") invisible(self) }, rename = function(name = NULL) { self$name <- name invisible(self) }, add_year = function(ages = 1) { self$age <- self$age + ages invisible(self) } ) ) # создаём экземпляр класса tom <- Cat$new(name = 'Tom', breed = 'Scottish fold', age = 1) # смотрим результат tom <Cat>:
Name: Tom Age: 1 Breed: Scottish fold Добавление новых свойств и методов в класс после его определение, метод $set() Даже после определения класса вы в любой момент можете добавить в него свойства или методы, используя метод $set() и указав уровень приватности. Ниже приведён пример кода, в котором мы сначала создаём класс с основными методами, после чего через метод $set() добавляем методы $rename() и $add_year(). # создаём класс Cat
Cat <- R6Class(classname = "Cat", public = list( name = NA, breed = NA, age = 0, initialize = function(name, breed, age) { self$name <- name self$breed <- breed self$age <- age }, print = function(...) { cat("<Cat>: \n") cat(" Name: ", self$name, "\n", sep = "") cat(" Age: ", self$age, "\n", sep = "") cat(" Breed: ", self$breed, "\n", sep = "") invisible(self) } ) ) # добавляем метод rename Cat$set( 'public', 'rename', function(name = NULL) { self$name <- name invisible(self) }) # добавляем метод add_year Cat$set( 'public', 'add_year', function(ages = 1) { self$age <- self$age + ages invisible(self) }) При этом, добавленные методы никак не изменят созданные до их добавления экземпляры класса, а будут распространяться лишь на те экземпляры класса, которые будут созданы после их добавления в класс. Так же вы можете запретить переопределение методов класса, используя при его создании аргумент lock_class = TRUE. В дальнейшем это поведение можно изменить, и разблокировать класс методом $unlock(), и опять заблокировать методом $lock(). # Создаём класс с блокировкой переопределения методов
Simple <- R6Class("Simple", public = list( x = 1, getx = function() self$x ), lock_class = TRUE ) # При попытке переопределить метод мы получим ошибку Simple$set("public", "y", 2) # Разблокируем класс Simple$unlock() # Теперь мы можем переопределять существующие свойства и методы класса Simple$set("public", "y", 2) # Повторно блокируем класс Simple$lock() Пример кода взят из официальной документации к пакету R6, автор Winston Chang
Наследование R6 классы поддерживают механизм наследования, т.е. вы можете создавать супер классы и подклассы, которые будут наследовать от супер классов методы и свойства. При необходимости вы можете переопределять методы супер класса. На изображении класс "Животные" является главным супер классом, его подклассом являются "Домашние животные" и "Дикие животные", т.е. они наследуют все свойства и методы класса (шаблона) животные, но могут их переопределять, а так же могут иметь свои дополнительные методы и свойства. Далее мы создаём подклассы "Кот" и "Собака", для которых класс "Домашние животные" уже будет родительским, т.е. супер классом. Так же мы создаём классы "Олень" и "Медведь", для которых супер классом будет "Дикие животные". Эту цепочку можно было продолжить породами котов, собак, оленей и медведей. Для реализации наследования в R6 классах необходимо использовать аргумент inherit. library(R6)
# создаём супер класс Cat Cat <- R6Class(classname = "Cat", public = list( name = NA, breed = NA, age = 3, initialize = function(name, breed, age) { self$name <- name self$breed <- breed self$age <- age }, rename = function(name = NULL) { self$name <- name invisible(self) }, add_year = function(ages = 1) { self$age <- self$age + ages invisible(self) } ) ) # создаём подкласс ScottishCat ScottishCat <- R6Class("ScottishCat", inherit = Cat, public = list( breed = "Scottish Fold", add_year = function() { cat("Увеличили возраст ", self$name, " на 1 год", sep = "") super$add_year(ages = 1) }, initialize = function(name, age, breed = "Scottish Fold") { self$name <- name self$breed <- breed self$age <- age } ) ) # создаём экземпляр класса scottish <- ScottishCat$new(name = 'Arnold', age = 1) # используем метод подкласса scottish$add_year() В данном примере мы создали супер класс Cat, и подкласс ScottishCat. В подклассе мы переопредели метод $add_year(), тем не менее, мы можем внутри подкласса использовать унаследованные от супер класса методы обращаясь к ним через super$method(). Приватные методы и свойства В аргумент public функции R6Class() мы передаём методы и свойства класса с общим доступом, т.е. эти методы и свойства доступны как внутри класса, так и за его пределами. Так же вы можете создавать приватные свойства и методы, которые будут доступны исключительно внутри класса. Такие свойства и методы необходимо передавать в аргумент private, внутри класса доступ к приватным методам и свойствам осуществляется через private$methode_name. library(R6)
# создаём класс User <- R6Class('User', public = list( name = NA, initialize = function(name, password, credits = 100) { self$name <- name private$password <- password private$credits <- credits }, print = function(...) { cat("<User>: ", self$name, sep='') }, get_credits = function() { cat(private$credits) } ), private = list( password = NULL, credits = NULL ) ) # экземпляр класса user_1 <- User$new('Alex', 'secretpwd') # метод который использует приватное свойство user_1$get_credits() 100
В данном случае мы получили значение приватного свойства credits через специальный метод. Но если мы напрямую попробуем обратиться к данному свойству, то у нас ничего не получится: # обращение к приватному свойству вне класса
user_1$credits NULL
Активные методы Активные методы для пользователя выглядят как свойства, но при обращении к ним они выполняют заданную функцию. При каждом обращении к активному методу будет выполняться определённая функция, это удобно к примеру для запуска генератора случайных чисел, или выбора случайного значения из вектора. Давайте вернёмся к нашему коту, и напишем класс, в котором будет свойство dictionary, в котором будет вектор звуков, которые может воспроизводить кот. И активный метод $say(), который случайным образом будет выводить одну из заданных фраз. library(R6)
# создаём класс Cat Cat <- R6Class(classname = "Cat", public = list( name = NA, breed = NA, dictionary = NA, initialize = function(name, breed, dictionary) { self$name <- name self$breed <- breed self$dictionary <- dictionary } ), active = list( say = function(value) { if (missing(value)) { return(paste0(self$name, ' say ', sample(self$dictionary, size = 1))) } else { self$dictionary <- value } } ) ) # создаём экземпляр класса cat <- Cat$new('Tom', 'Persian', c('meow', 'mrrr', 'frrr')) # запускаем активный метод cat$say [1] "Tom say meow"
Как видите к активным методам мы обращаемся как к свойствам, т.е. без скобок и аргументов, но при этом выполняется функция say. В функции мы реализовали проверку if (missing(value)), т.е. мы проверяем если идёт обращение к активному методу, то мы просто выводим случайную фразу из self$dictionary. Если в активный метод передать значение, то будет выполняться условие else, в нашем случае переопределение self$dictionary. # переопределяем свойство
cat$say <- c('grrr', 'waw', 'chfw') # используем активный метод cat$say "Tom say grrr"
Финализатор класса Вы можете добавить в класс специальный метод $finalize, который будет запускаться после удаления объекта при завершении R сессии. Это полезно в тех случаях когда ваш класс работает с файлами или базами данных, тогда вы можете написать финализатор для того, что бы быть уверенным, что соединение с файлом или базой будет разорвано. TemporaryFile <- R6Class("TemporaryFile", list(
path = NULL, initialize = function() { self$path <- tempfile() }, finalize = function() { message("Cleaning up ", self$path) unlink(self$path) } )) Пример кода взят из книги Advanced R, автор Hadley Wickham
Добавление R6 классов в пакет Ещё одно отличие R6 классов от S3 заключается в том, что вам не надо прописывать ваши R6 классы в фале NAMESPACE. Достаточно просто включить пакет R6 в поле Imports файла DESCRIPTION. Полезные ссылки Данная статья не является свободным переводом какой-либо англоязычной публикации, но при её написании я пользовался следующими источниками: Заключение Как вы убедились R6 классы это реализация классического объектно ориентированного программирования в языке R. Тем не менее данные класс используется в R достаточно редко, т.к. родной, и общепринятой реализацией ООП в R по-прежнему считаются S3 классы. Подписывайтесь на мой канал R4marketing в Telegram и YouTube. =========== Источник: habr.com =========== Похожие новости:
Программирование ), #_data_mining, #_oop ( ООП ), #_r, #_data_engineering |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 23:25
Часовой пояс: UTC + 5