Подтвердить что ты не робот

В чем опасность использования атрибутов R?

Добавление атрибутов, определенных с помощью к объектам R, позволяет легко переносить некоторую дополнительную информацию, склеенную вместе с объектом, представляющим интерес. Проблема в том, что он слегка изменяет то, как R видит объекты, например. числовой вектор с дополнительным атрибутом по-прежнему равен numeric, но уже не vector:

x <- rnorm(100)
class(x)
## [1] "numeric"
is.numeric(x)
## [1] TRUE
is.vector(x)
## [1] TRUE
mode(x)
## [1] "numeric"
typeof(x)
## [1] "double"
attr(x, "foo") <- "this is my attribute"
class(x)
## [1] "numeric"
is.numeric(x)
## [1] TRUE
is.vector(x)
## [1] FALSE  # <-- here!
mode(x)
## [1] "numeric"
typeof(x)
## [1] "double"

Может ли это привести к любым потенциальным проблемам? Я думаю о добавлении некоторых атрибутов к общим объектам R, а затем передаче их другим методам. Каков риск чего-то взлома только из-за того, что я добавил дополнительные атрибуты к стандартным объектам R (например, вектор, матрица, data.frame и т.д.)?

Обратите внимание, что я не спрашиваю о создании моих собственных классов. Для простоты мы также можем предположить, что конфликтов имен в именах атрибутов не будет (например, с использованием атрибута dims). Предположим также, что это не проблема, если какой-либо метод в какой-то момент отбросит мой атрибут, это приемлемый риск.

4b9b3361

Ответ 1

В моем (несколько ограниченном) опыте добавление новых атрибутов к объекту ни разу не сломалось. Единственный вероятный сценарий, который я могу придумать, где он сломает что-то, был бы, если бы функция требовала, чтобы у объекта был определенный набор атрибутов и ничего больше. Я не могу думать о времени, когда я столкнулся с этим. Большинство функций, особенно в S3-методах, просто игнорируют атрибуты, которые им не нужны.

Вероятнее всего, проблемы будут возникать, если вы удалите атрибуты.

Причина, по которой вы не увидите много проблем, связанных с дополнительными атрибутами, заключается в том, что методы отправляются на class объекта. Пока класс не изменяется, методы будут отправляться почти одинаково. Однако это не означает, что существующие методы будут знать, что делать с вашими новыми атрибутами. Возьмем следующий пример: после добавления атрибута new_attr как к x, так и y, а затем добавив их, результат примет атрибут x. Что случилось с атрибутом y? По умолчанию функция + не знает, что делать с конфликтующими атрибутами с тем же именем, поэтому она просто берет первый (подробнее в R Определение языка, спасибо Brodie).

x <- 1:10
y <- 10:1

attr(x, "new_attr") <- "yippy"
attr(y, "new_attr") <- "ki yay"

x + y

[1]  1  2  3  4  5  6  7  8  9 10
attr(,"new_attr")
[1] "yippy"

В другом примере, если мы даем атрибуты x и y с разными именами, x + y создает объект, который сохраняет оба атрибута.

x <- 1:10
y <- 10:1

attr(x, "new_attr") <- "yippy"
attr(y, "another_attr") <- "ki yay"

x + y
 [1] 11 11 11 11 11 11 11 11 11 11
attr(,"another_attr")
[1] "ki yay"
attr(,"new_attr")
[1] "yippy"

С другой стороны, mean(x) даже не пытается сохранить атрибуты. Я не знаю хорошего способа предсказать, какие функции будут и не будут сохранять атрибуты. Вероятно, есть какая-то надежная мнемоника, которую вы могли бы использовать в базе R (агрегация против векторизованной, возможно?), Но я думаю, что существует отдельный принцип, который следовало бы рассмотреть.

Если сохранение ваших новых атрибутов важно, вы должны определить новый класс, который сохраняет наследование старого класса

С новым классом вы можете писать методы, которые расширяют дженерики и обрабатывают атрибуты в зависимости от того, какой вы хотите. Независимо от того, следует ли вам определять новый класс и писать его методы, очень зависит от того, насколько ценны любые новые атрибуты, которые вы добавляете, к будущей работе, которую вы будете делать.

Таким образом, добавление новых атрибутов вряд ли может сломать что-либо в R. Но без добавления нового класса и методов для обработки новых атрибутов я был бы очень осторожен в интерпретации значения этих атрибутов после того, как они были прошел через другие функции.