Рефакторинг: прохождение
Я хочу провести вас через процесс рефакторинга. Обучение программированию - это не просто знание конечного результата, который вы обычно получаете, когда задаете вопрос о переполнении стека. Речь идет о том, как добраться до этого ответа самостоятельно. Когда люди публикуют короткие и точные ответы на подобные вопросы, не всегда очевидно, как они пришли к своим решениям.
Итак, давайте проведем некоторый рефакторинг и посмотрим, что мы можем сделать, чтобы упростить ваш код. Мы переписываем, удаляем, переименовываем и переставляем код до тех пор, пока больше не будет выполнено никаких улучшений.
Упростите ваши алгоритмы
Python не должен быть таким многословным. Обычно это пахнет кодом, когда у вас есть явные циклы, работающие над списками и диктантами в Python, вместо того, чтобы использовать списки и функции, которые работают с контейнерами в целом.
Использовать defaultdict для хранения количества символов
A defaultdict(int)
будет генерировать записи при обращении к ним, если они не существуют. Это позволит нам исключить ветку if / else при подсчете символов.
from collections import defaultdict
characterDict = defaultdict(int)
def putEncounteredCharactersInDictionary(lineStr):
for character in lineStr:
characterDict[character] += 1
Сортировка диктов
Словари не гарантируют порядок их ключей. Вы не можете предполагать, что элементы хранятся в том же порядке, в котором вы их вставили. Таким образом, сортировка записей в диктовке и последующее возвращение их в другой диктат просто копирует их обратно.
Это означает, что ваша функция в основном не работает. После сортировки элементов вам необходимо сохранить их в виде списка кортежей, чтобы сохранить их порядок сортировки. После удаления этого кода мы можем сократить этот метод до одной строки.
def sortCharacterDictionary(characterDict):
return sorted(characterDict.iteritems(), key=itemgetter(1))
Инвертирование диктов
Учитывая предыдущий комментарий, у вас больше не будет разборчивости после сортировки. Но, если вы это сделали, эта функция является одним из тех случаев, когда явное зацикливание не рекомендуется. В Python всегда думайте, как работать с коллекциями одновременно, а не с одним элементом.
def inverseSortedCharacterDictionary(sortedCharDict):
return dict((v, k) for k, v in sortedCharDict.iteritems())
Все в одной строке мы (1) перебираем пары ключ / значение в dict; (2) переключать их и создавать перевернутые значения / кортежи ключей; (3) создайте диктат из этих перевернутых кортежей.
Комментарий и название с умом
Ваши имена методов длинные и описательные. Там нет необходимости повторять ту же информацию в комментариях. Используйте комментарии только тогда, когда ваш код не является самоописательным, например, когда у вас сложный алгоритм или необычная конструкция, которая не сразу очевидна.
Что касается имен, ваши имена излишне длинные. Я бы придерживался гораздо более менее описательных имен, а также делал бы их более общими. Вместо inverseSortedCharacterDictionary
попробуйте просто invertedDict
. Это все, что делает этот метод, он инвертирует диктовку. На самом деле не имеет значения, прошел ли он сортированный символьный дикт или любой другой тип диктанта.
Как правило, старайтесь использовать как можно больше общих имен, чтобы ваши методы и переменные были как можно более общими. Более универсальный означает больше многоразового использования.
characters = defaultdict(int)
def countCharacters(string):
for ch in string:
characters[ch] += 1
def sortedCharacters(characters):
return sorted(characters.iteritems(), key=itemgetter(1))
def invertedDict(d):
return dict((v, k) for k, v in d.iteritems())
Уменьшить громкость
Использование временных переменных и вспомогательных методов является хорошей практикой программирования, и я приветствую вас за это в вашей программе. Однако теперь, когда они у нас достаточно простые, и каждая из них состоит из одной или двух строк, мы, вероятно, даже больше не нуждаемся в них.
Вот тело вашей программы после изменения функций, как указано выше:
f = open('funkymess.txt', 'r')
for line in f:
countCharacters(line.rstrip('\n'))
f.close()
print sortedCharacters(characters)[0]
А затем давайте просто продолжим и добавим эти вспомогательные методы, поскольку они такие простые. Вот итоговая программа после всего рефакторинга:
Финальная программа
#!/usr/bin/env python
from operator import itemgetter
from collections import defaultdict
characters = defaultdict(int)
f = open('funkymess.txt','r')
for line in f:
for ch in line.rstrip('\n'):
characters[ch] += 1
f.close()
print sorted(characters.iteritems(), key=itemgetter(1))[0]