2011-11-20 49 views
11

Giả sử tôi đang gọi hàm PackageFuncA tồn tại trong gói bên thứ 3 (tức là thư viện từ CRAN). PackageFuncA lần lượt gọi PackageFuncB trong cùng gói bên thứ 3. Có cách nào để gọi PackageFuncA như vậy mà khi nó gọi PackageFuncB, nó sẽ trong thực tế gọi của riêng tôi implimentation của PackageFuncB? Nói cách khác, tôi có thể chặn cuộc gọi đến PackageFuncB không? Tôi nghĩ rằng các giải pháp liên quan đến việc tạo ra chức năng PackageFuncB của riêng tôi và sau đó gọi PackageFuncA trong cùng một môi trường và không phải môi trường của PackageFuncA, nhưng tôi không thể làm cho nó hoạt động được với do.call cũng không phải eval.Lệnh chuyển hướng/chặn cuộc gọi trong chức năng gói

+0

Nó sẽ dễ dàng hơn để tạo PackageFunA của riêng bạn và thay đổi cuộc gọi thành PackageFunB sao cho nó gọi hàm của bạn thay thế? – joran

+0

Xem '? AssignInNamespace' – Andrie

+0

joran - Tôi không muốn duy trì phiên bản PackageFuncA của riêng mình, đặc biệt là vì nó không chỉ là một vài dòng mã. – SFun28

Trả lời

10

Đây là một lớp lót thực hiện. Tại đây PackageFuncAstats::acfPackageFuncBstats:::plot.acf mà chúng tôi muốn thay thế bằng my.plot.acf. my.plot.acf in "Hello" và sau đó gọi stats:::plot.acf thực.

# we want this to run in place of stats:::plot.acf 
my.plot.acf <- function(x, ...) { cat("Hello\n"); stats:::plot.acf(x, ...) } 

# this does it 
library(proto) 
acf <- with(proto(environment(acf), acf = stats::acf, plot.acf = my.plot.acf), acf) 

# test 
acf(1:10) 

Đối tượng proto là môi trường mà bất kỳ chức năng nào được chèn vào đối tượng qua chức năng proto đều có môi trường tự động đặt lại đối tượng đó. Arg đầu tiên của proto() là phụ huynh của đối tượng proto.

Trong ví dụ trên, thiết bị được thiết lập sao cho biến số acf đề cập đến phiên bản acf được chèn vào đối tượng proto (giống với bản gốc ngoại trừ môi trường của nó đã được sửa đổi làm đối tượng proto)). Khi chức năng acf mới chạy plot.acf là một biến miễn phí (tức là không được định nghĩa trong acf) để nó được tra cứu trong phụ huynh của acf và đó là môi trường trong đối tượng proto nơi nó tìm thấy plot.acf mới. acf có thể có các biến miễn phí khác nhưng trong những trường hợp này vì chúng không được tìm thấy trong đối tượng proto, nó trông giống như đối tượng gốc của đối tượng proto, là môi trường gốc của acf gốc. Về sơ đồ, chúng tôi có điều này nơi <- nghĩa bên trái là mẹ của phía bên phải:

environment(stats::acf) <- proto object <- revised acf 

và đối tượng proto chứa cả plot.acf và sửa đổi acf.

Chúng tôi cũng đã đặt môi trường của plot.acf mới thành đối tượng proto. Chúng tôi có thể hoặc có thể không cần thiết để làm điều này. Trong nhiều trường hợp, nó sẽ không thành vấn đề. Nếu điều quan trọng là không để thiết lập môi trường mới plot.acf sau đó nó sẽ được thực hiện như thế này bởi vì proto không bao giờ lặn môi trường của các chức năng chèn sử dụng [[...]]:

acf <- with(p <- proto(environment(acf), acf = stats::acf), acf) 
p[["plot.acf"]] <- my.plot.acf 

Trong ví dụ này, cả hai phương pháp tiếp cận công việc.

Nó sẽ có thể làm tất cả những điều này với môi trường đồng bằng tại các chi phí của việc phải sử dụng một vài dòng mã:

# create new environment whose parent is the original acf's parent 
e <- new.env(parent = environment(stats::acf)) 

# the next statement is only need to overwrite any acf you already might have from 
# trying other code. If you were sure there was no revised acf already defined 
# then the next line could be omitted. Its a bit safer to include it. 
acf <- stats::acf 

# This sets the environment of the new acf. If there were no acf already here 
# then it would copy it from stats::acf . 
environment(acf) <- e 

# may or may not need next statement. In this case it doesn't matter. 
environment(my.plot.acf) <- e 

e$plot.acf <- my.plot.acf 

acf(1:10) 

Trong trường hợp này, chúng tôi đã không đặt điều chỉnh acf trong e như trong proto ví dụ nhưng chỉ đặt cha mẹ của nó. Trong thực tế, đặt acf sửa đổi thành e hoặc đối tượng proto là không cần thiết nhưng chỉ được thực hiện trong trường hợp proto vì proto có tác dụng phụ của việc đặt lại môi trường và đó là tác dụng phụ mà chúng tôi đã làm sau đó.Mặt khác, cần phải đặt plot.acf sửa đổi trong e hoặc đối tượng proto để đối tượng đó gặp phải trước bản gốc.

Bạn có thể muốn đọc số này paper và cụ thể là phần trên proxy bắt đầu trang 21 vì kỹ thuật được hiển thị ở đây là ví dụ về đối tượng proxy.

+0

hoạt động hoàn hảo! Tôi sẽ phải nhìn chằm chằm vào điều này một chút trước khi tôi tìm ra lý do tại sao. Việc đi bộ ngắn gọn về những gì đang xảy ra sẽ là một trợ giúp lớn, nếu bạn có thời gian. – SFun28

+0

ok. đã thêm một số công phu. –

+0

điều này thật tuyệt vời! cám ơn rất nhiều – SFun28

0

Tạo bản sao mới PackageFuncA, đặt lại môi trường và viết phiên bản PackageFuncB của riêng bạn.

environment(PackageFuncA) <- globalenv() # makes a new copy of PackageFuncA 

PackageFuncB <- function(...) .... # will be called from your new PackageFuncA 

Bạn có thể phải thực hiện một chút chỉnh sửa nếu PackageFuncA sử dụng chức năng chưa được xuất từ ​​gói ban đầu. Ngoài ra, nếu bạn không muốn sử dụng PackageFuncB mới ở nơi khác, bạn có thể bọc nó bên trong PackageFuncA mới thay vì đặt nó trong môi trường toàn cầu.

Các vấn đề liên quan