it-swarm.asia

كيف يمكنني عرض الكود المصدري لوظيفة؟

أرغب في إلقاء نظرة على الكود المصدري للحصول على وظيفة لمعرفة كيف تعمل. أعلم أنه يمكنني طباعة دالة عن طريق كتابة اسمها على الموجه:

> t
function (x) 
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>

في هذه الحالة ، ماذا يعني UseMethod("t")؟ كيف يمكنني العثور على الكود المصدري الذي تستخدمه بالفعل ، على سبيل المثال: t(1:10)؟

هل هناك فرق بين عندما أرى UseMethod وعندما أرى standardGeneric و showMethods ، كما هو الحال مع with؟

> with
standardGeneric for "with" defined from package "base"

function (data, expr, ...) 
standardGeneric("with")
<bytecode: 0x102fb3fc0>
<environment: 0x102fab988>
Methods may be defined for arguments: data
Use  showMethods("with")  for currently available ones.

في حالات أخرى ، أستطيع أن أرى أنه يتم استدعاء وظائف R ، لكن لا يمكنني العثور على الكود المصدري لتلك الوظائف.

> ts.union
function (..., dframe = FALSE) 
.cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)
<bytecode: 0x36fbf88>
<environment: namespace:stats>
> .cbindts
Error: object '.cbindts' not found
> .makeNamesTs
Error: object '.makeNamesTs' not found

كيف يمكنني العثور على وظائف مثل .cbindts و .makeNamesTs؟

في حالات أخرى ، هناك القليل من كود R ، لكن يبدو أن معظم العمل يتم في مكان آخر.

> matrix
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
{
    if (is.object(data) || !is.atomic(data)) 
        data <- as.vector(data)
    .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), 
        missing(ncol)))
}
<bytecode: 0x134bd10>
<environment: namespace:base>
> .Internal
function (call)  .Primitive(".Internal")
> .Primitive
function (name)  .Primitive(".Primitive")

كيف يمكنني معرفة وظيفة .Primitive؟ وبالمثل ، تتصل بعض الوظائف بـ .C أو .Call أو .Fortran أو .External أو .Internal. كيف يمكنني العثور على شفرة المصدر لهؤلاء؟

469
Joshua Ulrich

يخبرك UseMethod("t") بأن t() هي وظيفة عامة ( S3 ) لها طرق لفئات كائن مختلفة.

نظام إرسال طريقة S3

بالنسبة لفئات S3 ، يمكنك استخدام الدالة methods لسرد الأساليب الخاصة بوظيفة أو فئة عامة معينة.

> methods(t)
[1] t.data.frame t.default    t.ts*       

   Non-visible functions are asterisked
> methods(class="ts")
 [1] aggregate.ts     as.data.frame.ts cbind.ts*        cycle.ts*       
 [5] diffinv.ts*      diff.ts          kernapply.ts*    lines.ts        
 [9] monthplot.ts*    na.omit.ts*      Ops.ts*          plot.ts         
[13] print.ts         time.ts*         [<-.ts*          [.ts*           
[17] t.ts*            window<-.ts*     window.ts*      

   Non-visible functions are asterisked

"الوظائف غير المرئية هي العلامة النجمية" تعني أن الوظيفة لا يتم تصديرها من مساحة اسم الحزمة الخاصة بها. لا يزال بإمكانك عرض التعليمات البرمجية المصدر الخاصة بها عبر دالة ::: (أي stats:::t.ts) أو باستخدام getAnywhere(). getAnywhere() مفيدة لأنك لا تحتاج إلى معرفة الحزمة التي جاءت منها الوظيفة.

> getAnywhere(t.ts)
A single object matching ‘t.ts’ was found
It was found in the following places
  registered S3 method for t from namespace stats
  namespace:stats
with value

function (x) 
{
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
<bytecode: 0x294e410>
<environment: namespace:stats>

نظام إرسال طريقة S4

نظام S4 هو نظام إرسال أحدث طريقة وهو بديل لنظام S3. فيما يلي مثال لوظيفة S4:

> library(Matrix)
Loading required package: lattice
> chol2inv
standardGeneric for "chol2inv" defined from package "base"

function (x, ...) 
standardGeneric("chol2inv")
<bytecode: 0x000000000eafd790>
<environment: 0x000000000eb06f10>
Methods may be defined for arguments: x
Use  showMethods("chol2inv")  for currently available ones.

الإخراج يقدم بالفعل الكثير من المعلومات. standardGeneric هو مؤشر دالة S4. يتم تقديم طريقة معرفة طرق S4 المحددة بشكل مفيد:

> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"

getMethod يمكن استخدامها لرؤية الكود المصدري لأحد الأساليب:

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

هناك أيضًا طرق ذات توقيعات أكثر تعقيدًا لكل طريقة ، على سبيل المثال

require(raster)
showMethods(extract)
Function: extract (package raster)
x="Raster", y="data.frame"
x="Raster", y="Extent"
x="Raster", y="matrix"
x="Raster", y="SpatialLines"
x="Raster", y="SpatialPoints"
x="Raster", y="SpatialPolygons"
x="Raster", y="vector"

للاطلاع على الكود المصدري لأحد هذه الطرق ، يجب توفير التوقيع بأكمله ، على سبيل المثال.

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

لن يكفي لتوفير التوقيع الجزئي

getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") : 
#  No method found for function "extract" and signature SpatialPolygons

الوظائف التي تستدعي الوظائف غير المصدرة

في حالة ts.union ، .cbindts و .makeNamesTs هي وظائف غير معلنة من مساحة الاسم stats. يمكنك عرض التعليمات البرمجية المصدر للوظائف غير المصدرة باستخدام عامل التشغيل ::: أو getAnywhere.

> stats:::.makeNamesTs
function (...) 
{
    l <- as.list(substitute(list(...)))[-1L]
    nm <- names(l)
    fixup <- if (is.null(nm)) 
        seq_along(l)
    else nm == ""
    dep <- sapply(l[fixup], function(x) deparse(x)[1L])
    if (is.null(nm)) 
        return(dep)
    if (any(fixup)) 
        nm[fixup] <- dep
    nm
}
<bytecode: 0x38140d0>
<environment: namespace:stats>

وظائف استدعاء رمز المترجمة

لاحظ أن كلمة "compiled" لا تشير إلى رمز R byte-compiled كما تم إنشاؤه بواسطة compiler package. يشير سطر <bytecode: 0x294e410> في الإخراج أعلاه إلى أن الوظيفة يتم ترجمتها بواسطة البايت ، ولا يزال بإمكانك عرض المصدر من سطر الأوامر R.

الوظائف التي تستدعي .C أو .Call أو .Fortran أو .External أو .Internal أو .Primitive تستدعي نقاط الإدخال في التعليمات البرمجية المترجمة ، لذلك يجب أن تبحث عن مصادر التعليمات البرمجية المترجمة ، إذا كنت تريد أن تفهم الوظيفة بالكامل. هذه GitHub مرآة شفرة المصدر R هو مكان لائق للبدء. يمكن أن تكون الوظيفة pryr::show_c_source أداة مفيدة حيث ستنقلك مباشرةً إلى صفحة GitHub لمكالمات .Internal و .Primitive. قد تستخدم الحزم .C و .Call و .Fortran و .External؛ لكن ليس .Internal أو .Primitive ، لأن هذه تستخدم للاتصال بالوظائف المضمنة في مترجم R.

قد تستخدم المكالمات إلى بعض الوظائف أعلاه كائن بدلاً من سلسلة أحرف للإشارة إلى الدالة المترجمة. في هذه الحالات ، يكون الكائن من فئة "NativeSymbolInfo" أو "RegisteredNativeSymbol" أو "NativeSymbol" ؛ وطباعة الكائن تعطي معلومات مفيدة. على سبيل المثال ، optim تستدعي .External2(C_optimhess, res$par, fn1, gr1, con) (لاحظ أن C_optimhess ، وليس "C_optimhess"). optim موجود في حزمة stats ، لذلك يمكنك كتابة stats:::C_optimhess لرؤية معلومات حول الدالة المترجمة التي يتم استدعاؤها.

التعليمات البرمجية المترجمة في حزمة

إذا كنت تريد عرض التعليمات البرمجية المترجمة في حزمة ، فستحتاج إلى تنزيل/تفريغ مصدر الحزمة. الثنائيات المثبتة ليست كافية. يتوفر رمز مصدر الحزمة من نفس مستودع CRAN (أو CRAN المتوافق) الذي تم تثبيت الحزمة منه في الأصل. وظيفة download.packages() يمكنها الحصول على مصدر الحزمة لك.

download.packages(pkgs = "Matrix", 
                  destdir = ".",
                  type = "source")

سيؤدي ذلك إلى تنزيل الإصدار المصدر لحزمة Matrix وحفظ ملف .tar.gz المقابل في الدليل الحالي. يمكن العثور على التعليمات البرمجية المصدر للوظائف المترجمة في دليل src الخاص بالملف غير المضغوط وغير المُتداول. يمكن إجراء الخطوة غير المضغوطة وغير الثابتة خارج R ، أو من R باستخدام دالة untar(). من الممكن دمج خطوة التنزيل والتوسيع في مكالمة واحدة (لاحظ أنه يمكن تنزيل حزمة واحدة فقط وتفريغها بهذه الطريقة):

untar(download.packages(pkgs = "Matrix",
                        destdir = ".",
                        type = "source")[,2])

بدلاً من ذلك ، إذا تمت استضافة تطوير الحزمة بشكل عام (على سبيل المثال عبر GitHub ، R-Forge أو أو - RForge.net ) ، يمكنك على الأرجح تصفح التعليمات البرمجية المصدر عبر الإنترنت.

التعليمات البرمجية المترجمة في الحزمة الأساسية

تعتبر حزم معينة حزم "أساسية". تأتي هذه الحزم مع R وتم قفل نسختها على إصدار R. وتشمل الأمثلة base و compiler و stats و utils. على هذا النحو ، فهي غير متوفرة كحزم منفصلة قابلة للتنزيل على CRAN كما هو موضح أعلاه. بدلاً من ذلك ، فهي جزء من شجرة مصدر R في دلائل الحزمة الفردية تحت /src/library/. يتم وصف كيفية الوصول إلى مصدر R في القسم التالي.

التعليمات البرمجية المترجمة المضمنة في مترجم R

إذا كنت ترغب في عرض الكود المدمج في مترجم R ، فستحتاج إلى تنزيل/تفريغ مصادر R ؛ أو يمكنك عرض المصادر عبر الإنترنت من خلال R مستودع التخريب أو مرآة جيثب الخاصة بـ Winston Chang .

تعتبر المقالة الإخبارية الخاصة بـ Uwe Ligges R (PDF) (ص 43) مرجعًا عامًا جيدًا لكيفية عرض التعليمات البرمجية المصدر لوظائف .Internal و .Primitive. الخطوات الأساسية هي البحث أولاً عن اسم الوظيفة في src/main/names.c ثم البحث عن اسم "C-entry" في الملفات الموجودة في src/main/*.

453
Joshua Ulrich

بالإضافة إلى الإجابات الأخرى على هذا السؤال وتكراراته ، إليك طريقة جيدة للحصول على شفرة المصدر لوظيفة الحزمة دون الحاجة إلى معرفة الحزمة التي توجد بها. على سبيل المثال إذا كنا نريد مصدر randomForest::rfcv():

إلى عرض/تحرير في نافذة منبثقة:

edit(getAnywhere('rfcv'), file='source_rfcv.r')

إلى إعادة التوجيه إلى ملف منفصل :

capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
89
smci

يتم الكشف عنها عند تصحيح الأخطاء باستخدام دالة debug (). افترض أنك تريد مشاهدة التعليمات البرمجية الأساسية في t() وظيفة تبديل. مجرد كتابة 'ر' ، لا يكشف الكثير.

>t 
function (x) 
UseMethod("t")
<bytecode: 0x000000003085c010>
<environment: namespace:base>

لكن باستخدام 'debug (functionName)' ، فإنه يكشف عن الكود الأساسي ، بدون الباطن.

> debug(t)
> t(co2)
debugging in: t(co2)
debug: UseMethod("t")
Browse[2]> 
debugging in: t.ts(co2)
debug: {
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
Browse[3]> 
debug: cl <- oldClass(x)
Browse[3]> 
debug: other <- !(cl %in% c("ts", "mts"))
Browse[3]> 
debug: class(x) <- if (any(other)) cl[other]
Browse[3]>  
debug: attr(x, "tsp") <- NULL
Browse[3]> 
debug: t(x)

تحرير: debugonce () ينجز نفسه دون الحاجة إلى استخدام undebug ()

25
Selva

لم أر كيف يتلاءم هذا مع تدفق الإجابة الرئيسية ولكنه أوقفني لفترة من الوقت لذا فأضفته هنا:

مشغلي Infix

للاطلاع على الكود المصدري لبعض مشغلي infix الأساسيين (على سبيل المثال ، %% ، %*% ، %in%) ، استخدم getAnywhere ، على سبيل المثال:

getAnywhere("%%")
# A single object matching ‘%%’ was found
# It was found in the following places
#   package:base
#   namespace:base
#  with value
#
# function (e1, e2)  .Primitive("%%")

تغطي الإجابة الرئيسية كيفية استخدام المرايا لحفر أعمق.

18
MichaelChirico

للوظائف غير البدائية ، تتضمن قاعدة R دالة تسمى body() والتي تُرجع نص الدالة. على سبيل المثال ، يمكن عرض مصدر الدالة print.Date():

body(print.Date)

سوف تنتج هذا:

{
    if (is.null(max)) 
        max <- getOption("max.print", 9999L)
    if (max < length(x)) {
        print(format(x[seq_len(max)]), max = max, ...)
        cat(" [ reached getOption(\"max.print\") -- omitted", 
            length(x) - max, "entries ]\n")
    }
    else print(format(x), max = max, ...)
    invisible(x)
}

إذا كنت تعمل في برنامج نصي وتريد رمز الوظيفة باعتباره ناقل أحرف ، فيمكنك الحصول عليه.

capture.output(print(body(print.Date)))

سوف تحصل:

[1] "{"                                                                   
[2] "    if (is.null(max)) "                                              
[3] "        max <- getOption(\"max.print\", 9999L)"                      
[4] "    if (max < length(x)) {"                                          
[5] "        print(format(x[seq_len(max)]), max = max, ...)"              
[6] "        cat(\" [ reached getOption(\\\"max.print\\\") -- omitted\", "
[7] "            length(x) - max, \"entries ]\\n\")"                      
[8] "    }"                                                               
[9] "    else print(format(x), max = max, ...)"                           
[10] "    invisible(x)"                                                    
[11] "}"     

لماذا أريد أن أفعل هذا الشيء؟ كنت أقوم بإنشاء كائن S3 مخصص (x ، حيث class(x) = "foo") بناءً على قائمة. أحد أعضاء القائمة (المسمى "مرح") كان وظيفة وأردت print.foo() لعرض كود مصدر الوظيفة ، المسافة البادئة. انتهى بي الأمر مع المقتطف التالي في print.foo():

sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0("      ", sourceVector, "\n"))

الذي يقوم بادئة وعرض الكود المرتبط بـ x[["fun"]].

17
Geoffrey Poole

هناك وظيفة مفيدة للغاية في R edit

new_optim <- edit(optim)

سيفتح الكود المصدري لـ optim باستخدام المحرر المحدد في R's options ، ثم يمكنك تحريره وتعيين الوظيفة المعدلة إلى new_optim. تعجبني هذه الوظيفة كثيرًا لعرض التعليمات البرمجية أو تصحيح التعليمات البرمجية ، على سبيل المثال ، طباعة بعض الرسائل أو المتغيرات أو حتى تعيينها لمتغيرات عمومية لمزيد من الاستكشاف (بالطبع يمكنك استخدام debug).

إذا كنت تريد فقط عرض التعليمات البرمجية المصدر ولا تريد طباعة التعليمات البرمجية المصدر المزعجة طويلة على وحدة التحكم الخاصة بك ، يمكنك استخدام

invisible(edit(optim))

بوضوح ، لا يمكن استخدام هذا لعرض شفرة مصدر C/C++ أو Fortran.

راجع للشغل ، edit يمكن فتح كائنات أخرى مثل القائمة ، المصفوفة ، وما إلى ذلك ، مما يدل على بنية البيانات مع السمات كذلك. يمكن استخدام الدالة de لفتح محرر مثل Excel (إذا كان يدعم واجهة المستخدم الرسومية) لتعديل المصفوفة أو إطار البيانات وإرجاع الجديد. يكون هذا مفيدًا في بعض الأحيان ، ولكن يجب تجنبه في الحالة المعتادة ، خاصة عندما تكون المصفوفة كبيرة.

9
Eric

طالما أن الوظيفة مكتوبة بـ R فقط C/C++/Fortran خالصة ، يمكن للمرء استخدام ما يلي. وإلا فإن أفضل طريقة هي تصحيح الأخطاء واستخدام " القفز إلى ":

> functionBody(functionName)
6
MCH

View([function_name]) - على سبيل المثال. View(mean) تأكد من استخدام الأحرف الكبيرة [V]. سيتم فتح الكود للقراءة فقط في المحرر.

4
Koo

يمكنك أيضًا محاولة استخدام print.function() ، وهو S3 عام ، للحصول على وظيفة الكتابة في وحدة التحكم.

4
strboul

في RStudio ، هناك (على الأقل) 3 طرق:

  1. اضغط على المفتاح F2 أثناء وجود المؤشر في أي وظيفة.
  2. انقر فوق اسم الوظيفة أثناء الضغط على Ctrl أو Command
  3. View (function_name) (كما هو مذكور أعلاه)

سيتم فتح جزء جديد برمز المصدر. إذا وصلت .Primitive أو .C ستحتاج إلى طريقة أخرى ، آسف.

3
Arthur Yip