Translate English to Pig Latin This is a program for converting English to the pseudo-language Pig Latin. Not the strictest form of Pig Latin but it most likely will accurately output an argument in Pig Latin. I got the idea from a list of ideas on Github. Is there any way I can improve it concisely?

def pig_latin(message):
    consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y',
                  'z']
    new_message = ''

    for word in message.split():
        ay = ['a', 'y']
        listed_word = list(word)
        word_copy = word
        moved_consonants = ''

        for letter in listed_word.copy():
            if letter.lower() == 'y':
                if letter in word_copy[0]:
                    moved_consonants += letter
                    listed_word.remove(letter)
                else:
                    break
            elif letter.lower() in consonants:
                moved_consonants += letter
                listed_word.remove(letter)
            else:
                break

        listed_word.append('-' + moved_consonants + ''.join(ay))
        new_message += ''.join(listed_word) + ' '

    return new_message


print(pig_latin('Can you read pig latin?'))
First, at the top you list all the consonants out. There are two things that can be improved here:


Since you only use it to check whether or not something is a consonant, it should be a set. It's much more efficient to to a membership lookup on a set than it is to do one on a list. Just replace the [] with {}.

consonants = {'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'}

Second, there's a slightly less painful way to generate those letters. Python's string module contains a ascii_lowercase built-in that holds 'abcdefghijklmnopqrstuvwxyz'. You can use that along with a set of vowels to limit what letters need to be hard-coded:

import string as s

vowels = {'a', 'e', 'i', 'o', 'u'}
consonants = set(s.ascii_lowercase) - vowels  # Consonants are the set of letters, minus the vowels


I personally prefer this way.


You could also just change your algorithm to use vowels directly.



Just to clear something up, 

word_copy = word


does not create a copy of word. This just creates a second name for the word string. For Strings this doesn't matter because Strings are immutable, but with a mutable object, this will bite you:

my_list = []
list_copy = my_list  # Does not actually create a copy!
my_list.append(1)
print(my_list, list_copy)  # prints [1] [1]


Notice how both lists were added to. This happens because there's actually only one list. Both names are referring to the same list.

For the sake of clarity, I'd rename it to say what it's purpose is. Offhand though, I can't see the need for word_copy at all! It would make sense if it was being used as an accumulator for a loop or something, but the only time its ever used is at word_copy[0], and since you never reassign word, you could just do word[0]. I'd simply get rid of word_copy.

Along the same lines, I'd reconsider ay. The name you've given it is exactly as descriptive as the string it contains, and is only ever used in one place. At the very least, I'd rename it to something meaningful:

pig_latin_suffix = ['a', 'y']


I'll also note that there's no reason to use a list of Strings here instead of a multi-character String. They behave the same in this case:

" ".join(['a', 'y'])
'a y'

" ".join("ay")
'a y'


Strings are iterable just like lists are.



I think pig_latin is too big. It's doing two main jobs: breaking the message into words, and processing the words. I would make the processing step its own function:

def process_word(word):
    ay = ['a', 'y']
    listed_word = list(word)
    word_copy = word
    moved_consonants = ''

    for letter in listed_word.copy():
        if letter.lower() == 'y':
            if letter in word_copy[0]:
                moved_consonants += letter
                listed_word.remove(letter)
            else:
                break
        elif letter.lower() in consonants:
            moved_consonants += letter
            listed_word.remove(letter)
        else:
            break

    listed_word.append('-' + moved_consonants + ''.join(ay))

    return ''.join(listed_word)

def pig_latin(message):
    new_message = ''

    for word in message.split():
        processed_word = process_word(word)

        new_message += processed_word + ' '

    return new_message


process_word could arguably be broken down further. This is already much better though. The immediate benefit is now you can test individual words, and not have to worry about how the rest of the code will react:

print(process_word("Can"))  # Prints 'an-Cay'