Giải thích rõ hơn về thời điểm sử dụng Nhập khẩu / Phụ thuộc


148

Hướng dẫn " Viết phần mở rộng R " cung cấp hướng dẫn sau đây về thời điểm sử dụng Nhập khẩu hoặc phụ thuộc:

Các quy tắc chung là

  • Các gói có không gian tên chỉ cần để tải gói bằng thư viện (pkgname) phải được liệt kê trong trường 'Nhập khẩu' và không phải trong trường 'Phụ thuộc'.
  • Các gói cần được đính kèm để tải thành công gói bằng thư viện (pkgname) phải được liệt kê trong trường 'Phụ thuộc'.

Ai đó có thể cung cấp một chút rõ ràng hơn về điều này? Làm thế nào để tôi biết khi gói của tôi chỉ cần không gian tên được tải so với khi tôi cần một gói được đính kèm? Ví dụ của cả hai là gì? Tôi nghĩ rằng gói thông thường chỉ là một tập hợp các hàm đôi khi gọi các hàm trong các gói khác (trong đó một số công việc đã được mã hóa). Là kịch bản 1 hoặc 2 ở trên?

Biên tập

Tôi đã viết một bài đăng trên blog với một phần về chủ đề cụ thể này (tìm kiếm 'Nhập khẩu v Phụ thuộc'). Hình ảnh làm cho nó dễ hiểu hơn rất nhiều.


1
Bài đăng trên blog của bạn cho tôi biết mọi thứ về cấu trúc gói, trở lại khi tôi bắt đầu lập kế hoạch mô-đun . Cảm ơn!
Konrad Rudolph

Câu trả lời:


143

"Imports"an toàn hơn "Depends"(và cũng làm cho một gói sử dụng nó trở thành "công dân tốt hơn" đối với các gói khác sử dụng "Depends").

Một lệnh "Depends"cố gắng để đảm bảo rằng một chức năng từ gói khác có sẵn bằng cách đính kèm gói khác vào đường dẫn tìm kiếm chính (tức là danh sách các môi trường được trả về bởi search()). Tuy nhiên, chiến lược này có thể bị cản trở nếu một gói khác, được tải sau đó, đặt một chức năng có tên giống hệt trước đó trên đường tìm kiếm. Chambers ( trong SoDA ) sử dụng ví dụ về hàm "gam", được tìm thấy trong cả gói gammgcvgói. Nếu hai gói khác được tải, một trong số chúng phụ thuộc gamvà một tùy thuộc vào mgcv, chức năng được tìm thấy bởi các cuộc gọi gam()sẽ phụ thuộc vào thứ tự mà hai gói đó được đính kèm. Không tốt.

Một lệnh "Imports"nên được sử dụng cho bất kỳ gói hỗ trợ nào có chức năng được đặt trong <imports:packageName>(được tìm kiếm ngay sau đó <namespace:packageName>), thay vì trên đường dẫn tìm kiếm thông thường. Nếu một trong các gói trong ví dụ trên sử dụng "Imports"cơ chế (cũng yêu cầu importhoặc importFromchỉ thị trong NAMESPACEtệp), vấn đề sẽ được cải thiện theo hai cách. (1) Gói sẽ tự kiểm soát mgcvchức năng nào được sử dụng. (2) Bằng cách giữ cho đường dẫn tìm kiếm chính rõ ràng khỏi các đối tượng được nhập, nó thậm chí sẽ không có khả năng phá vỡ sự phụ thuộc của gói khác vào mgcvchức năng khác .

Đây là lý do tại sao sử dụng không gian tên là một cách thực hành tốt như vậy, tại sao bây giờ nó được thi hành bởi CRAN và (đặc biệt) tại sao sử dụng lại "Imports"an toàn hơn sử dụng "Depends".


Chỉnh sửa để thêm một cảnh báo quan trọng:

một ngoại lệ không may chung cho những lời khuyên ở trên: nếu gói của bạn dựa vào một gói phần mềm Amà bản thân "Depends"trên một gói khác B, gói của bạn có thể sẽ cần phải đính kèm Avới một "Dependschỉ thị.

Điều này là do các hàm trong gói Ađược viết với kỳ vọng rằng gói Bvà các hàm của nó sẽ được gắn vào search()đường dẫn .

Một lệnh "Depends"sẽ tải và đính kèm gói A, tại đó chỉ thị Acủa chính gói đó "Depends", theo phản ứng dây chuyền, sẽ khiến gói Bđược tải và đính kèm. Các hàm trong gói Asau đó sẽ có thể tìm thấy các hàm trong gói Bmà chúng dựa vào.

Một lệnh "Imports"sẽ tải nhưng không đính kèm gói Avà sẽ không tải cũng không đính kèm gói B. ( "Imports", Sau khi tất cả, hy vọng rằng tác giả gói đang sử dụng cơ chế namespace, và gói phần mềm đó Asẽ được sử dụng "Imports"để trỏ đến bất kỳ chức năng trong Bđó cần truy cập vào.) Các cuộc gọi theo chức năng của mình cho bất kỳ chức năng trong gói Amà dựa vào chức năng trong gói Bdi chúc hậu quả là thất bại.

Hai giải pháp duy nhất là:

  1. Có gói của bạn đính kèm gói Abằng cách sử dụng một "Depends"chỉ thị.
  2. Về lâu dài, hãy liên hệ với người bảo trì gói hàng Avà yêu cầu họ thực hiện công việc cẩn thận hơn trong việc xây dựng không gian tên của họ (theo lời của Martin Morgan trong câu trả lời liên quan này ).

1
Gần đây đã hỏi một câu hỏi tương tự và gần đây vật lộn với những vấn đề này, đây là những khái niệm tinh tế và thường không được truyền đạt. Tôi sẽ giới thiệu bạn ở đây để có lời giải thích khác: stackoverflow.com/questions/7880455/ Kẻ
Bryan Hanson

@BryanHanson - Cảm ơn bạn đã viết lên các ghi chú tại liên kết đó. Sự khác biệt giữa ImportsDependsyêu cầu phiên bản wrt và kiểm tra các ví dụ trong .Rdcác tệp thực sự tinh tế và đáng để biết.
Josh O'Brien

1
Sự cảnh báo về sự phụ thuộc sử dụng 'Phụ thuộc' là một điều khủng khiếp. Điều đó có nghĩa là về cơ bản tôi không thể sử dụng 'Nhập khẩu' trong gói của mình cho đến khi mọi người khác cũng vậy. = (
Ken Williams

Một điều tôi vẫn chưa rõ là, nếu tôi đang viết một gói, và tôi muốn Imports: ggplot2, tại sao gói của tôi sau đó không tìm thấy autoplotchức năng? Rõ ràng là Dependsđính kèm thư viện gói ggplot2và vì vậy không có vấn đề. ví dụ: tôi có một chức năng autoplot.myFunction() sử dụng @import ggplot2thẻ và gói của tôi có Imports: ggplot2nhưng tôi gặp lỗi: Error in eval(expr, envir, enclos) : could not find function "autoplot"khi tôi cố gắng sử dụng nó.
nathaneastwood

1
@Willem Cảm ơn. Tất nhiên bạn đúng và tôi đã chỉnh sửa câu trả lời để xóa nội dung sai lệch. Một phần của điều khiến câu trả lời phức tạp này là, trong khi OP đóng khung câu hỏi của anh ta có liên quan đến các phần DependsImportsphần DESCRIPTION, anh ta thực sự hỏi về việc "nhập" một chức năng (chứ không phải "phụ thuộc" vào nó) nghĩa là gì. Vì đó là câu hỏi tôi đã cố gắng trả lời (và - tôi nghi ngờ - điều mà hầu hết mọi người tìm kiếm câu trả lời này đều muốn biết), tôi sẽ không trả lời câu trả lời.
Josh O'Brien

31

Hadley Wickham đưa ra một lời giải thích dễ dàng ( http://r-pkgs.had.co.nz/namespace.html ):

Liệt kê một gói trong một Dependshoặc Importsđảm bảo rằng nó được cài đặt khi cần. Sự khác biệt chính là nơi Importschỉ cần tải gói, Dependsđính kèm nó. Không có sự khác biệt khác. [...]

Trừ khi có một lý do chính đáng khác, bạn nên luôn luôn liệt kê các gói Importskhông Depends. Đó là bởi vì một gói tốt là khép kín và giảm thiểu các thay đổi đối với môi trường toàn cầu (bao gồm cả đường dẫn tìm kiếm). Ngoại lệ duy nhất là nếu gói của bạn được thiết kế để được sử dụng cùng với gói khác. Ví dụ, gói tương tự được xây dựng trên đỉnh của thuần chay. Nó không hữu ích nếu không có thuần chay, vì vậy nó có thuần chay Dependsthay vì Imports. Tương tự, ggplot2 nên thực sự phụ thuộc vào quy mô, thay vì nhập nó.


15

Chambers trong SfDA nói sẽ sử dụng 'Nhập khẩu' khi gói này sử dụng cơ chế 'không gian tên' và vì tất cả các gói hiện bắt buộc phải có chúng, nên giờ đây câu trả lời có thể luôn là sử dụng 'Nhập khẩu'. Trong các gói trước đây có thể đã được tải mà không thực sự có không gian tên và trong trường hợp đó, bạn sẽ cần phải sử dụng Phụ thuộc.


2
khi một gói được chỉ định trong "nhập khẩu" và tôi muốn sử dụng một chức năng trong gói đó, các chức năng của riêng tôi có cần gọi thư viện (...) hay tất cả các chức năng đã có sẵn trong đường dẫn tìm kiếm? Ngoài ra, SfDA là gì? liên kết?
SFun28

2
Phần mềm phân tích dữ liệu : springer.com/statistic/computanional+statistic/book/, ... đối với câu hỏi của bạn, tôi không biết câu trả lời trực tiếp, nhưng bạn có thể hack một gói kiểm tra tối thiểu khá dễ dàng và tìm câu trả lời theo kinh nghiệm ...
Ben Bolker

1
SfDA == "Phần mềm phân tích dữ liệu". [65] tại r-project.org/doc/bib/R-books.html . Nếu một gói chỉ định gói khác, bạn sẽ thấy một thông báo cho bạn biết về việc tải phụ thuộc (mã hóa) và nhập (hành) khi bạn sử dụng thư viện () hoặc request () tại bàn điều khiển. Vâng, sau đó họ nên có sẵn.
IRTFM

4
+1 - Đây cũng là ấn tượng mạnh mẽ của tôi. Ngoài ra, một gói được chỉ định trong nhập khẩu sẽ được tìm kiếm ngay sau đó <namespace:packageName>, như là một phần của <imports:packageName>. Không cần gọi thêm nữa library()và R sẽ không thông báo cho bạn tại bàn điều khiển trong thời gian tải gói trừ khi Importkhông thể tìm thấy gói ed.
Josh O'Brien

5

Đây là một câu hỏi đơn giản để giúp bạn quyết định sử dụng:

Gói của bạn có yêu cầu người dùng cuối có quyền truy cập trực tiếp vào các chức năng của gói khác không?

  • KHÔNG -> Nhập khẩu (câu trả lời phổ biến nhất)
  • CÓ -> Phụ thuộc

Lần duy nhất bạn nên sử dụng 'Tùy thuộc' là khi gói của bạn là tiện ích bổ sung hoặc đồng hành với gói khác, nơi người dùng cuối của bạn sẽ sử dụng các chức năng từ cả gói của bạn và gói 'Phụ thuộc' trong mã của họ. Nếu người dùng cuối của bạn sẽ chỉ can thiệp vào các chức năng của bạn và gói khác sẽ chỉ thực hiện công việc phía sau hậu trường, sau đó sử dụng 'Nhập khẩu'.

Thông báo trước cho điều này là nếu bạn thêm một gói vào 'Nhập khẩu', như bạn thường làm, mã của bạn sẽ cần tham chiếu đến các hàm từ gói đó, sử dụng cú pháp không gian tên đầy đủ, ví dụ dplyr::mutate(), thay vì chỉ mutate(). Nó làm cho mã trở nên khó đọc hơn một chút, nhưng đó là một cái giá nhỏ để trả cho việc vệ sinh gói tốt hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.