2014-10-15 1 views
2

스크립트에서 여러 파일과 데이터베이스 연결을 열어 적절한 SIGINT 처리를 구현하고 싶습니다. 스크립트가 Ctrl + C 또는 다른 방법으로 중단 된 경우에는 닫아야합니다.SIGINT를 올바르게 처리하여 파일/연결을 닫는 방법

이전에 KeyboardInterrupt 예외를 사용하여 CTRL + C를 잡았습니다. 파일/연결이 정의되어 있는지 확인한 다음 닫았다면 닫고 종료하십시오.

정말이 방법을 사용하는 것이 좋을까요, 아니면 신호 처리기를 사용하는 것이 더 좋을까요? 예 :

import signal, sys, time 

def handler(signum, frame): 
    print("..kthxbye") 
    sys.exit(1) 

def main(): 
    signal.signal(signal.SIGINT, handler) 
    i = 0 
    while True: 
     print(i) 
     i += 1 
     time.sleep(1) 

if __name__ == "__main__": 
    main() 

이 나에게 청소기 보인다, 그러나 나는 핸들러에 파일 이름이나 데이터베이스 연결을 통과 할 방법을 모르겠어요.

답변

4

나는 오히려 주 스레드에서 KeyboardInterrupt 예외를 잡을 것입니다. KeyboardInterrupt은 파이썬의 기본 SIGINT 처리기의 결과입니다. KeyboardInterrupt 예외 예외 처리기는 SIGINT을 직접 catch하는 경우보다 훨씬 안전하고 친숙한 컨텍스트입니다.

if __name__ == '__main__': 
    try: 
     main() 
    except KeyboardInterrupt: 
     cleanup() 

편집 : 절차

:

import sys, time 

class SharedState: 
    def __init__(self): 
     self.var0 = 42 
     self.var1 = 'string' 

# method 1 
shared_variable = 'woof woof' 

# method 2: avoiding global declarations in functions 
shared_state = SharedState() 

def main(): 
    # In order to write a global variable you need a global 
    # declaration otherwise the assignment would create a 
    # local variable 

    global shared_variable 
    shared_variable = 5 

    shared_state.var0 = 10 

    time.sleep(10) 

def cleanup(): 
    print shared_variable 
    print shared_state.var0 
    sys.exit(1) 

if __name__ == '__main__': 
    try: 
     main() 
    except KeyboardInterrupt: 
     cleanup() 

객체 지향 (내 취향) :

다음 두 가지 방법 사이의 변수 (상태)를 공유하는 방법입니다
import sys, time 

# method 3: object oriented programming 
class Program: 
    def __init__(self): 
     self.var0 = 42 
     self.var1 = 'string' 

    def main(self): 
     self.var0 = 5 
     self.var1 = 'woof woof' 
     time.sleep(10) 

    def cleanup(self): 
     # both main and cleanup can access the member 
     # variables of this class 
     print self.var0 
     print self.var1 
     sys.exit(1) 

    def execute(self): 
     try: 
      self.main() 
     except KeyboardInterrupt: 
      self.cleanup() 

if __name__ == '__main__': 
    Program().execute() 
+0

답변 해 주셔서 감사합니다. 그래서 나는 KeyboardInterrupt : print ("clean-up")'을 제외하고 try : print ("파일과 데이터베이스와 stuff")를 제외하고 try/main을 사용하여 몇 백 줄의 메인을 감싸는 것이 좋습니다. –

+0

@DaedalusMythos 긴 방법이나 긴 블록을 결코 선호하지 않습니다 (try-except 블록으로 사용하십시오). 대신 주요 함수의 전체 고기를 다른 함수 (예 : : safe_main())에 넣고 주 함수에서 try 블록에 함수 호출 만있는 간단한 try-except 구조 만 있으면됩니다. 마찬가지로 except 블록을 단순화 할 수 있습니다. 예를 들어, C + +에서 표준 라이브러리는 try-catch 블록으로 싸여있는 main 함수를 유사하게 호출합니다. – pasztorpisti

+0

@DaedalusMythos 글쎄, 당신은 기본적으로 기본적으로 2 개의 주요 블록을 가지고 있다는 것을 알아 챘습니다 ...'if __name__ == "__main __":'블록에서 try-except를 쉽게 할 수 있습니다. 그런 다음 try 블록은'main()'호출 만 포함합니다. 내 업데이트 답변을 참조하십시오. – pasztorpisti

1

My sug gestion은 signal 라이브러리를 사용하여 신호를 처리하는 것입니다. 신호는 예외가 아니며 운영 체제의 Inter Process Communication (IPC) 인프라의 일부입니다.

신호는 구성 파일을 다시로드하거나 로그를 순환하는 동안 로그 파일 처리기를 닫는 것과 같이 프로그램과 통신하는 데 도움이됩니다. 아파치와 같은 대몬 프로세스의 대부분은 그것을 먹는다.

쉘 스크립트에는 신호를 처리하고 캡처 된 신호를 기반으로 적절한 조치를 취하는 trap 명령이 있습니다.

일반적으로 파이썬은 종료시 모든 파일 핸들러와 데이터베이스 연결을 자동으로 닫습니다. 하지만 안전을 위해 암묵적으로 처리 할 수있는 기능이 있습니다.

아래의 코드는 SIGINT를 트랩하고 파일을 올바르게 닫습니다.

import signal 
import sys 

die = False 

def handler(signum, frame): 
    global die 
    print('Got SIGINT.') 
    die = True 

def closeFile(fh): 
    fh.flush() 
    fh.close() 

signal.signal(signal.SIGINT, handler) 

fh = open('/tmp/a.txt', 'w') 

while True: 
    data = input('> ') 

    if data == 'q': 
     closeFile(fh) 
     break 
    else: 
     fh.write(data + '\n') 

    if die: 
     closeFile(fh) 
     print('Completed cleanup.. ') 
     sys.exit() 
+0

답변 해 주셔서 감사합니다! 어떻게 처리기에 데이터베이스 연결/열린 파일을 전달할 수 있습니까? 호출 될 때 닫으려면 어떻게해야합니까? –

+1

파이썬에서는 C 프로그램에서와 같이 신호를 처리 할 수 ​​없습니다. 신호 처리기가 호출되면 C 신호 처리기가 이미 반환됩니다. 더 많은 정보 : https://docs.python.org/2/library/signal.html'SIGINT'를 직접 처리하면 파이썬 프로그램이 "원자"로 취급되는 작업 중간에 중단 될 위험이 있습니다. 예외 처리에 관해서. 예외 핸들러에서 python 메소드를 안전하게 호출 할 수 있지만 시그널 핸들러에서 동일한 메소드를 수행 할 수는 없습니다. 신호가 아니라면 "원자 적"연산 사이에 예외가 발생합니다. – pasztorpisti

+1

@DaedalusMythos SIGINT를 받고 종료되기 전에 파일 처리기를 닫는 샘플 코드를 추가했습니다. –