programing

왜 'eval'을 사용하는 것이 나쁜 관행입니까?

iphone6s 2023. 6. 6. 00:37
반응형

왜 'eval'을 사용하는 것이 나쁜 관행입니까?

저는 제 노래의 데이터를 쉽게 저장하기 위해 다음 수업을 이용합니다.

class Song:
    """The class to store the details of each song"""
    attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
    def __init__(self):
        for att in self.attsToStore:
            exec 'self.%s=None'%(att.lower()) in locals()
    def setDetail(self, key, val):
        if key in self.attsToStore:
            exec 'self.%s=val'%(key.lower()) in locals()

저는 이것이 단지 그것을 쓰는 것보다 훨씬 더 확장 가능하다고 느낍니다.if/else 저는 그런 말을 적이 . 하지만, 저는 들었습니다.eval안전하지 않습니다.그래요? 위험성은 무엇인가요?어떻게할 수 요?self위험을 초래하지 않고 동적으로)?

예, 용을 사용합니다.eval나쁜 관행입니다.이유를 , 가지이유말씀자면리드를몇,면자▁just,

  1. 그것을 하는 더 좋은 방법은 거의 항상 있습니다.
  2. 매우 위험하고 불안정합니다.
  3. 디버깅을 어렵게 합니다.
  4. 느림

이 경우 setattr을 대신 사용할 수 있습니다.

class Song:
    """The class to store the details of each song"""
    attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
    def __init__(self):
        for att in self.attsToStore:
            setattr(self, att.lower(), None)
    def setDetail(self, key, val):
        if key in self.attsToStore:
            setattr(self, key.lower(), val)

사용해야 하는 경우가 있습니다.eval또는exec하지만 그들은 희귀합니다.용사를 합니다.eval당신의 경우는 확실히 나쁜 관행입니다.ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠeval그리고.exec잘못된 장소에서 자주 사용됩니다.

댓글에 대한 회신:

일부 의견이 다른 것 같습니다.evalOP 사건에서 '매우 위험하고 불안정한' 것입니다.이 경우에는 해당될 수 있지만 일반적으로는 해당되지 않습니다.질문은 일반적이었고 제가 열거한 이유는 일반적인 경우에도 사실입니다.

용사를 합니다.eval약한 것이지, 분명히 나쁜 관행은 아닙니다.

  1. 이는 "소프트웨어의 기본 원칙"을 위반합니다.원본은 실행 파일의 합계가 아닙니다.에도, 당의출외에, 과같주있습다에 대한 .eval분명히 이해해야 할 것입니다.이러한 이유로, 그것은 최후의 수단입니다.

  2. 그것은 보통 무분별한 디자인의 표시입니다.동적 소스 코드를 즉시 구축할 수 있는 좋은 이유는 거의 없습니다.위임 및 기타 OO 설계 기법을 사용하면 거의 모든 작업을 수행할 수 있습니다.

  3. 이것은 작은 코드 조각들의 비교적 느린 즉석 컴파일로 이어집니다.더 나은 설계 패턴을 사용하여 피할 수 있는 오버헤드입니다.

각주로서, 정신나간 소시오패스들의 손에서, 그것은 잘 풀리지 않을 수도 있습니다.하지만 정신 나간 소시오패스 사용자나 관리자와 마주칠 때는 애초에 해석된 파이썬을 주지 않는 것이 최선입니다.을 질 수 ; 진한악인손에의정파, 이은책질수있습다니임을썬.eval위험을 전혀 증가시키지 않습니다.

예, 다음과 같습니다.

Python을 사용한 해킹:

>>> eval(input())
"__import__('os').listdir('.')"
...........
...........   #dir listing
...........

아래 코드는 Windows 컴퓨터에서 실행 중인 모든 작업을 나열합니다.

>>> eval(input())
"__import__('subprocess').Popen(['tasklist'],stdout=__import__('subprocess').PIPE).communicate()[0]"

Linux의 경우:

>>> eval(input())
"__import__('subprocess').Popen(['ps', 'aux'],stdout=__import__('subprocess').PIPE).communicate()[0]"

이 경우에는, 그렇습니다.대신에

exec 'self.Foo=val'

당신은 내장된 기능을 사용해야 합니다.setattr:

setattr(self, 'Foo', val)

다른 사용자들은 어떻게 당신의 코드가 의존하지 않도록 변경될 수 있는지 지적했습니다.eval합법적인 사용 사례를 제시하겠습니다.evalCPython에서도 발견되는 하나: 테스트.

여기 제가 찾은 한 가지 예가 있습니다.(+|-|~)b'a'을 유발합니다.TypeError:

def test_bad_types(self):
    for op in '+', '-', '~':
        self.assertRaises(TypeError, eval, op + "b'a'")
        self.assertRaises(TypeError, eval, op + "'a'")

여기서 사용법은 분명히 나쁜 관행이 아닙니다. 입력을 정의하고 행동을 관찰할 뿐입니다. eval테스트에 편리합니다.

다음에 대한 이 검색 보기evalCPythongit 저장소에서 수행되며, eval을 사용한 테스트가 많이 사용됩니다.

문제의 특정 문제에 대해 사용할 수 있는 몇 가지 대안이 있다는 것에 주목할 필요가 있습니다.eval:

언급한 것처럼 가장 간단한 것은 사용하는 것입니다.setattr:

def __init__(self):
    for name in attsToStore:
        setattr(self, name, None)

덜 명확한 접근 방식은 객체의 정보를 업데이트하는 것입니다.__dict__정으로반대다하경속것으로 하는 것만 .None그러면 이것은 위의 것보다 덜 간단합니다.하지만 이것을 고려해 보십시오.

def __init__(self, **kwargs):
    for name in self.attsToStore:
       self.__dict__[name] = kwargs.get(name, None)

이를 통해 키워드 인수를 생성자에게 전달할 수 있습니다. 예:

s = Song(name='History', artist='The Verve')

은 또한다같기사수있다습니용할을능은과음다▁of있니수를 사용할 수 있습니다.locals()보다 명시적인 예:

s = Song(**locals())

... 로 할당하고 그리고, 만약 당신이 정말로 할당하고 싶다면.None름이검속대한성에에 이 있는 locals():

s = Song(**dict([(k, None) for k in locals().keys()]))

하는 또 속목성록대기객제또공는체하다접다것방니입클정는의래하를스식은근른에에한본을값▁the'▁class▁another▁with다니것입▁for를 정의하는 것입니다.__getattr__방법:

def __getattr__(self, name):
    if name in self.attsToStore:
        return None
    raise NameError, name

이 메서드는 명명된 특성이 정상적인 방법으로 발견되지 않을 때 호출됩니다. 방식은 덜 직접적입니다.__dict__그러나 속성이 존재하지 않는 한 실제로 속성을 만들지 않는다는 장점이 있으며, 이는 클래스의 메모리 사용량을 상당히 줄일 수 있습니다.

이 모든 것의 요점:일반적으로 피해야 할 많은 이유가 있습니다.eval제어할 수 없는 코드 실행의 보안 문제, 디버깅할 수 없는 코드의 실제 문제 등.하지만 더 중요한 이유는 일반적으로 사용할 필요가 없다는 것입니다.Python은 내부 메커니즘의 대부분을 프로그래머에게 노출하므로 코드를 작성하는 코드를 작성할 필요가 거의 없습니다.

eval()는 사용자가 제공한 입력을 처리하는 데 사용되며, 사용자는 다음과 같은 기능을 제공하여 Drop-to-REPL을 사용할 수 있습니다.

"__import__('code').InteractiveConsole(locals=globals()).interact()"

당신은 그것을 피할 수 있지만, 일반적으로 당신은 당신의 응용 프로그램에서 임의 코드 실행을 위한 벡터를 원하지 않습니다.

@Nadia Alramli 답변 외에도, 저는 Python이 처음이고 어떻게 사용하는지 확인하고 싶었기 때문에eval시간에 영향을 미칠 것입니다. 작은 프로그램을 시도해 보았는데 아래의 관찰 결과가 있었습니다.

#Difference while using print() with eval() and w/o eval() to print an int = 0.528969s per 100000 evals()

from datetime import datetime
def strOfNos():
    s = []
    for x in range(100000):
        s.append(str(x))
    return s

strOfNos()
print(datetime.now())
for x in strOfNos():
    print(x) #print(eval(x))
print(datetime.now())

#when using eval(int)
#2018-10-29 12:36:08.206022
#2018-10-29 12:36:10.407911
#diff = 2.201889 s

#when using int only
#2018-10-29 12:37:50.022753
#2018-10-29 12:37:51.090045
#diff = 1.67292

언급URL : https://stackoverflow.com/questions/1832940/why-is-using-eval-a-bad-practice

반응형