I heard/read that writers of texts can be recognized by counting their used words and compare these to previous works. As a code kata  I experimented with this a bit and found some disturbing facts.'Romeo and Juliet' was written by one of the Bronte sisters.Shakespeare plagiarized it from the future.My program is not repeatable.I think the last is most disturbing, see the numbers of corresponding words between brackets in my results below.Used code is also below and used .txt files were downloaded from https://www.gutenberg.org/ and conveniently renamed, temporary available in a zip at http://kuiken.dyndns.org/spul/books.zip.Questions:Why is my code not repeatableCoding style commentsResults:jk@ASUS-flaptop:~/PythonFun/Boeken$ python books.py I read WutheringHeights.txt by BronteI read PrideAndPrejudice.txt by AustenI read TheMerchantOfVenice.txt by ShakespeareI think SensAndSensibility.txt is written by Austen (405)I think RomeoAndJuliet.txt is written by Bronte (278)I think JaneEyre.txt is written by Bronte (376)I think Hamlet.txt is written by Shakespeare (324)jk@ASUS-flaptop:~/PythonFun/Boeken$ python books.py I read WutheringHeights.txt by BronteI read PrideAndPrejudice.txt by AustenI read TheMerchantOfVenice.txt by ShakespeareI think SensAndSensibility.txt is written by Austen (404)I think RomeoAndJuliet.txt is written by Bronte (279)I think JaneEyre.txt is written by Bronte (376)I think Hamlet.txt is written by Shakespeare (319)Code:from collections import Counterfrom string import ascii_letters, whitespacedef read_book(filename):    with open(filename) as f:        return f.read()def make_words(text):    '''removes weird characters and split into words'''    remain = ascii_letters + whitespace    filtered =     for ch in text:        if ch in remain:            filtered += ch    return filtered.lower().split()def most_used(words, n=500):    '''returns a `set` of the `n` most used words'''    counting = Counter(words)    counted = counting.most_common(n)    return set([item[0] for item in counted])def read_and_analyse(filename):    '''reads a book and returns most used words'''    book = read_book(filename)    words = make_words(book)    favorites = most_used(words)    return favoritesclass WriterKnower():    def __init__(self):        self.analysed_books = []    def read_and_remeber_words(self, filename, writer):        favorite_words = read_and_analyse(filename)        self.analysed_books.append({ 'favorite_words' : favorite_words,                                      'writer' : writer})        print(I read %s by %s % (filename, writer))    def read_and_recognize(self, filename):        favorit_words = read_and_analyse(filename)        writer = 'unknown'        max_identical_words = 0        for book in self.analysed_books:            common = len(favorit_words.intersection(book['favorite_words']))            if (common > max_identical_words):                max_identical_words = common                writer = book['writer']        print(I think %s is written by %s (%d) %               (filename, writer, max_identical_words))if __name__ == __main__:    nerd = WriterKnower();    print()    nerd.read_and_remeber_words('WutheringHeights.txt', 'Bronte')    nerd.read_and_remeber_words('PrideAndPrejudice.txt', 'Austen')    nerd.read_and_remeber_words('TheMerchantOfVenice.txt', 'Shakespeare')    print()    nerd.read_and_recognize('SensAndSensibility.txt')    nerd.read_and_recognize('RomeoAndJuliet.txt')    nerd.read_and_recognize('JaneEyre.txt')    # to be a bit reinsured....    nerd.read_and_recognize('Hamlet.txt')    print()
Non-repeatability (plagiarism and time travel)
python
Repeatability?The reason for non-repeatability is quite simple. Try running the following program a couple of times:from collections import Counterprint(Counter(['hello', 'world']).most_common(1))Notice how it is non-repeatable? The reason is that the hash values of strings are somewhat randomized. In the case of ties, Counter doesn't really care which value it returns. Hash value randomization is important to prevent a 'hashdos' attack.If you really care to fix it, here's a small recipe:class OrderedCounter(Counter, OrderedDict):    passThis one gives repeatability.(Based on this Tweet: https://twitter.com/dabeaz/status/745253234323881984).