1

는 "Generating an MD5 checksum of a file는"나는이 코드를 가지고 :파이썬에서 파일을 닫는 데 참조 카운팅을 사용할 수 있습니까? 이 질문에

import hashlib 
def hashfile(afile, hasher, blocksize=65536): 
    buf = afile.read(blocksize) 
    while len(buf) > 0: 
     hasher.update(buf) 
     buf = afile.read(blocksize) 
    return hasher.digest() 

[(fname, hashfile(open(fname, 'rb'), hashlib.sha256())) for fname in fnamelst] 

내가 지능형리스트의 내부 파일을 열 비판되었고, 한 사람이 내가 충분히 긴 목록을 가지고 있다면 밖으로 실행하는 것이라고 의견을 말했다 열린 파일 핸들. hashfile의 유연성을 상당히 줄이고 파일 이름 인수를 취하고 해시 파일을 사용하고 with을 사용하는 인터페이스가 제안되었습니다.

필요 했습니까? 나는 그 일을 정말로 잘못하고 있었습니까? 이 코드 아웃

시험이 출력

#!/usr/bin/python3 

import sys 
from pprint import pprint # Pretty printing 

class HereAndGone(object): 
    def __init__(self, i): 
     print("%d %x -> coming into existence." % (i, id(self)), 
       file=sys.stderr) 
     self.i_ = i 
    def __del__(self): 
     print("%d %x <- going away now." % (self.i_, id(self)), 
       file=sys.stderr) 

def do_nothing(hag): 
    return id(hag) 

l = [(i, do_nothing(HereAndGone(i))) for i in range(0, 10)] 

pprint(l) 

결과

0 7f0346decef0 -> coming into existence. 
0 7f0346decef0 <- going away now. 
1 7f0346decef0 -> coming into existence. 
1 7f0346decef0 <- going away now. 
2 7f0346decef0 -> coming into existence. 
2 7f0346decef0 <- going away now. 
3 7f0346decef0 -> coming into existence. 
3 7f0346decef0 <- going away now. 
4 7f0346decef0 -> coming into existence. 
4 7f0346decef0 <- going away now. 
5 7f0346decef0 -> coming into existence. 
5 7f0346decef0 <- going away now. 
6 7f0346decef0 -> coming into existence. 
6 7f0346decef0 <- going away now. 
7 7f0346decef0 -> coming into existence. 
7 7f0346decef0 <- going away now. 
8 7f0346decef0 -> coming into existence. 
8 7f0346decef0 <- going away now. 
9 7f0346decef0 -> coming into existence. 
9 7f0346decef0 <- going away now. 
[(0, 139652050636528), 
(1, 139652050636528), 
(2, 139652050636528), 
(3, 139652050636528), 
(4, 139652050636528), 
(5, 139652050636528), 
(6, 139652050636528), 
(7, 139652050636528), 
(8, 139652050636528), 
(9, 139652050636528)] 

그것은 각 HereAndGone 객체가 생성되고 지능형리스트의 각 요소가 구성되어 파괴되는 것이 분명하다. 파이썬 참조 카운팅은 객체에 대한 참조가 없 자마자 객체를 해제합니다.이 참조는 해당 요소의 값이 계산 된 직후에 발생합니다.

물론 다른 파이썬 구현은 이것을하지 않을 수도 있습니다. 파이썬 구현이 어떤 형태의 참조 계산을 수행해야합니까? 참조 카운팅과 같은 모듈이 gc 모듈의 설명서에서 핵심 기능이라고 생각됩니다.

그리고 내가 잘못했을 경우 어떻게하면 목록 이해력의 간결한 명확성과 파일처럼 읽을 수있는 인터페이스의 유연성을 유지하도록 다시 작성하라는 제안을했을까요?

+0

"파이썬 구현시 참조 계산을 수행해야합니까?" - 아니. – user2357112

+1

"참조 카운팅과 같은 gc 모듈의 설명서가 언어의 핵심 기능인 것 같습니다." - gc 모듈의 대부분, 특히 전원을 끄는 부분은 선택적 기능으로 간주되어야합니다. – user2357112

+0

'hashfile'을 수정하여 파일 이름을 취하고 파일 자체를 열고 닫는 작업을 처리합니다. 시스템의 메모리 관리를 사용하여 일반적으로 다른 자원을 관리하는 것은 끔찍한 생각입니다. – tfb

답변

0

누군가가 매우 명시 적으로 "에 도달 했으므로 개체를 즉시 종료하지 마십시오. 따라서 파일을 명시 적으로 닫아야합니다.". 따라서 이것은 코드가 보장되지 않는 행동에 의존한다는 것을 분명히합니다.

그럼에도 불구하고 여전히 취약합니다. 개별 파일의 해시를 초과하는 순환 참조 또는 수명을 갖는 데이터 구조에 의해 참조되지 않도록 파일에 눈에 보이지 않게 의존합니다. 미래에 코드에 어떤 일이 일어날 지, 누군가가이 핵심 세부 사항을 기억할 것인지를 누가 알 수 있습니까?

질문은 무엇을해야할까요? 질문에있는 hashfile 기능은 멋지게 융통성이 있으며, 파일 이름을 취하고 함수 내에 파일을 열어 유연성을 없애기 위해 인터페이스를 조작하는 것이 수치 스럽습니다. 최소한의 해결책은 이것이라고 생각합니다 :

해결책은 인터페이스를 약간 재고하고 훨씬 더 일반적으로 만드는 것입니다.

def hash_bytestr_iter(hasher, bytesiter, ashexstr=False): 
    for block in bytesiter: 
     hasher.update(bytesiter) 
    return (hasher.hexdigest() if ashexstr else hasher.digest()) 

def iter_and_close_file(afile, blocksize=65536): 
    with afile: 
     block = afile.read(blocksize) 
     while len(block) > 0: 
      yield block 

하나는 원래 hashfile이 (가) 컨텍스트 매니저로 afile 전달 사용 할 수 있습니다,하지만 난 미묘한 방법으로 휴식 기대 이런 종류의 생각합니다. 그것은 hashfile을 파일을 닫고, 그 이름의 정렬은 파일을 닫지 않고 해시를 계산한다는 것을 약속합니다.

그리고 블록의 바이트가 있고 연속 블록이나 스트림의 일부인 것처럼 해시를 모두 처리하려는 경우가 많이 발생한다고 생각합니다.반복자를 바이트 블록으로 해싱하는 것은 파일을 해시하는 것이 훨씬 더 일반적입니다.

마찬가지로 파일과 같은 개체를 반복하고 닫는 경우가 많이 있다고 생각합니다. 따라서이 두 기능을 모두 재사용 및 일반화 할 수 있습니다.

관련 문제