델파이는 언제 파이썬에서 유용합니까?


374

파이썬에 del키워드가 필요한 이유를 생각할 수 없습니다 (대부분의 언어에는 비슷한 키워드가없는 것 같습니다). 예를 들어 변수를 삭제하는 대신 변수를 할당 None할 수 있습니다. 사전에서 삭제할 때 del방법을 추가 할 수 있습니다.

del파이썬 에 보관해야 할 이유가 있습니까? 아니면 파이썬의 쓰레기 수거 전날의 흔적입니까?


46
역사적 메모 : 파이썬은 처음부터 가비지 수집을했습니다. 2.0 이전에는 Python의 가비지 수집기가 참조주기를 감지 할 수 없었지만 이는 관련이 없습니다 del.
Steven Rumbalski 2:27에

28
@Steven Rumbalksi, del과 관련이 있습니다. Del은 참조주기를 중단하는 데 사용되었습니다.
Winston Ewert

6
하지만 del항상 가질 수 있기 때문에 사전 쓰레기 수거에 대한 증거는 아닙니다 used = None. 특정 구문을 사용하는 것이 항상 의미가 있습니다. 우리는 지금 cylical GC를 가지고 있기 때문에 어느 쪽을 사용하고 싶은지는 작습니다.
Winston Ewert

3
> 대부분의 언어에는 비슷한 키워드가없는 것 같습니다. 대부분의 가비지 수집 언어는 그렇지 않습니다 (또는 변수를 수집 할 수 있다는 것을 GC에 암시하는 데만 사용). 가장 오래된 언어는 다음과 같습니다.-QuickBasic과 같은 오래된 기존 기본 언어 ERASE(특정 변수 CLEAR
강제 종료

답변:


499

첫째, 지역 변수 외에 다른 것을 델 수 있습니다

del list_item[4]
del dictionary["alpha"]

둘 다 분명히 유용해야합니다. 둘째, del지역 변수를 사용하면 의도가 더 명확 해집니다. 비교:

del foo

foo = None

나는의 경우 알고 del foo의도 범위에서 변수를 제거하는 것입니다. 그 foo = None일이 확실하지 않습니다 . 누군가 방금 할당 한 경우 foo = None죽은 코드라고 생각할 수 있습니다. 그러나 나는 코드 del foo를 작성하는 사람이 무엇 을하려고 하는지 즉시 알고 있습니다.


51
+1입니다. 무언가를 할당하면 나중에 사용하려는 의도를 전달합니다. 나는 del메모리 집약적 계산 에서만 사용되는 것을 보았지만 그것을 보았을 때 그것이 왜 필요한지 즉시 깨달았습니다.
detly

17
목록이나 사전에서 삭제하는 유스 케이스는 방법으로 쉽게 바꿀 수 있습니다 (질문에서 언급 한 것처럼). 나는 확실히 내가 아니에요 동의 의 사용과 함께 del(주석이 언어에 추가하지 않고 동일한 기능을 수행 할 수 있기 때문에) 의도 신호를,하지만 난 그게 최선의 대답 가정합니다.
Jason Baker

6
메소드에 부여 된 @JasonBaker. 슬라이스를 삭제하는 것은 방법을 사용하는 것이 더 어색합니다. 예, 당신은 의견을 사용할 수 있습니다. 그러나 나는 문장을 사용하는 것이 언어의 일부인 주석보다 낫다고 생각합니다.
Winston Ewert

2
@JasonBaker : 의도에 관한 것이 아니라이 두 구문은 매우 다른 두 가지를 수행합니다.
Pavel Šimerda

2
또한 각 사전에서 삭제하여 처리됩니다. len()같은 방식으로 함수에 이의를 제기 할 수도 있습니다 . 이 경우 질문이 의견이나 취향에 따라 종결되었을 수 있습니다. 파이썬은 단순히 메소드에 의존하는 대신 기본 조작을위한 기본 요소를 제공하는 경향이 있습니다.
Pavel Šimerda

161

파이썬 언어 레퍼런스 (Python Language Reference ) del의 기능 중 일부는 다음과 같습니다.

이름을 삭제하면 로컬 또는 글로벌 네임 스페이스에서 해당 이름의 바인딩이 제거됩니다.

None이름을 할당 해도 네임 스페이스에서 이름의 바인딩이 제거되지 않습니다.

(이름 바인딩을 제거하는 것이 실제로 유용한 지에 대한 논쟁이있을 수 있지만 다른 질문입니다.)


22
-1 포스터는 이미 이것을 이해하고 있으며, 이름 바인딩을 제거 할 이유를 묻습니다.
Winston Ewert

71
@Winston Ewert : 포스터 가 대안으로 del할당 None할 때 제안 된 이름 바인딩 을 제거 한다는 것을 이해하지 못했습니다 .
Steven Rumbalski 2:27에

8
@Steven, 포스터는 변수 삭제 (이름 제거) 및 없음 할당을 명확하게 대조합니다. 그는 없음을 지정할 수 있는데 왜 변수를 삭제해야하는지 알지 못합니다. 이전에 해당 이름에 바인딩 된 항목에 대한 참조를 해제한다는 점에서 동일한 효과가 있습니다.
Winston Ewert

19
@Winston Ewert : 명확하지 않습니다. 아마도 "이전에 해당 이름에 바인딩 된 모든 것에 대한 참조를 릴리스하는 것과 동일한 효과가 있습니다"라고 말한 것이 분명합니다. 그러나 이름을 삭제 한 후 이름을 사용하려고하면 이름이 높아진다는 점에서 전체 이야기가 아닙니다 NameError. Greg Hewgill은이를 매우 구별합니다. 그리고이 구별이 포스터가 "명확하게"이해 한 것에 대한 당신의 주장을 불명확하게 만듭니다.
Steven Rumbalski

9
@Winston Ewert 동의하지 않습니다. 그러나 충분히 말했다. 우리는 모두 우리의 경우를 만들었습니다.
Steven Rumbalski 12

44

내가 찾은 del유용한 곳 중 하나 는 for 루프에서 외부 변수를 정리하는 것입니다.

for x in some_list:
  do(x)
del x

for 루프 외부에서 x를 사용하면 x가 정의되지 않을 것입니다.


1
당신의인가 del라인은 여기 (루프, 즉 부분)을 들여 가정?
Sam

11
@Sam, 아니요 의도하지 않았습니다.
user5319825

7
@Sam 아니요, 여기서 아이디어는 루프의 마지막 반복 후 (some_list의 최종 요소에서 do ()를 수행 한 후) x가 some_list의 최종 값에 대한 참조로 남아 있다는 것입니다. del x는 이것이 그대로 할당되어 있지 않은지 확인합니다.
Matthew

12
NameError: name 'x' is not defined목록이 비어 있으면 이 문제가 발생 합니다.
WofWca

18

변수를 삭제하는 것은 없음으로 설정하는 것과 다릅니다

변수 이름을 삭제 del하면 거의 사용되지 않지만 키워드가 없으면 사소하게 달성 할 수 없습니다. 을 작성하여 변수 이름을 만들 수 있다면 a=1이론적으로 a를 삭제하여이를 취소 할 수 있습니다.

삭제 된 변수에 액세스하려고하면 NameError가 발생하기 때문에 경우에 따라 디버깅이 더 쉬워 질 수 있습니다.

클래스 인스턴스 속성을 삭제할 수 있습니다

파이썬을 사용하면 다음과 같은 것을 작성할 수 있습니다.

class A(object):
    def set_a(self, a):
        self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
    print("Hallo")

클래스 인스턴스에 속성을 동적으로 추가하기로 선택한 경우 반드시 작성하여 취소 할 수 있습니다.

del a.a

16

예외를 검사하는 데 사용할 때 사용해야하는 특정 예가 있습니다 del(다른 사람이있을 수도 있지만이 정보를 알고 sys.exc_info()있음). 이 함수는 튜플, 발생한 예외 유형, 메시지 및 역 추적을 리턴합니다.

처음 두 값은 일반적으로 오류를 진단하고 조치를 취하기에 충분하지만 세 번째 값은 예외가 발생한 위치와 예외가 발생한 위치 사이의 전체 호출 스택을 포함합니다. 특히, 당신이 같은 것을하면

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if something(exc_value):
        raise

역 추적 tb은 호출 스택의 로컬에서 끝나며 가비지 수집 할 수없는 순환 참조를 만듭니다. 따라서 다음을 수행하는 것이 중요합니다.

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    del tb
    if something(exc_value):
        raise

순환 참조를 끊습니다. sys.exc_info()메타 클래스 매직과 같이을 호출하려는 많은 경우에 역 추적 (traceback) 유용하므로 예외 핸들러를 떠나기 전에이를 정리해야합니다. 역 추적이 필요하지 않은 경우 역 추적을 즉시 삭제하거나 다음을 수행해야합니다.

exc_type, exc_value = sys.exc_info()[:2]

모두 함께 피하십시오.


18
가비지 수집기가 수집하지 않는다는 사실은 더 이상 사실이 아닙니다. 그러나주기는 수집을 지연시킵니다.
Winston Ewert

이것은 너무 관련성이 없으며 op의 질문에 대답하지 않습니다.
WhyNotHugo 2016 년

15

또 다른 생각.

Django와 같은 프레임 워크에서 http 응용 프로그램을 디버깅 할 때 이전에 사용 된 쓸모없고 엉망이 된 변수로 가득 찬 호출 스택, 특히 매우 긴 목록 인 경우 개발자에게는 매우 고통 스럽습니다. 따라서이 시점에서 네임 스페이스 제어가 유용 할 수 있습니다.


12

변수를 없음에 할당하는 것보다 "del"을 명시 적으로 사용하는 것이 좋습니다. 존재하지 않는 변수를 찾으려고하면 런타임 오류가 발생하지만 존재하지 않는 변수를 None으로 설정하려고하면 Python은 자동으로 새 변수를 None으로 설정하여 변수를 남겨 둡니다. 원래 있던 곳을 삭제하고 싶었습니다. 델은 실수를 미리 잡을 수 있도록 도와 줄 것입니다.


11

위의 답변에 몇 가지 사항을 추가하려면 del x

의 정의 xr -> o( r객체를 가리키는 참조 o)이지만 오히려 del x변경 됩니다. 관련 객체가 아닌 객체에 대한 참조 (포인터)에 대한 작업입니다 . 여기서 와를 구별하는 것이 중요합니다.roxro

  • 에서 제거합니다 locals().
  • 거기에 속하는 globals()경우 제거합니다 x.
  • 스택 프레임에서 제거합니다 (물리적으로 참조를 제거하지만 개체 자체는 스택 프레임이 아니라 개체 풀에 있습니다).
  • 현재 범위에서 제거합니다. 지역 변수의 정의 범위를 제한하면 문제가 발생할 수 있습니다.
  • 내용의 정의보다는 이름의 선언에 관한 것입니다.
  • 위치가 x아닌 위치 에 영향을 미칩니다 x. 메모리의 물리적 변화는 이것뿐입니다. 예를 들어 x사전 또는 목록에있는 경우 참조 (참조로서)가 해당 개체 풀에서 제거 될 수 있습니다. 이 예제에서 해당 사전은 스택 프레임 ( locals())이며 겹칩니다 globals().

6

numpy.load를 사용한 후 파일을 강제로 닫습니다.

틈새 사용법은 아마도 numpy.load파일을 읽을 때 유용하다는 것을 알았습니다 . 가끔씩 파일을 업데이트하고 같은 이름의 파일을 디렉토리에 복사해야합니다.

예전 del에는 파일을 해제하고 새 파일로 복사 할 수있었습니다.

참고 with명령 줄에 플롯을 가지고 놀고 컨텍스트 탭을 많이 사용하고 싶지 않으므로 컨텍스트 관리자 를 피하고 싶습니다!

참조 질문을.


Python Image Library (PIL)를 사용하여로드 된 이미지와 비슷한 것이 있습니다. 이미지를 열고 특정 크기가있는 경우 파일을 삭제하고 싶었습니다. 그러나 파일은 여전히 ​​파이썬에서 사용 중입니다. 따라서 'del img'라고 말한 다음 파일을 제거 할 수 있습니다.
물리적

2
이이 때 언어 사양이 보장하지 않는 구현 세부이라고 조심 __del__()쓰레기에 대한 메서드를 호출 개체 또는 경우 가 전혀 호출되는가. 따라서 __del__()메소드가 어느 정도 호출 되기를 기대하는 것 이외의 리소스를 해제 할 수있는 방법을 제공하지 않는 API 는 (객체가 쓰레기가 된 후 곧) 어느 정도 깨졌습니다.
BlackJack

6

del종종 __init__.py파일 에서 볼 수 있습니다. __init__.py파일에 정의 된 모든 글로벌 변수 는 자동으로 "내 보냅니다"(에 포함됨 from module import *). 이것을 피하는 한 가지 방법은을 정의 __all__하는 것입니다.

예를 들어, 당신은 코드를 가지고 __init__.py같은

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

그런 다음 모듈에서 sys이름을 내 보냅니다 . 대신 써야합니다

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

del sys

4

무엇을 del사용할 수 있는지에 대한 예로서 다음과 같은 상황에서 유용합니다.

def f(a, b, c=3):
    return '{} {} {}'.format(a, b, c)

def g(**kwargs):
    if 'c' in kwargs and kwargs['c'] is None:
        del kwargs['c']

    return f(**kwargs)

# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'

이 두 기능은 서로 다른 패키지 / 모듈에있을 수 있습니다 프로그래머는 어떤 기본값 인수가 알 필요가 없습니다 cf실제로있다. kwargs를 del과 함께 사용하면 None으로 설정하여 "c의 기본값을 원합니다"라고 말할 수 있습니다 (또는이 경우에도 그대로 두십시오).

당신은 같은 것을 할 수 있습니다 :

def g(a, b, c=None):
    kwargs = {'a': a,
              'b': b}
    if c is not None:
        kwargs['c'] = c

    return f(**kwargs)

그러나 이전 예가 더 건조하고 우아하다는 것을 알았습니다.


3

델파이는 언제 파이썬에서 유용합니까?

이것을 사용하여 슬라이스 구문 대신 배열의 단일 요소를 제거 할 수 있습니다 x[i:i+1]=[]. 예를 들어 os.walk디렉토리에있는 요소를 삭제하려는 경우에 유용 할 수 있습니다 . 하나 그냥 만들 수 있기 때문에 나는이 생각에 대한 키워드 유용을 고려하지 않을 [].remove(index)방법을합니다 ( .remove방법은 검색 및 제거 - 첫 번째 인스턴스의 값 사실이다).


7
[].pop(index)그리고 [].remove(item). "index"가치에 대해 이야기 할 때 명명 된 변수를 사용하지 말고 혼란스럽게 만듭니다.
스키

@Ski pop은 index를 사용 합니다. 이것은 유효한 답변이지만이 답변의 절반은 델이 사용하는 예제를 제공합니다. 없음으로 설정된 목록 개체는 여전히 목록에 있지만 del은 항목을 제거합니다.
user5389726598465

3

delNumpy로 대용량 데이터를 처리 할 때 의사 수동 메모리 관리에 유용한 것으로 나타났습니다 . 예를 들면 다음과 같습니다.

for image_name in large_image_set:
    large_image = io.imread(image_name)
    height, width, depth = large_image.shape
    large_mask = np.all(large_image == <some_condition>)
    # Clear memory, make space
    del large_image; gc.collect()

    large_processed_image = np.zeros((height, width, depth))
    large_processed_image[large_mask] = (new_value)
    io.imsave("processed_image.png", large_processed_image)

    # Clear memory, make space
    del large_mask, large_processed_image; gc.collect()

이것은 파이썬 GC를 유지할 수 없을 때 시스템이 미친 것처럼 스왑 할 때 스크립트를 연삭 정지로 가져 오는 것과 차이가있을 수 있습니다. 메모리 여유 공간이 부족하여 시스템을 탐색 할 수있는 충분한 여유 공간을 남겨 둡니다. 작동하는 동안 코드를 작성하십시오.


2

델이 자체 구문을 가지고있는 이유 중 하나는 함수로 대체하는 것이 바인딩이나 변수에서 작동하고 참조하는 값이 아니라면 특정 경우에 어려울 수 있다고 생각합니다. 따라서 del의 함수 버전을 만들려면 컨텍스트를 전달해야합니다. del foo는 globals (). remove ( 'foo') 또는 locals (). remove ( 'foo')가되어야합니다. 가독성이 떨어집니다. 아직도 나는 델을 제거하는 것이 겉보기 드문 사용으로 인해 좋을 것이라고 말합니다. 그러나 언어 기능 / 결함을 제거하는 것은 고통 스러울 수 있습니다. 아마도 파이썬 4가 그것을 제거 할 것입니다 :)


2

변수를 설정하는 None것과 제거하는 것 사이의 뉘앙스를 강조하기 위해 허용 된 답변에 대해 자세히 설명하고 싶습니다 del.

변수 foo = 'bar'및 다음 함수 정의가 제공됩니다.

def test_var(var):
    if var:
        print('variable tested true')
    else:
        print('variable tested false')

처음 선언되면 예상대로 test_var(foo)산출 variable tested true합니다.

이제 시도하십시오 :

foo = None
test_var(foo)

어느 것이 생산 variable tested false됩니다.

이 동작을 다음과 대조하십시오.

del foo
test_var(foo)

지금은 제기 NameError: name 'foo' is not defined합니다.


0

또 다른 틈새 사용은 :에서 pyroot ROOT5 또는 ROOT6과, "델"노 더 이상 존재하지 C ++ 객체 참조 파이썬 개체를 제거하는 것이 유용 할 수 있습니다. 이를 통해 pyroot의 동적 조회는 동일한 이름을 가진 C ++ 객체를 찾아 파이썬 이름에 바인딩 할 수 있습니다. 따라서 다음과 같은 시나리오를 가질 수 있습니다.

import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object

바라건대,이 틈새 시장은 ROOT7의 성실한 객체 관리로 닫힐 것입니다.


0

"del"명령은 배열에서 데이터를 제어하는 ​​데 매우 유용합니다. 예를 들면 다음과 같습니다.

elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)

산출:

[ 'B', 'C', 'D']


-2

일단 사용해야했다 :

del serial
serial = None

다음을 사용하기 때문에 :

serial = None

직렬 포트를 즉시 다시 열 수있을 정도로 빠르게 해제하지 않았습니다. 그 교훈에서 나는 del"GC this NOW! 그리고 그것이 끝날 때까지 기다린다" 는 것을 의미한다는 것을 배웠고 그것은 많은 상황에서 정말 유용합니다. 물론을 가질 수 있습니다 system.gc.del_this_and_wait_balbalbalba(obj).


5
흠 ... 정말 차이가 없어야합니다. 그럼에도 문제가 추가 지연으로 해결 되었습니까?
Winston Ewert

3
나는 당신 이 지금 어떤 문서로도 GC를 뒷받침 할 수 있다고 생각하지 않습니다 . __del__()파이썬 에서는 GC에 의존하고 호출하는 것이 항상 잘못 이라고 생각합니다 (그러나이 디자인의 이유를 모르겠습니다 with). 컨텍스트 관리자 API ( 문) 를 사용하는 것이 좋습니다 .
Pavel Šimerda

1
그것은 일종의 부두 프로그래밍입니다. 의 방법 설명 및 메모 참조 개체 .__ 델 __ ()에 대한 문서 세부 사항을, 그리고 명심 이것은 단지 CPythons을 참조 횟수와 현재 구현에 대해 설명합니다. 다른 Python 구현 (PyPy, Jython, IronPython, Brython 등) 또는 향후 CPython 구현에서는 다른 가비지 수집 체계를 사용할 수 있습니다. 자이 썬은 즉시 객체를 삭제하지 않는 JVM GC를 사용한다. 이 serial모듈은 Jython 과도 작동하므로 해킹 이 작동하지 않습니다!
BlackJack

BTW gc.collect 는 명시 적으로 재활용하는 방법입니다. 대부분의 파이썬 구현에서 지원됩니다.
tdihp

-2

del은 많은 언어에서 "unset"과 동일하며 다른 언어에서 파이썬으로 이동하는 상호 참조 지점입니다. 사람들은 첫 번째 언어에서 사용했던 것과 동일한 기능을 수행하는 명령을 찾는 경향이 있습니다. var를 ""로 바꾸거나 아무것도 범위에서 var를 제거하지는 않습니다. var 자체의 이름이 여전히 메모리에 저장되는 이유는 무엇입니까? 메모리를 많이 사용하는 스크립트에서 .. 휴지통에 쓰레기를 남기지 말고 어쨌든 ... 언어마다 "unset / delete"var 함수가 있습니다. 파이썬이 아닌 이유는 무엇입니까?


7
del가비지 수집기를보다 빠르게 호출하지 않으며 = None장기적으로 가비지를 남겨 두지 않습니다. 파이썬의 가비지 콜렉션을 강화하고 싶을 수도 있습니다.
SilverbackNet

-3

파이썬의 모든 객체에는 식별자, 유형, 관련 참조 횟수가 있습니다. del을 사용할 때 참조 횟수가 줄어들고 참조 횟수가 0이되면 가비지 수집을위한 잠재적 후보입니다. 이것은 식별자를 없음으로 설정하는 것과 비교할 때 델을 구별합니다. 나중에는 단순히 객체가 야생에서 제외되고 (우리가 범위를 벗어날 때까지 카운트가 줄어들 때) 단순히 식별자가 다른 객체 (메모리 위치)를 가리킴을 의미합니다.


3
이것의 증거를보고 싶습니다. 없음을 지정하면 참조 횟수가 감소해야합니다.
Jason Baker

3
이것은 말도 안되고 가비지 수집과 반대입니다 (쓰레기가 가두는 것을 의미합니다).
Pavel Šimerda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.