2017-08-10 4 views
1

Donc, je suis très nouveau sur python et je ne suis pas sûr que mon code est le plus efficace, mais serait toujours très reconnaissant si quelqu'un pouvait m'expliquer pourquoi mon script renvoie l'erreur "nom non défini" lorsque je l'exécute. J'ai une liste de 300 noms de gènes dans un fichier séparé, un nom par ligne, que je veux lire, et stocker chaque ligne comme une variable de chaîne.Nom non défini erreur Python lors de la lecture de fichier ligne par ligne

Dans le script j'ai une liste de 600 variables. 300 variables nommées name_bitscore et 300 nommées name_length pour chacun des 300 noms. Je souhaite filtrer la liste en fonction d'une condition. Mon script ressemble à ceci:

#!/usr/bin/python 
with open("seqnames-test1-iso-legal-temp.txt") as f: 
    for line in f: 
     exec("b="+line+"_bitscore") 
     exec("l="+line+"_length") 
     if 0.5*b <= 2*1.05*l and 0.5*b >= 2*0.95*l: 
      print line 
ham_pb_length=2973 
ham_pb_bitscore=2165 
g2225_ph_length=3303 
cg2225_ph_bitscore=2278 

etc. pour les variables longueur et bitscore. Essentiellement, ce que j'essaie de faire ici, c'est lire la ligne 1 du fichier "seqnames-test1-iso-legal-temp.txt" qui est ham_pb. Ensuite, j'utilise voulu utiliser la fonction exec pour créer une variable b = ham_pb_bitscore et l = ham_pb_length, afin que je puisse tester si la moitié de la valeur du bitcore du gène est dans la plage de double sa longueur avec une marge d'erreur de 5%. Ensuite, répétez cette opération pour chaque gène, c'est-à-dire chaque ligne du fichier "seqnames-test1-sio-legal-temp.txt".

Lorsque j'exécute le script, je reçois le message d'erreur:

Traceback (most recent call last): 
    File "duplicatebittest.py", line 4, in <module> 
    exec("b="+line+"_bitscore") 
    File "<string>", line 1, in <module> 
NameError: name 'ham_pb' is not defined 

J'ai fait un autre script court pour vous assurer que j'utilisais la fonction exec correctement qui ressemble à ceci:

#!/usr/pin/python 
name="string" 
string_value=4 
exec("b="+name+"_value") 
print(name) 
print(b) 

Et cela renvoie:

string 
4 

Donc, je sais que je peux utiliser exec pour inclure une variable de chaîne dans une déclaration de variable car b renvoie 4 comme prévu. Donc, je ne suis pas sûr pourquoi je reçois une erreur dans mon premier script.

J'ai testé pour vous assurer que la ligne de variable était une chaîne en entrant

#!/usr/bin/python 
    with open("seqnames-test1-iso-legal-temp.txt") as f: 
     for line in f: 
      print type(line) 

Et il est revenu la ligne

<type 'str'> 

300 fois, donc je sais chaque ligne variable est une chaîne qui C'est pourquoi je ne comprends pas pourquoi mon script de test a fonctionné, mais celui-ci n'a pas fonctionné.

Toute aide serait super appréciée!

+1

'line' comprend la terminaison de ligne. vous devez utiliser 'line.rstrip()' –

+0

Donc, pour clarifier, la ligne 2 doit-elle être remplacée par 'pour line.rstrip() dans f'? – Louis

+0

no. Voir ma réponse (et l'accepter si cela fonctionne pour vous) –

Répondre

0

mettez #!/usr/bin/env python comme première ligne. Voir this question pour plus d'explications. Comme l'a souligné Jean, exec n'est pas le bon outil pour ce travail. Vous devriez utiliser des dictionnaires, car ils sont moins dangereux (injection de code de recherche) et les dictionnaires sont plus faciles à lire. Voici un exemple de la façon d'utiliser des dictionnaires tirés de la documentation python:

>>> tel = {'jack': 4098, 'sape': 4139} 
>>> tel['guido'] = 4127 
>>> tel 
{'sape': 4139, 'guido': 4127, 'jack': 4098} 
>>> tel['jack'] 
4098 
>>> del tel['sape'] 
>>> tel['irv'] = 4127 
>>> tel 
{'guido': 4127, 'irv': 4127, 'jack': 4098} 
>>> list(tel.keys()) 
['irv', 'guido', 'jack'] 
>>> sorted(tel.keys()) 
['guido', 'irv', 'jack'] 
>>> 'guido' in tel 
True 
>>> 'jack' not in tel 
False 

Voici une manière que je peux penser à atteindre votre objectif:

with open("seqnames-test1-iso-legal-temp.txt") as f: 
    gene_data = {'ham_pb_length':2973, 'am_pb_bitscore':2165, 
       'g2225_ph_length':3303, 'cg2225_ph_bitscore':2278} 
    '''maybe you have more of these gene data things. If so, 
    just append them to the end of the above dictionary literal''' 
    for line in f: 
     if not line.isspace(): 
      bitscore = gene_data[line.rstrip()+'_bitscore'] 
      length = gene_data[line.rstrip()+'_bitscore'] 
      if (0.95*length <= bitscore/4 <= 1.05*length): 
       print line 

Je profite de quelques fonctionnalités de python utiles ici . Dans python3, 5/7 évalue à 0.7142857142857143, pas votre 0 typique comme dans beaucoup de langages de programmation. Si vous voulez une division entière dans python3, utilisez 5//7. En outre, dans python 1<2<3 évalue à True, et 1<3<2 évalue à False alors que dans de nombreux langages de programmation, 1<2<3 évalue à True<3 qui pourrait donner une erreur ou évaluer à True selon le langage de programmation.

+0

Cela semble fonctionner pour la plupart car il imprime 4 résultats attendus, mais me donne alors une erreur: 'KeyError: ' _bitscore'' – Louis

+0

Votre fichier contient probablement des espaces à la fin. Le 'KeyError' signifie que vous avez essayé une recherche de dictionnaire et qu'il a échoué. Sur la ligne 'bitscore = gene_data [ligne.rstrip() + '_ bitscore']', 'line.rstrip()' est la chaîne vide sur certaines itérations. Python l'exécute alors comme 'bitscore = gene_data ['' + '_ bitscore']' qui est le même que 'bitscore = gene_data ['_ bitscore']'. Pour le corriger, mettez 'si ce n'est pas line.isspace():' après la boucle for et avant l'instruction d'affectation (et modifiez l'indentation en conséquence). Cela vérifie que la ligne n'est pas tous les caractères d'espacement. J'ai changé ma réponse originale pour démontrer. – asky

+0

ça marche, merci pour toute votre aide! – Louis

2

line est le rendement par l'itérateur du fichier texte, qui émet un retour à la ligne pour chaque ligne lue.

Ainsi, votre expression:

exec("b="+line+"_bitscore") 

est passé à exec comme:

b=ham_pb 
_bitscore 

bande la sortie et qui fonctionnera

exec("b="+line.rstrip()+"_bitscore") 

à condition que vous déplacez les lignes suivantes avant la boucle si variable s sont déclarés:

ham_pb_length=2973 
ham_pb_bitscore=2165 
g2225_ph_length=3303 
cg2225_ph_bitscore=2278 

Mieux: cesser d'utiliser exec et utiliser des dictionnaires pour éviter de définir dynamiquement des variables.

+0

Je viens d'obtenir l'erreur 'NameError: nom 'ham_pb_bitscore' n'est pas défini'. Serait-ce parce qu'il est défini après le bloc de code? Si ce n'est pas le cas, je vais essayer de le réécrire en utilisant un dictionnaire parce que j'ai lu ailleurs qu'utiliser exec de cette façon n'est pas la meilleure pratique. – Louis

+0

oui, déplacez le bloc ci-dessus. mais oui, utiliser exec n'est pas la meilleure pratique. Et il est plutôt dangereux (si vous ne contrôlez pas ce qui est dans le fichier, cela pourrait conduire à l'injection de code) –