A pesar de todas las respuestas que muestran cómo resolver eso con parse ... ¿Por qué necesita almacenar tipos de idioma en un carácter string? La respuesta de Martin Mächler debería merecer muchos más votos a favor.
Petr Matousu el
77
Gracias @PetrMatousu. Sí, me sorprende ver cómo la información errónea se propaga en SO ahora ... por personas que votan por eval(parse(text = *)) soluciones falsas.
Martin Mächler
2
Quiero ejecutar scripts de la forma: QQ = c('11','12','13','21','22','23')es decir: QQ = c (..., 'ij', ..) con i, j variando en un rango que puede variar de una ejecución a otra. Para este y otros ejemplos similares, puedo escribir el script como paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep=""), y la opción eval(parse(text=...))crea el vector QQ en el entorno de trabajo según el script. ¿Cuál sería la forma correcta de codificador R para hacer esto, si no fuera con "text = ..."?
VictorZurkowski
Respuestas:
418
La eval()función evalúa una expresión, pero "5+5"es una cadena, no una expresión. Use parse()con text=<string>para cambiar la cadena en una expresión:
Llamar eval()invoca muchos comportamientos, algunos no son inmediatamente obvios:
> class(eval(parse(text="5+5")))[1]"numeric"> class(eval(parse(text="gray")))[1]"function"> class(eval(parse(text="blue")))
Error in eval(expr, envir, enclos): object 'blue' not found
Se deben especificar los efectos secundarios del uso de eval (parse). Por ejemplo, si tiene un nombre de variable predefinido igual a "David" y lo reasigna usando eval (parse (text = "name") == "Alexander", obtendrá un error porque eval & parse no devuelve un Expresión R que se puede evaluar.
Crt
1
@NelsonGon: expresiones no evaluadas construidas usando quote(), bquote()o las herramientas más sofisticadas proporcionadas por el rlangpaquete.
Artem Sokolov
@ArtemSokolov Gracias, de alguna manera sigo volviendo a esta pregunta en busca de una alternativa. Lo miré, rlangpero lo más cercano que encontré fue parse_exprqué llamadas, parse_exprsa su vez, es lo mismo que usar parsey envolver, lo evalque parece ser lo mismo que aquí. No estoy seguro de cuál sería la ventaja de usar rlang.
NelsonGon
1
@NelsonGon: con rlang, trabajarías directamente con expresiones, no con cadenas. No es necesario un paso de análisis. Tiene dos ventajas. 1. Las manipulaciones de expresiones siempre producirán expresiones válidas. Las manipulaciones de cadenas solo producirán cadenas válidas. No sabrá si son expresiones válidas hasta que las analice. 2. No existe un equivalente a la substitute()clase de funciones en el mundo de las cadenas, lo que limita severamente su capacidad para manipular las llamadas a funciones. Considere esta envoltura glm . ¿Cómo sería un equivalente de cadena?
Artem Sokolov
100
Puede usar la parse()función para convertir los caracteres en una expresión. Debe especificar que la entrada es texto, porque parse espera un archivo por defecto:
> fortunes :: fortune ("la respuesta es parse") Si la respuesta es parse (), generalmente debería repensar la pregunta. - Thomas Lumley R-help (febrero de 2005)>
Martin Mächler
13
@ MartinMächler ¡Eso es irónico, porque los paquetes principales de R se usan parsetodo el tiempo! github.com/wch/r-source/…
geneorama
49
Lo siento, pero no entiendo por qué tanta gente incluso piensa que una cadena es algo que podría evaluarse. Debes cambiar tu mentalidad, de verdad. Olvídese de todas las conexiones entre cadenas en un lado y expresiones, llamadas, evaluación en el otro lado.
La (posiblemente) única conexión es vía parse(text = ....)y todos los buenos programadores de R deben saber que rara vez es un medio eficiente o seguro para construir expresiones (o llamadas). Más bien, aprenda más sobre substitute(), quote()y posiblemente el poder de usar do.call(substitute, ......).
fortunes::fortune("answer is parse")# If the answer is parse() you should usually rethink the question.# -- Thomas Lumley# R-help (February 2005)
Dec.2017: Ok, aquí hay un ejemplo (en los comentarios, no hay un buen formato):
¿podrías dar un ejemplo? tal vez podría mostrarnos cómo "mantener" 5 + 5 en un objeto r, luego evaluarlo más tarde, usando comillas y sustitutos en lugar de un carácter y eval (parse (text =)?
Richard DiSalvo
3
Puedo estar un poco perdido. ¿En qué punto obtienes 10? ¿O ese no es el punto?
Nick S
@RichardDiSalvo: sí, q5 <- quote(5+5)arriba está la expresión (en realidad, la "llamada") 5+5y es un objeto R, pero no una cadena. Puedes evaluarlo en cualquier momento. Nuevamente: usando, quote (), substitute (), ... en su lugar, parse crea llamadas o expresiones directamente y de manera más eficiente que a través de parse (text =.). El uso eval()está bien, el uso parse(text=*)es propenso a errores y, a veces, es bastante ineficiente en comparación con las llamadas de construcción y su manipulación. @Nick S: Es eval(q5) o eval(e5) en nuestro ejemplo actual
Martin Mächler
@NickS: para obtener 10, evalúa la llamada / expresión, es decir, invoca eval(.). Mi punto era que la gente no debería usar, parse(text=.)sino más bien quote(.), etc., para construir la llamada que luego será eval()editada.
Martin Mächler
2
eval(quote())funciona en algunos casos, pero fallará en algunos casos donde eval(parse())funcionaría bien.
NelsonGon
18
Alternativamente, puede usar evalsdesde mi panderpaquete para capturar la salida y todas las advertencias, errores y otros mensajes junto con los resultados sin procesar:
Buena función llena un agujero dejado al evaluate::evaluatedevolver el objeto de resultado; eso deja su función adecuada para usar para llamar a través de mclapply. ¡Espero que esa característica permanezca!
russellpierce
Gracias @rpierce. Esta función se escribió originalmente en 2011 como parte de nuestro rapportpaquete, y desde entonces se ha mantenido activamente como un uso intensivo en nuestro servicio de rapporter.net , además de algunos otros proyectos, así que estoy seguro de que se mantendrá durante un tiempo. while :) Me alegra que lo encuentres útil, gracias por tus amables comentarios.
daroczig
14
Hoy en día también puedes usar la lazy_evalfunción del lazyevalpaquete.
Vine aquí buscando una rlangrespuesta, pero ¿qué pasa si alguna es la ventaja de esto sobre las alternativas básicas? En realidad, un examen minucioso del código utilizado muestra que, de hecho, está utilizando eval(parse(....))lo que quería evitar.
NelsonGon
44
No solo esos aspectos negativos, sino que su nombre también es engañoso. NO está evaluando una expresión. Debe llamarse parse_to_expr o algo más para indicar que el usuario sabrá que está destinado a argumentos de caracteres.
string
? La respuesta de Martin Mächler debería merecer muchos más votos a favor.eval(parse(text = *))
soluciones falsas.QQ = c('11','12','13','21','22','23')
es decir: QQ = c (..., 'ij', ..) con i, j variando en un rango que puede variar de una ejecución a otra. Para este y otros ejemplos similares, puedo escribir el script comopaste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")
, y la opcióneval(parse(text=...))
crea el vector QQ en el entorno de trabajo según el script. ¿Cuál sería la forma correcta de codificador R para hacer esto, si no fuera con "text = ..."?Respuestas:
La
eval()
función evalúa una expresión, pero"5+5"
es una cadena, no una expresión. Useparse()
context=<string>
para cambiar la cadena en una expresión:Llamar
eval()
invoca muchos comportamientos, algunos no son inmediatamente obvios:Ver también tryCatch .
fuente
quote()
,bquote()
o las herramientas más sofisticadas proporcionadas por elrlang
paquete.rlang
pero lo más cercano que encontré fueparse_expr
qué llamadas,parse_exprs
a su vez, es lo mismo que usarparse
y envolver, loeval
que parece ser lo mismo que aquí. No estoy seguro de cuál sería la ventaja de usarrlang
.rlang
, trabajarías directamente con expresiones, no con cadenas. No es necesario un paso de análisis. Tiene dos ventajas. 1. Las manipulaciones de expresiones siempre producirán expresiones válidas. Las manipulaciones de cadenas solo producirán cadenas válidas. No sabrá si son expresiones válidas hasta que las analice. 2. No existe un equivalente a lasubstitute()
clase de funciones en el mundo de las cadenas, lo que limita severamente su capacidad para manipular las llamadas a funciones. Considere esta envoltura glm . ¿Cómo sería un equivalente de cadena?Puede usar la
parse()
función para convertir los caracteres en una expresión. Debe especificar que la entrada es texto, porque parse espera un archivo por defecto:fuente
parse
todo el tiempo! github.com/wch/r-source/…Lo siento, pero no entiendo por qué tanta gente incluso piensa que una cadena es algo que podría evaluarse. Debes cambiar tu mentalidad, de verdad. Olvídese de todas las conexiones entre cadenas en un lado y expresiones, llamadas, evaluación en el otro lado.
La (posiblemente) única conexión es vía
parse(text = ....)
y todos los buenos programadores de R deben saber que rara vez es un medio eficiente o seguro para construir expresiones (o llamadas). Más bien, aprenda más sobresubstitute()
,quote()
y posiblemente el poder de usardo.call(substitute, ......)
.Dec.2017: Ok, aquí hay un ejemplo (en los comentarios, no hay un buen formato):
y si adquieres más experiencia aprenderás que
q5
es un"call"
mientras quee5
es un"expression"
, e incluso esoe5[[1]]
es idéntico aq5
:fuente
q5 <- quote(5+5)
arriba está la expresión (en realidad, la "llamada")5+5
y es un objeto R, pero no una cadena. Puedes evaluarlo en cualquier momento. Nuevamente: usando, quote (), substitute (), ... en su lugar, parse crea llamadas o expresiones directamente y de manera más eficiente que a través de parse (text =.). El usoeval()
está bien, el usoparse(text=*)
es propenso a errores y, a veces, es bastante ineficiente en comparación con las llamadas de construcción y su manipulación. @Nick S: Eseval(q5)
oeval(e5)
en nuestro ejemplo actualeval(.)
. Mi punto era que la gente no debería usar,parse(text=.)
sino más bienquote(.)
, etc., para construir la llamada que luego seráeval()
editada.eval(quote())
funciona en algunos casos, pero fallará en algunos casos dondeeval(parse())
funcionaría bien.Alternativamente, puede usar
evals
desde mipander
paquete para capturar la salida y todas las advertencias, errores y otros mensajes junto con los resultados sin procesar:fuente
evaluate::evaluate
devolver el objeto de resultado; eso deja su función adecuada para usar para llamar a través de mclapply. ¡Espero que esa característica permanezca!rapport
paquete, y desde entonces se ha mantenido activamente como un uso intensivo en nuestro servicio de rapporter.net , además de algunos otros proyectos, así que estoy seguro de que se mantendrá durante un tiempo. while :) Me alegra que lo encuentres útil, gracias por tus amables comentarios.Hoy en día también puedes usar la
lazy_eval
función dellazyeval
paquete.fuente
De manera similar usando
rlang
:fuente
rlang
respuesta, pero ¿qué pasa si alguna es la ventaja de esto sobre las alternativas básicas? En realidad, un examen minucioso del código utilizado muestra que, de hecho, está utilizandoeval(parse(....))
lo que quería evitar.