Parent.env(x) путаница
Я прочитал документацию для parent.env(), и она кажется довольно простой - она возвращает окружение. Однако, если я использую parent.env(), чтобы ходить по цепочке окружающих сред, я вижу то, что я не могу объяснить. Во-первых, код (взятый из "R в двух словах" )
library( PerformanceAnalytics )
x = environment(chart.RelativePerformance)
while (environmentName(x) != environmentName(emptyenv()))
{
print(environmentName(parent.env(x)))
x <- parent.env(x)
}
И результаты:
[1] "imports:PerformanceAnalytics"
[1] "base"
[1] "R_GlobalEnv"
[1] "package:PerformanceAnalytics"
[1] "package:xts"
[1] "package:zoo"
[1] "tools:rstudio"
[1] "package:stats"
[1] "package:graphics"
[1] "package:utils"
[1] "package:datasets"
[1] "package:grDevices"
[1] "package:roxygen2"
[1] "package:digest"
[1] "package:methods"
[1] "Autoloads"
[1] "base"
[1] "R_EmptyEnv"
Как мы можем объяснить "базу" наверху и "базу" внизу? Кроме того, как мы можем объяснить "пакет: PerformanceAnalytics" и "import: PerformanceAnalytics"? Все казалось бы последовательным без первых двух строк. То есть, функция chart.RelativePerformance находится в пакете: среда PerformanceAnalytics, созданная xts, которая создается зоопарком,... полностью вверх (или вниз) на базовую и пустую среду.
Кроме того, документация не очень понятна для этого - это "окружающая среда" - среда, в которой создается другая среда, и, таким образом, ходьба parent.env() показывает цепочку создания?
Edit
Бесстыдный плагин: я написал сообщение в блоге, в котором объясняются среды, parent.env(), оболочки, пространство имен/пакет и т.д. с интуитивным диаграммы.
Ответы
Ответ 1
Первые несколько элементов в ваших результатах свидетельствуют о том, что правила R используются для поиска переменных, используемых в функциях в пакетах с пространствами имен. Из руководства R-ext:
Пространство имен управляет стратегией поиска для переменных, используемых функциями в пакете. Если локально не найден, R сначала ищет пространство имен пакетов, затем импортирует, а затем базу пространство имен, а затем обычный путь поиска.
Разработав немного, взгляните на первые несколько строк chart.RelativePerformance
:
head(body(chart.RelativePerformance), 5)
# {
# Ra = checkData(Ra)
# Rb = checkData(Rb)
# columns.a = ncol(Ra)
# columns.b = ncol(Rb)
# }
Когда вычисляется вызов chart.RelativePerformance
, каждый из этих символов --- будь то checkData
в строке 1 или ncol
в строке 3 --- должен быть найден где-то на пути поиска, Ниже перечислены первые окружные среды:
-
Прежде всего, это namespace:PerformanceAnalytics
. checkData
находится там, но ncol
- нет.
-
Следующая остановка (и первое место, указанное в ваших результатах) imports:PerformanceAnalytics
. Это список функций, указанных как импорт в пакете NAMESPACE
. ncol
также не найден.
-
Пространство имен base
(где ncol
будет найдено) является последней остановкой, прежде чем перейти к обычным траекториям поиска. Почти любая функция R будет использовать некоторые функции base
, поэтому эта остановка гарантирует, что ни одна из этих функций не может быть разбита объектами в глобальной среде или в других пакетах. (Дизайнеры R могли оставить это, чтобы авторы пакетов явно импортировали среду base
в свои файлы NAMESPACE
, но добавление этого пропуска по умолчанию через base
кажется лучшим решением дизайна.)
Ответ 2
1) Относительно того, как base
может быть там дважды (учитывая, что среда формирует дерево), его ошибка в функции environmentName
. На самом деле первое вхождение .BaseNamespaceEnv
, а последнее вхождение - baseenv()
.
> identical(baseenv(), .BaseNamespaceEnv)
[1] FALSE
2) Что касается imports:PerformanceAnalytics
, который является специальной средой, которую R устанавливает для хранения импортируемых в пакете файлов NAMESPACE или DESCRIPTION, чтобы объекты в ней встречались раньше всего.
Попробуйте выполнить это для некоторой ясности. Операторы str(p)
и следующих if
будут лучше понимать, что p
:
library( PerformanceAnalytics )
x <- environment(chart.RelativePerformance)
str(x)
while (environmentName(x) != environmentName(emptyenv())) {
p <- parent.env(x)
cat("------------------------------\n")
str(p)
if (identical(p, .BaseNamespaceEnv)) cat("Same as .BaseNamespaceEnv\n")
if (identical(p, baseenv())) cat("Same as baseenv()\n")
x <- p
}
Ответ 3
Второй base
- .BaseNamespaceEnv
, а второй - base
- baseenv()
. Это не разные (вероятно, w.r.t. его родители). Родитель .BaseNamespaceEnv
- .GlobalEnv
, а baseenv()
- emptyenv()
.
В пакете, как @Josh говорит, R ищет пространство имен пакета, затем импортирует, а затем базу (т.е. BaseNamespaceEnv
).
вы можете найти это, например:
> library(zoo)
> packageDescription("zoo")
Package: zoo
# ... snip ...
Imports: stats, utils, graphics, grDevices, lattice (>= 0.18-1)
# ... snip ...
> x <- environment(zoo)
> x
<environment: namespace:zoo>
> ls(x) # objects in zoo
[1] "-.yearmon" "-.yearqtr" "[.yearmon"
[4] "[.yearqtr" "[.zoo" "[<-.zoo"
# ... snip ...
> y <- parent.env(x)
> y # namespace of imported packages
<environment: 0x116e37468>
attr(,"name")
[1] "imports:zoo"
> ls(y) # objects in the imported packages
[1] "?" "abline"
[3] "acf" "acf2AR"
# ... snip ...