# Buggy code
def train(self, sentences, save_loc=None, nr_iter=5):
    """Train a model from sentences, and save it at ``save_loc``. ``nr_iter``
    controls the number of Perceptron training iterations.

    :param sentences: A list of (words, tags) tuples.
    :param save_loc: If not ``None``, saves a pickled model in this location.
    :param nr_iter: Number of training iterations.
    """
    self._make_tagdict(sentences)
    self.model.classes = self.classes
    for iter_ in range(nr_iter):
        c = 0
        n = 0
        for sentence in sentences:
            words = [word for word, tag in sentence]
            tags = [tag for word, tag in sentence]

            prev, prev2 = self.START
            context = self.START + [self.normalize(w) for w in words] + self.END
            for i, word in enumerate(words):
                guess = self.tagdict.get(word)
                if not guess:
                    feats = self._get_features(i, word, context, prev, prev2)
                    guess = self.model.predict(feats)
                    self.model.update(tags[i], guess, feats)
                prev2 = prev
                prev = guess
                c += guess == tags[i]
                n += 1
        random.shuffle(sentences)
        logging.info("Iter {0}: {1}/{2}={3}".format(iter_, c, n, _pc(c, n)))
    self.model.average_weights()
    # Pickle as a binary file
    if save_loc is not None:
        with open(save_loc, "wb") as fout:
            # changed protocol from -1 to 2 to make pickling Python 2 compatible
            pickle.dump((self.model.weights, self.tagdict, self.classes), fout, 2)


# Traceback (TypeError)
from nltk.tag import PerceptronTagger
from nltk.corpus import alpino as alp
training_corpus = alp.tagged_sents()
tagger = PerceptronTagger(load=False)
tagger.train(training_corpus)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Python/2.7/site-packages/nltk/tag/perceptron.py", line 194, in train
random.shuffle(sentences)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.py", line 291, in shuffle
x[i], x[j] = x[j], x[i]
TypeError: 'StreamBackedCorpusView' object does not support item assignment

# Fixed code
def train(self, sentences, save_loc=None, nr_iter=5):
    """Train a model from sentences, and save it at ``save_loc``. ``nr_iter``
    controls the number of Perceptron training iterations.

    :param sentences: A list or iterator of sentences, where each sentence
        is a list of (words, tags) tuples.
    :param save_loc: If not ``None``, saves a pickled model in this location.
    :param nr_iter: Number of training iterations.
    """
    # We'd like to allow ``sentences`` to be either a list or an iterator,
    # the latter being especially important for a large training dataset.
    # Because ``self._make_tagdict(sentences)`` runs regardless, we make
    # it populate ``self._sentences`` (a list) with all the sentences.
    # This saves the overheard of just iterating through ``sentences`` to
    # get the list by ``sentences = list(sentences)``.

    self._sentences = list()  # to be populated by self._make_tagdict...
    self._make_tagdict(sentences)
    self.model.classes = self.classes
    for iter_ in range(nr_iter):
        c = 0
        n = 0
        for sentence in self._sentences:
            words, tags = zip(*sentence)

            prev, prev2 = self.START
            context = self.START + [self.normalize(w) for w in words] + self.END
            for i, word in enumerate(words):
                guess = self.tagdict.get(word)
                if not guess:
                    feats = self._get_features(i, word, context, prev, prev2)
                    guess = self.model.predict(feats)
                    self.model.update(tags[i], guess, feats)
                prev2 = prev
                prev = guess
                c += guess == tags[i]
                n += 1
        random.shuffle(self._sentences)
        logging.info("Iter {0}: {1}/{2}={3}".format(iter_, c, n, _pc(c, n)))

    # We don't need the training sentences anymore, and we don't want to
    # waste space on them when we pickle the trained tagger.
    self._sentences = None

    self.model.average_weights()
    # Pickle as a binary file
    if save_loc is not None:
        with open(save_loc, "wb") as fout:
            # changed protocol from -1 to 2 to make pickling Python 2 compatible
            pickle.dump((self.model.weights, self.tagdict, self.classes), fout, 2)