2011-08-11 6 views
1

사전의 문자열 표현을 취하고 사전의 항목을 나타내는 튜플 목록을 출력하는 Python 스크립트를 만들고 싶습니다. 문질러서, 정의되지 않은 변수를 가져 오길 원합니다.정의되지 않은 변수에 eval() 사용하기

입력 : {'test': test}

출력 : 내가 사전에 읽고 아직 정의되지 않은 변수를 정의하는 몇 가지 코드를 생성 한 [('test': test)]

하지만 때 내가 예는이 최고 보여 eval() 결과 변수 이름 대신 실제 변수 값으로 대체됩니다. 그것은 완벽하게 입력 문자열과 일치하는 것입니다 인쇄하지만, DICT 대신이 0의 값에 대입 것을,

import sys 
import re 

if __name__ == "__main__": 
    instr = sys.argv[1] 
    success = False 
    while not success: 
     try: 
      indict = eval(instr) 
      success = True 
     except NameError, e: 
      defname = re.search("name '([^\']*)' is not defined", str(e)) 
      locals()[defname.group(1)] = 0 
    print indict 

나는 위에서 정의 된 입력 값에 대해 기대했다 : 여기

코드입니다 test입니다. 내가 ast.literal_eval을 시도

{'test': 0} 

하지만이 정의되어있어 경우에도 문자 그대로의 모든 변수 이름에 대한 ValueError: malformed string가 발생합니다 : 따라서 스크립트를 출력합니다.

따라서 제 질문은 : 변수 이름을 잃지 않고 입력 사전을 변환하는 방법이 있습니까?

답변

0

나는 변수의 이름에 대해 고유 한 문자열에 대입하여이 문제를 해결했다.

import sys 
import re 

if __name__ == "__main__": 
    instr = sys.argv[1] 
    subs = [] 
    success = False 
    while not success: 
     try: 
      indict = eval(instr) 
      success = True 
     except NameError, e: 
      defname = re.search("name '([^\']*)' is not defined", str(e)).group(1) 
      subs.append(defname) 
      locals()[defname] = '//substitute{%d}' % (len(subs) - 1) 
    outlist = indict.items() 
    outstr = str(outlist) 
    for i, sub in enumerate(subs): 
     outstr = outstr.replace("'//substitute{%d}'" % i, sub) 
    print outstr 

입력 : {"test": test}

출력 : [('test', test)]

입력 : {"test": [{"test": test}, {word: "word"}]}

출력 : [('test', [{'test': test}, {word: 'word'}])] (이 바람직하다 있습니다, 내가 원하지 않는이 원하는 결과를 생성 내부 사전 압축).

사소한 단점은 입력 문자열에서 아무 곳에서나 사용하도록 선택한 대체 문자열을 가질 수 없다는 것이지만이 스크립트를 사용하고자하는 대상에 문제가되지 않는다는 것이 합리적이라고 확신합니다.

2

ast 모듈을 사용하지만 literal_eval은 사용하지 않습니다. 변수 참조를 찾으면 변수 이름을 출력에 삽입하면됩니다.

+0

'ast.walk'의 정의 (내 자신의 실험)에 따르면, 노드는 특별한 순서없이 되돌려 져서, 입력 문자열의 신뢰할 수있는 표현을 출력 할 수 없습니다. –

+0

'ast.walk'는 당신이 원하는 것이 아닙니다. 트리의 각 노드를 방문해야합니다. 예제는 http://stackoverflow.com/questions/1515357/simple-example-of-how-to-use-ast-nodevisitor를 참조하십시오. –

0

나는 당신이 가지고있는 문제는 그 변수의 값 대신에 변수의 이름을 평가하기를 원한다고 생각한다. 특히, test은 파이썬에서 값이 아니기 때문에 {'test':test}은 사전 인쇄의 결과물이 아니며, 아마도 변수 이름 일 수 있습니다. 당신이 얻을 수있는 가장 가까운 당신이 원하는 무엇을 주기로 당신은 eval을 속일 수

{'test':'test'} 
1

를 얻을 수

locals()[defname.group(1)] = defname.group(1) 

를 할당한다 :

class Reflector(object): 
    def __getitem__(self, name): 
     return name 

s = "{'test':test}" 

print eval(s, globals(), Reflector()) 

는 생산 :

{'test': 'test'} 

을 평소 동굴 eval의 위험에 대해 ats : 비록 당신이 이러한 문자열의 출처에 대해 의심이 있다면, 당신은 해킹에 대한 자신을 열어 있습니다.

+0

나는 출처에 대해 의심의 여지가 없다. –

+0

이것은 흥미 롭습니다. 그러나 변수 대신 변수의 이름을 가진 문자열을 갖게되었습니다. –

0

적절한 해결 방법은 유용하지 않은 변수를 보존하는 코드 eval을 전달하는 것입니다. 당신은 평가 후면 어떤 dict 서브 클래스를 전달할 수 있습니다, 당신은 딕셔너리의 __missing__ 방법은 '정의되지 않은 변수'개체를 반환 재정의 할 수

>>> class Var(object): 
...  def __init__(self, name): 
...   self.name = name 
...  def __repr__(self): 
...   return "Var(%r)" % (self.name,) 
... 
>>> class UndefSubst(dict): 
...  def __missing__(self, key): 
...   return Var(key) 
... 
>>> foo = 'bar' 
>>> eval("{'baz': quux, 1: foo}", UndefSubst(locals())) 
{1: 'bar', 'baz': Var('quux')} 
관련 문제