问题
Working with data in Python or R, we often load several packages. In some cases, two packages (e.g. foo
and bar
) might each contain some function (e.g. do_stuff
).
The way this is managed in Python to prevent ambiguity or surprises is like:
from foo import do_stuff
from bar import other_function # (does not load/import do_stuff() from bar)
In R, all the code I see just imports whole packages with
multiple library(package_name)
statements. I would think this would lead to very difficult-to-catch bugs. For example, see Reordering factor gives different results, depending on which packages are loaded. In fact this occurred even though "there is no masking, since reorder.factor doesn't exist in base."
I expected the general answer to this problem to be something like the from package import function
code above, but it wasn't. In fact the accepted (and only) answer just explains why the problem exists (not to downplay that contribution). There's a workaround provided in a comment of the answer, but that workaround is specific to that particular function (reorder
).
Is there a general way that I can import only a specific function from a specific package in R? So that I can be deliberate and unambiguous about where all of the function calls in my code come from and ensure that they do what I think they're doing?
回答1:
You can explicitly tell R which package should be used for a given function using the package::function()
construction. You can even use that to call functions from packages that you haven't loaded with library
.
library(dplyr) # Has a function called filter()
library(plyr) # Also has a filter() function
dplyr::filter(foo)
plyr::filter(bar)
If you want to make sure you're minimizing the possibility for confusion in your code, I highly recommend the conflicted
package, which forces you to explicitly identify the package for all ambiguous function calls: https://www.tidyverse.org/articles/2018/06/conflicted/
回答2:
Although this answer is correct, it doesn't work for infix operators such as magrittr
's %>%
and %$%
. The import
package works a treat:
import::from(magrittr, "%$%")
But obviously can be used for any function:
import::from(foo, "do_stuff", "do_other_stuff")
Be aware that "[import
] is not intended for use with library
. It is named to make calls like import::from(pkg, fun1, fun2)
expressive." See https://CRAN.R-project.org/package=import for more details.
回答3:
You're comparing two languages that function differently. First of all, you can easily refer to a function from a package using ::
, eg:
fortunes::fortune()
To call the fortune
function from the fortunes
package.
But you also have to be careful doing so. Because depending on how the package is constructed, you might end up with using a function that's dependent on other (non-exported) functions from the namespace, but that can't be found because the namespace isn't loaded. I've run into that problem myself using plotting functions from eg the mgcv
package. This is one reason to attach the packages using library()
as Andrew Breza illustrates in his answer. At least the functions you call using the ::
construct will work (99.9% of the time) as expected.
But the problem you link to, won't be solved by this. The problem there is "bad design" in the sense that the package author decided he needed an S3 method for reordering a factor instead of a class specific to his package. Doing so registered an S3 method for the entire factor class and hence changed the behaviour of every function that calls reorder()
on a factor.
And as that problem is caused by the package developers themselves, there's little you can do as a user apart from hacking into the S3 system yourself to find the actual method you need.
来源:https://stackoverflow.com/questions/45150870/from-package-import-function-in-r