ตัวแปรส่วนกลางและท้องถิ่นใน R


126

ฉันเป็นมือใหม่สำหรับ R และฉันค่อนข้างสับสนกับการใช้ตัวแปรท้องถิ่นและทั่วโลกใน R

ฉันอ่านโพสต์บนอินเทอร์เน็ตที่ระบุว่าฉันใช้=หรือ<-ฉันจะกำหนดตัวแปรในสภาพแวดล้อมปัจจุบันและ<<-ฉันสามารถเข้าถึงตัวแปรส่วนกลางได้เมื่ออยู่ในฟังก์ชัน

อย่างไรก็ตามตามที่ฉันจำได้ในตัวแปรโลคัล C ++ เกิดขึ้นทุกครั้งที่คุณประกาศตัวแปรภายในวงเล็บ{}ดังนั้นฉันจึงสงสัยว่านี่จะเหมือนกันสำหรับ R หรือไม่? หรือเป็นเพียงสำหรับฟังก์ชันใน R ที่เรามีแนวคิดของตัวแปรท้องถิ่น

ฉันได้ทำการทดลองเล็กน้อยซึ่งดูเหมือนจะชี้ให้เห็นว่าเพียงวงเล็บไม่เพียงพอฉันได้รับอะไรผิดปกติหรือไม่

{
   x=matrix(1:10,2,5)
}
print(x[2,2])
[1] 4

โค้ดบางส่วนที่จะเรียกใช้นอกเหนือจากคำตอบเหล่านี้: globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env, …
isomorphismes

Error: could not find function "%>%"@isomorphismes, เป็นการมอบหมายรูปแบบอื่นหรือไม่?
Aaron McDaid

1
เธรดที่เกี่ยวข้องใน R-help: ตัวดำเนินการ "<< -" หมายถึงอะไร .
Henrik

2
@AaronMcDaid สวัสดีขอโทษที่ไม่ตอบเร็ว! ที่มาจากrequire(magrittr). เป็นวิธีการใช้ฟังก์ชันทางด้านขวา ( x | f1 | f2 | f3) แทนที่จะเป็นทางซ้าย ( f3( f2( f1( x ) ) ))
isomorphismes

คำตอบ:


153

ตัวแปรที่ประกาศภายในฟังก์ชันเป็นตัวแปรภายในของฟังก์ชันนั้น ตัวอย่างเช่น:

foo <- function() {
    bar <- 1
}
foo()
bar

ให้ข้อผิดพลาดต่อไปนี้: Error: object 'bar' not found.

หากคุณต้องการสร้างbarตัวแปรส่วนกลางคุณควรทำ:

foo <- function() {
    bar <<- 1
}
foo()
bar

ในกรณีbarนี้สามารถเข้าถึงได้จากภายนอกฟังก์ชัน

อย่างไรก็ตามไม่เหมือนกับภาษา C, C ++ หรือภาษาอื่น ๆ วงเล็บไม่ได้กำหนดขอบเขตของตัวแปร ตัวอย่างเช่นในข้อมูลโค้ดต่อไปนี้:

if (x > 10) {
    y <- 0
}
else {
    y <- 1
}

yยังคงสามารถเข้าถึงได้หลังจากif-elseคำสั่ง

คุณสามารถสร้างสภาพแวดล้อมที่ซ้อนกันได้เช่นกัน คุณสามารถดูลิงก์ทั้งสองนี้เพื่อทำความเข้าใจวิธีการใช้งาน:

  1. http://stat.ethz.ch/R-manual/R-devel/library/base/html/environment.html
  2. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

คุณมีตัวอย่างเล็ก ๆ ดังนี้

test.env <- new.env()

assign('var', 100, envir=test.env)
# or simply
test.env$var <- 100

get('var') # var cannot be found since it is not defined in this environment
get('var', envir=test.env) # now it can be found

136

<- ไม่มอบหมายงานในสภาพแวดล้อมปัจจุบัน

เมื่อคุณอยู่ในฟังก์ชัน R จะสร้างสภาพแวดล้อมใหม่สำหรับคุณ โดยค่าเริ่มต้นจะรวมทุกอย่างตั้งแต่สภาพแวดล้อมที่สร้างขึ้นเพื่อให้คุณสามารถใช้ตัวแปรเหล่านั้นได้เช่นกัน แต่สิ่งใหม่ที่คุณสร้างขึ้นจะไม่ถูกเขียนลงในสภาพแวดล้อมส่วนกลาง

ในกรณีส่วนใหญ่<<-จะกำหนดให้กับตัวแปรที่มีอยู่แล้วในสภาพแวดล้อมส่วนกลางหรือสร้างตัวแปรในสภาพแวดล้อมส่วนกลางแม้ว่าคุณจะอยู่ในฟังก์ชันก็ตาม อย่างไรก็ตามมันไม่ค่อยตรงไปตรงมาเท่าไหร่ สิ่งที่ทำคือตรวจสอบสภาพแวดล้อมหลักสำหรับตัวแปรที่มีชื่อที่น่าสนใจ หากไม่พบในสภาพแวดล้อมพาเรนต์ของคุณระบบจะไปที่พาเรนต์ของสภาวะแวดล้อมพาเรนต์ (ณ เวลาที่สร้างฟังก์ชัน) และดูที่นั่น มันยังคงขึ้นอยู่กับสภาพแวดล้อมทั่วโลกและหากไม่พบในสภาพแวดล้อมส่วนกลางก็จะกำหนดตัวแปรในสภาพแวดล้อมส่วนกลาง

สิ่งนี้อาจแสดงให้เห็นถึงสิ่งที่เกิดขึ้น

bar <- "global"
foo <- function(){
    bar <- "in foo"
    baz <- function(){
        bar <- "in baz - before <<-"
        bar <<- "in baz - after <<-"
        print(bar)
    }
    print(bar)
    baz()
    print(bar)
}
> bar
[1] "global"
> foo()
[1] "in foo"
[1] "in baz - before <<-"
[1] "in baz - after <<-"
> bar
[1] "global"

ในครั้งแรกที่เราพิมพ์แถบเรายังไม่ได้เรียกfooมันจึงควรจะเป็นแบบโกลบอล - นี่ก็สมเหตุสมผลดี ครั้งที่สองที่เราพิมพ์ด้านในfooก่อนที่จะเรียกbazค่า "in foo" จึงเหมาะสม ต่อไปนี้เป็นที่ที่เราจะเห็นสิ่งที่<<-กำลังทำอยู่ ค่าถัดไปที่พิมพ์คือ "in baz - before << -" แม้ว่าคำสั่งพิมพ์จะมาหลัง<<-. นี่เป็นเพราะ<<-ไม่ได้ดูในสภาพแวดล้อมปัจจุบัน (เว้นแต่คุณจะอยู่ในสภาพแวดล้อมทั่วโลกซึ่งในกรณีนี้<<-จะเป็นเช่นนั้น<-) ดังนั้นภายในbazค่าของแท่งจะเป็น "in baz - before << -" เมื่อเราเรียกbazสำเนาของแถบด้านในของfoogets เปลี่ยนเป็น "in baz" แต่อย่างที่เราเห็น global barไม่เปลี่ยนแปลงbarที่กำหนดไว้ภายในfooอยู่ในสภาพแวดล้อมพาเรนต์เมื่อเราสร้างbazดังนั้นนี่คือสำเนาแรกของbarที่<<-เห็นและสำเนาที่กำหนดให้ ดังนั้นจึง<<-ไม่ใช่แค่การกำหนดให้กับสภาพแวดล้อมทั่วโลกโดยตรง

<<-เป็นเรื่องยุ่งยากและฉันจะไม่แนะนำให้ใช้หากคุณสามารถหลีกเลี่ยงได้ หากคุณต้องการกำหนดให้กับสภาพแวดล้อมส่วนกลางจริงๆคุณสามารถใช้ฟังก์ชันกำหนดและบอกอย่างชัดเจนว่าคุณต้องการกำหนดทั่วโลก

ตอนนี้ฉันเปลี่ยน<<-เป็นคำสั่งมอบหมายและเราสามารถดูว่ามีผลอย่างไร:

bar <- "global"
foo <- function(){
    bar <- "in foo"   
    baz <- function(){
        assign("bar", "in baz", envir = .GlobalEnv)
    }
    print(bar)
    baz()
    print(bar)
}
bar
#[1] "global"
foo()
#[1] "in foo"
#[1] "in foo"
bar
#[1] "in baz"

ดังนั้นทั้งสองครั้งที่เราพิมพ์แถบภายในfooค่าจึงเป็น "in foo" แม้ว่าจะโทรbazแล้วก็ตาม นี่เป็นเพราะassignไม่เคยพิจารณาสำเนาของbarinside of foo ด้วยซ้ำเพราะเราบอกว่าจะดูตรงไหน อย่างไรก็ตามในครั้งนี้ค่าของแท่งในสภาพแวดล้อมทั่วโลกมีการเปลี่ยนแปลงเนื่องจากเรากำหนดไว้ที่นั่นอย่างชัดเจน

ตอนนี้คุณถามเกี่ยวกับการสร้างตัวแปรในพื้นที่และคุณสามารถทำได้ค่อนข้างง่ายเช่นกันโดยไม่ต้องสร้างฟังก์ชัน ... เราต้องใช้localฟังก์ชัน

bar <- "global"
# local will create a new environment for us to play in
local({
    bar <- "local"
    print(bar)
})
#[1] "local"
bar
#[1] "global"

2

อีกเล็กน้อยตามแนวเดียวกัน

attrs <- {}

attrs.a <- 1

f <- function(d) {
    attrs.a <- d
}

f(20)
print(attrs.a)

จะพิมพ์ "1"

attrs <- {}

attrs.a <- 1

f <- function(d) {
   attrs.a <<- d
}

f(20)
print(attrs.a)

จะพิมพ์ "20"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.