2010-03-31 4 views
34

C'è un modo per mappare un numero di segnale (ad esempio signal.SIGINT) al suo nome rispettivo (ad esempio "SIGINT")?Ottieni i nomi dei segnali dai numeri in Python

mi piacerebbe essere in grado di stampare il nome di un segnale nel registro quando lo ricevo, però non riesco a trovare una mappa da numeri di segnale ai nomi in Python, vale a dire:

import signal 
def signal_handler(signum, frame): 
    logging.debug("Received signal (%s)" % sig_names[signum]) 

signal.signal(signal.SIGINT, signal_handler) 

Per alcuni sig_names del dizionario, in modo che quando il processo riceve SIGINT esso stampa:

Received signal (SIGINT) 

risposta

27

non c'è nessuno, ma se non ti dispiace un po 'di trucco, è possibile generare in questo modo:

import signal 
dict((k, v) for v, k in reversed(sorted(signal.__dict__.items())) 
    if v.startswith('SIG') and not v.startswith('SIG_')) 
+0

A rigor di termini, ciò mapperà 1 a '' SIG_IGN' e SIGHUP' sulla maggior parte delle piattaforme, quindi suppongo che il test dovrebbe essere, se 'v.startswith ('SIG') e non v.startswith ('SIG _') '. –

+0

Inoltre esegue il double mapping 6 su 'SIGABRT' e' SIGIOT' su Mac OS X (sebbene possano essere usati in modo intercambiabile, suppongo, a differenza di 'SIG_IGN' - che non è un segnale). –

+0

@Brian: molto vero ... non è una soluzione perfetta di gran lunga. Ma è almeno in qualche modo indipendente dalla piattaforma. – Wolph

0

Beh, help(signal) dice in fondo:

DATA 
    NSIG = 23 
    SIGABRT = 22 
    SIGBREAK = 21 
    SIGFPE = 8 
    SIGILL = 4 
    SIGINT = 2 
    SIGSEGV = 11 
    SIGTERM = 15 
    SIG_DFL = 0 
    SIG_IGN = 1 

Quindi questo dovrebbe funzionare:

sig_names = {23:"NSIG", 22:"SIGABRT", 21:"SIGBREAK", 8:"SIGFPE", 4:"SIGILL", 
      2:"SIGINT", 11:"SIGSEGV", 15:"SIGTERM", 0:"SIG_DFL", 1:"SIG_IGN"} 
+3

Sfortunatamente piattaforme diverse hanno numeri di segnale diversi, quindi questo non è portatile. Grazie comunque. –

+1

Per esempio, ecco la X 'help Mac OS (segnale)': SIGABRT = 6 SIGALRM = 14 SIGBUS = 10 SIGCHLD = 20 SIGCONT = 19 SIGEMT = 7 SIGFPE = 8 SIGHUP = 1 SIGILL = 4 SIGINFO = 29 SIGINT = 2 SIGIO = 23 SIGIOT = 6 SIGKILL = 9 SIGPIPE = 13 SIGPROF = 27 SIGQUIT = 3 SIGSEGV = 11 SIGSTOP = 17 SIGSYS = 12 SIGTERM = 15 012.351.SIGTRAP = 5 SIGTSTP = 18 SIGTTIN = 21 SIGTTOU = 22 SIGURG = 16 SIGUSR1 = 30 SIGUSR2 = 31 SIGVTALRM = 26 SIGWINCH = 28 SIGXCPU = 24 SIGXFSZ = 25 –

+1

Ah - Mi dovrebbe ho capito che, tutto sommato, specialmente da quando ho sperimentato quanti segnali differenti sono su Windows e Linux. La soluzione di WoLpH è comunque più pulita :) –

2

Ho trovato questo articolo quando ero nella stessa situazione e pensato che il gestore è solo gestendo un segnale in un momento, quindi non ho nemmeno bisogno di un intero dizionario, solo il nome di un segnale:

sig_name = tuple((v) for v, k in signal.__dict__.iteritems() if k == signum)[0] 

probabilmente c'è una notazione che non ha bisogno della tupla (...) [0] bit, ma non riesco a capirlo.

+0

signame = [v per v, k nel segnale .__ dict __. Iteritems() se k == signum] [0] funziona correttamente. – dwelch91

+2

"signame = next (v per v, k nel segnale .__ dict __. Iteritems() se k == signum)" si ferma quando lo trova invece di continuare attraverso il resto del dict (inoltre, non ha il [ 0] che @ssc non ha gradito: D). – CryingCyclops

+0

Se v, k deve rappresentare chiavi e valori, i nomi devono essere invertiti, ad es. sig_name = tupla ((k) k, v in segnale .__ dict __. Iteritems() se v == signum) [0] Ma poi ci sono altri valori dict del segnale il cui valore può corrispondere v, in tal caso , a seconda dell'ordine, iteritems() restituisce gli articoli, è possibile stampare un nome senza senso. – tbc0

12

Il Python standard libreria esempio mostra questa funzione nel capitolo sui segnali:

SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) \ 
    for n in dir(signal) if n.startswith('SIG') and '_' not in n) 

è possibile utilizzare in questo modo:

print "Terminated by signal %s" % SIGNALS_TO_NAMES_DICT[signal_number] 
+2

o (forse leggermente più preferibile) 'SIGNALS_TO_NAMES_DICT.get (signal_number," Segnale senza nome:% d "% signal_number)' –

+0

Questa è una risposta migliore e dovrebbe essere accettata. – kevinarpe

+0

Come sottolinea @Wolph nella sua risposta, questa soluzione non garantisce un nome coerente per duplicare i segnali. – tbc0

27

Con l'aggiunta del signal.Signalsenum in Python 3.5 questo è ora facile come:

>>> import signal 
>>> signal.SIGINT.name 
'SIGINT' 
>>> signal.SIGINT.value 
2 
>>> signal.Signals(2).name 
'SIGINT' 
>>> signal.Signals['SIGINT'].value 
2 
+1

Questa è un'ottima risposta per gli utenti Py3. –

0

B OSTRUIRE su another answer:

import signal 

if hasattr(signal, "Signals"): 
    def _signal_name(signum): 
     try: 
      return signal.Signals(signum).name 
     except ValueError: 
      pass 
else: 
    def _signal_name(signum): 
     for n, v in sorted(signal.__dict__.items()): 
      if v != signum: 
       continue 
      if n.startswith("SIG") and not n.startswith("SIG_"): 
       return n 

def signal_name(signum): 
    if signal.SIGRTMIN <= signum <= signal.SIGRTMAX: 
     return "SIGRTMIN+{}".format(signum - signal.SIGRTMIN) 
    x = _signal_name(signum) 
    if x is None: 
     # raise ValueError for invalid signals 
     signal.getsignal(signum) 
     x = "<signal {}>".format(signum) 
    return x