5
\$\begingroup\$

I have recently started coding in Python and this is my first proper project.

The user enters an RNA sequence and the program converts the code into the corresponding amino acid sequence. The user can then choose what kind of a mutation they want to introduce and where. The program will then output the amino acid sequence that the mutation results in.

This is by no means a perfect code but I wanted to ask for feedback on its readability and if there are any ways to improve efficiency.

## Making the dictionary to convert the 3 letter codon to the amino acid code ##

amino_acid_dictionary = {'uuu' :'Phe',
"uuc" : "Phe",
'uua' : 'Leu',
'uug' : 'Leu',
'cuu' : 'Leu',
'cuc' : 'Leu',
'cua' : 'Leu',
'cug' : 'Leu',
'auu' : 'Ile',
'auc' : 'Ile',
'aua' : 'Ile',
'aug' : 'Met',
'guu' : 'Val',
'guc' : 'Val',
'gua' : 'Val',
'gug' : 'Val',
'ucu' : 'Ser',
'ucc' : 'Ser',
'uca' : 'Ser',
'ucg' : 'Ser',
'agu' : 'Ser',
'agc' : 'Ser',
'ccu' : 'Pro',
'ccc' : 'Pro',
'cca' : 'Pro',
'ccg' : 'Pro',
'acu' : 'Thr',
'acc' : 'Thr',
'aca' : 'Thr',
'acg' : 'Thr',
'gcu' : 'Ala',
'gcc' : 'Ala',
'gca' : 'Ala',
'gcg' : 'Ala',
'uau' : 'Tyr',
'uac' : 'Tyr',
'uaa' : 'STOP',
'uag' : 'STOP',
'uga' : 'STOP',
'cau' : 'His',
'cac' : 'His',
'caa' : 'Gln',
'cag' : 'Gln',
'aau' : 'Asn',
'aac' : 'Asn',
'aaa' : 'Lys',
'aag' : 'Lys',
'gau' : 'Asp',
'gac' : 'Asp',
'gag' : 'Glu',
'gaa' : 'Glu',
'ugg' : 'Trp',
'ugu' : 'Cys',
'ugc' : 'Cys',
'cgu' : 'Arg',
'cgc' : 'Arg',
'cga' : 'Arg',
'cgg' : 'Arg',
'aga' : 'Arg',
'agg' : 'Arg',
'ggu' : 'Gly',
'ggc' : 'Gly',
'gga' : 'Gly',
'ggg' : 'Gly'}


                          
        ## Splitting the RNA sequence into a triplet code and convertin it to the amino acid sequence ##
print("Hello")
sequence = str(input("Enter your RNA sequence:"))
letter_code = []
maximum = len(sequence) // 3
remainder = len(sequence) % 3
aa_code_start = 0
letter_one = 0
letter_two = 1
letter_three = 2


while len(letter_code) < maximum:
    letter_code.insert(aa_code_start, sequence[letter_one] + sequence[letter_two] + sequence[letter_three])
    aa_code_start = aa_code_start + 1
    letter_one = letter_one + 3
    letter_two = letter_two + 3
    letter_three = letter_three + 3


a = 0
while a < len(letter_code):
    letter_code[a] = amino_acid_dictionary[letter_code[a]]
    a = a + 1



if remainder == 1:
    letter_code.append(sequence[-1])

elif remainder == 2:
    letter_code.append(sequence[-2] + sequence[-1])
                       
print( "The amino acid sequence from your RNA code is: " , letter_code)



print("")
print("")

# introducing a mutation
print(" What kind of mutation would you like to introduce?")
print("Choose 1 for deletion mutation.")
print("Choose 2 for insertion mutation.")
print("Choose 3 for substitution mutation.")
mutation = int(input("Enter number: "))

if mutation == 1:
    position = int(input("Enter the position you want to carry out the deletion mutation: "))
    position = position - 1
    new_sequence_bases = sequence[:position] + sequence[(position + 1):]
    print("The new sequence is: ", new_sequence_bases)

    new_sequence = []
    new_maximum = len(new_sequence_bases) // 3
    new_start = 0
    new_one = 0
    new_two = 1
    new_three = 2
    
    while len(new_sequence) < new_maximum:
        new_sequence.insert(new_start, new_sequence_bases[new_one] + new_sequence_bases[new_two] + new_sequence_bases[new_three])
        new_start = new_start + 1
        new_one = new_one + 3
        new_two = new_two + 3
        new_three = new_three + 3
        
    
    a = 0
    while a < new_maximum:
        new_sequence[a] = amino_acid_dictionary[new_sequence[a]]
        a = a + 1

    print("")
    print("")
    print("A deletion mutation at position", position + 1, "changes the amino acid sequence from ", letter_code, "to ", new_sequence)
        

elif mutation == 2:
    position = int(input("Enter the position you want to carry out the insertion mutation(s): "))
    base_inserted = input("Enter the base(s) are you want to insert: ")
    position = position - 1
    new_sequence = sequence[:position] + base_inserted + sequence[(position + 1):]
    

    new_maximum = len(new_sequence) // 3
    new_letter_code = []
    new_start = 0
    new_one = 0
    new_two = 1
    new_three = 2

    print(sequence)
    print(new_sequence)
    
    while len(new_letter_code) < new_maximum:
        new_letter_code.insert(new_start, new_sequence[new_one] + new_sequence[new_two] + new_sequence[new_three])
        new_start = new_start + 1
        new_one = new_one + 3
        new_two = new_two + 3
        new_three = new_three + 3


    a = 0
    while a < new_maximum:
        new_letter_code[a] = amino_acid_dictionary[new_letter_code[a]]
        a = a + 1

    print("")
    print("")
    print("An insertion of ", base_inserted, "at position", position + 1, "changes the amino acid sequence from ", letter_code, "to ", new_letter_code)

    
elif mutation == 3: 
    position = int(input("Enter the position you want to carry out the substitution: "))
    base_substitute = input("Enter the base you want to be substituted in: ")
    first_half = sequence[:(position - 1)]
    second_half = sequence[position:]
    new_sequence = first_half + base_substitute + second_half

    new_letter_code = []
    new_start = 0
    new_one = 0
    new_two = 1
    new_three = 2

    while len(new_letter_code) < maximum:
        new_letter_code.insert(new_start, new_sequence[new_one] + new_sequence[new_two] + new_sequence[new_three])
        new_start = new_start + 1
        new_one = new_one + 3
        new_two = new_two + 3
        new_three = new_three + 3
    
    
    a = 0
    while a < maximum:
        new_letter_code[a] = amino_acid_dictionary[new_letter_code[a]]
        a = a + 1

    print("")
    print("")
    print("A base substitution of ", base_substitute, "at position ", position , "changes the amino acid sequence from ", letter_code, "to ", new_letter_code)

else:
    print("This is not an option.")
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Two thoughts: 1) create subroutines for the separate cases instead of elif. 2) read the dictionary from a file or something-- kind of ugly to put it directly into the code. \$\endgroup\$ Commented Jul 14, 2022 at 14:57
  • \$\begingroup\$ Can you show an example sequence? \$\endgroup\$
    – Reinderien
    Commented Jul 17, 2022 at 12:06

1 Answer 1

1
\$\begingroup\$

amino_acid_dictionary, for the purposes of self-documentation, is better-named something like AMINOS_BY_CODON (capitals since it's a global constant). This literal can also be cleaned up by writing one line per amino acid group.

You need functions for reusability, testability and maintainability.

Your RNA-codon-to-amino-acid conversion code is much more complicated than it needs to be. You can just write an iterator that selects a start index at multiples of 3.

Consider writing a lookup for your mutation method. I have shown a tuple written in the same order as your index options.

Are you sure that this insertion:

new_sequence = sequence[:position] + base_inserted + sequence[(position + 1):]

does what you intend? You're losing the character at the insertion position.

Consider writing some input validation loops; I've shown one for selecting the mutation.

Suggested

from typing import Iterator, Protocol

AMINOS_BY_CODON = {
    'uuu': 'Phe', 'uuc': 'Phe',
    'uua': 'Leu', 'uug': 'Leu', 'cuu': 'Leu', 'cuc': 'Leu', 'cua': 'Leu', 'cug': 'Leu',
    'auu': 'Ile', 'auc': 'Ile', 'aua': 'Ile',
    'aug': 'Met',
    'guu': 'Val', 'guc': 'Val', 'gua': 'Val', 'gug': 'Val',
    'ucu': 'Ser', 'ucc': 'Ser', 'uca': 'Ser', 'ucg': 'Ser', 'agu': 'Ser', 'agc': 'Ser',
    'ccu': 'Pro', 'ccc': 'Pro', 'cca': 'Pro', 'ccg': 'Pro',
    'acu': 'Thr', 'acc': 'Thr', 'aca': 'Thr', 'acg': 'Thr',
    'gcu': 'Ala', 'gcc': 'Ala', 'gca': 'Ala', 'gcg': 'Ala',
    'uau': 'Tyr', 'uac': 'Tyr',
    'uaa': 'STOP', 'uag': 'STOP', 'uga': 'STOP',
    'cau': 'His', 'cac': 'His',
    'caa': 'Gln', 'cag': 'Gln',
    'aau': 'Asn', 'aac': 'Asn',
    'aaa': 'Lys', 'aag': 'Lys',
    'gau': 'Asp', 'gac': 'Asp',
    'gag': 'Glu', 'gaa': 'Glu',
    'ugg': 'Trp',
    'ugu': 'Cys', 'ugc': 'Cys',
    'cgu': 'Arg', 'cgc': 'Arg', 'cga': 'Arg', 'cgg': 'Arg', 'aga': 'Arg', 'agg': 'Arg',
    'ggu': 'Gly', 'ggc': 'Gly', 'gga': 'Gly', 'ggg': 'Gly',
}


class MutateMethod(Protocol):
    def __call__(self, rna_sequence: str, position: int) -> str:
        ...


def deletion(rna_sequence: str, position: int) -> str:
    return rna_sequence[:position] + rna_sequence[position + 1:]


def insertion(rna_sequence: str, position: int) -> str:
    base_inserted = input('Enter the base(s) you want to insert: ')
    return rna_sequence[:position] + base_inserted + rna_sequence[position:]


def substitution(rna_sequence: str, position: int) -> str:
    base_substitute = input('Enter the base you want to be substituted in: ')
    first_half = rna_sequence[:position]
    second_half = rna_sequence[position + 1:]
    return first_half + base_substitute + second_half


MUTATIONS = deletion, insertion, substitution


def select_mutation() -> MutateMethod:
    # introducing a mutation
    print('What kind of mutation would you like to introduce?')
    for i, method in enumerate(MUTATIONS, 1):
        print(f'Choose {i} for {method.__name__} mutation.')

    while True:
        try:
            mutation = int(input('Enter number: '))
            return MUTATIONS[mutation - 1]
        except (ValueError, IndexError):
            print('This is not an option.')


def translate_sequence(rna_sequence: str) -> Iterator[str]:
    """Split the RNA sequence into a triplet code and convert it to the amino acid sequence"""
    for start in range(0, len(rna_sequence), 3):
        codon = rna_sequence[start: start+3]
        yield AMINOS_BY_CODON.get(codon, codon)


def main() -> None:
    print('Hello')
    rna_sequence = input('Enter your RNA sequence: ')

    aminos = list(translate_sequence(rna_sequence))
    print(f'The amino acid sequence from your RNA code is: {aminos}\n')

    mutate = select_mutation()
    position = int(input(f'Enter the position you want to carry out the {mutate.__name__} mutation: '))
    new_sequence = mutate(rna_sequence, position - 1)
    new_aminos = list(translate_sequence(new_sequence))
    print(f'{mutate.__name__.title()} at position {position} changes '
          f'the amino acid sequence from {aminos} to {new_aminos}')


if __name__ == '__main__':
    main()

Output

Hello
Enter your RNA sequence: caaccugga
The amino acid sequence from your RNA code is: ['Gln', 'Pro', 'Gly']

What kind of mutation would you like to introduce?
Choose 1 for deletion mutation.
Choose 2 for insertion mutation.
Choose 3 for substitution mutation.
Enter number: 1
Enter the position you want to carry out the deletion mutation: 4
Deletion at position 4 changes the amino acid sequence from ['Gln', 'Pro', 'Gly'] to ['Gln', 'Leu', 'ga']
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.