Repository: cuthbertLab/music21
Pull request #825 (2021-02-05 21:44:21)

 Add first() and last() to streamIterator
first() is much faster than [0].  Last is the same as [-1] (except that it can return None rather than an IndexError)

Fixed a few places in docs and performance-critical places in the score.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/36917044/badge)](https://coveralls.io/builds/36917044)

Coverage increased (+0.007%) to 91.489% when pulling **5b8543c1b396eec67174585c7bea330eff11ad71 on streamIterator-first** into **4f67e0ddb4e5d9fce459d7aa0802b278de1c9d06 on master**.


Patch:
diff --git a/music21/abcFormat/translate.py b/music21/abcFormat/translate.py
index 5af2f8ceb..be7715cd3 100644
--- a/music21/abcFormat/translate.py
+++ b/music21/abcFormat/translate.py
@@ -198,7 +198,7 @@ def abcToStreamPart(abcHandler, inputM21=None, spannerBundle=None):
     # following the meta data, or in the open stream
     if not clefSet and not p.recurse().getElementsByClass('Clef'):
         if useMeasures:  # assume at start of measures
-            p.getElementsByClass('Measure')[0].clef = clef.bestClef(p, recurse=True)
+            p.getElementsByClass('Measure').first().clef = clef.bestClef(p, recurse=True)
         else:
             p.insert(0, clef.bestClef(p, recurse=True))
 
@@ -517,7 +517,7 @@ def reBar(music21Part, *, inPlace=False):
     >>> irl15 = corpus.parse('irl', number=15)
     >>> irl15.metadata.title
     'Esternowe, S. 60'
-    >>> music21Part2 = irl15.parts[0]  # 4/4 time signature
+    >>> music21Part2 = irl15.parts.first()  # 4/4 time signature
     >>> music21Part2.measure(1).show('text')
     {0.0} <music21.note.Note C>
     {1.0} <music21.note.Note A>
@@ -717,7 +717,7 @@ class Test(unittest.TestCase):
         ah = abcFormat.ABCHandler()
         ah.process(testFiles.hectorTheHero)
         s = abcToStreamScore(ah)
-        m1 = s.parts[0].getElementsByClass('Measure')[0]
+        m1 = s.parts[0].getElementsByClass('Measure').first()
         # s.show()
         # ts is 3/4
         self.assertEqual(m1.barDuration.quarterLength, 3.0)
@@ -742,7 +742,7 @@ class Test(unittest.TestCase):
         ah = abcFormat.ABCHandler()
         ah.process(testFiles.theAleWifesDaughter)
         s = abcToStreamScore(ah)
-        m1 = s.parts[0].getElementsByClass('Measure')[0]
+        m1 = s.parts[0].getElementsByClass('Measure').first()
 
         # ts is 3/4
         self.assertEqual(m1.barDuration.quarterLength, 4.0)
@@ -823,11 +823,11 @@ class Test(unittest.TestCase):
         self.assertEqual(sMerged.metadata.composer, 'Josquin des Prez')
         self.assertEqual(len(sMerged.parts), 4)
 
-        self.assertEqual(sMerged.parts[0].getElementsByClass('Clef')[0].sign, 'G')
-        self.assertEqual(sMerged.parts[1].getElementsByClass('Clef')[0].sign, 'G')
-        self.assertEqual(sMerged.parts[2].getElementsByClass('Clef')[0].sign, 'G')
-        self.assertEqual(sMerged.parts[2].getElementsByClass('Clef')[0].octaveChange, -1)
-        self.assertEqual(sMerged.parts[3].getElementsByClass('Clef')[0].sign, 'F')
+        self.assertEqual(sMerged.parts[0].getElementsByClass('Clef').first().sign, 'G')
+        self.assertEqual(sMerged.parts[1].getElementsByClass('Clef').first().sign, 'G')
+        self.assertEqual(sMerged.parts[2].getElementsByClass('Clef').first().sign, 'G')
+        self.assertEqual(sMerged.parts[2].getElementsByClass('Clef').first().octaveChange, -1)
+        self.assertEqual(sMerged.parts[3].getElementsByClass('Clef').first().sign, 'F')
 
         # sMerged.show()
 
@@ -948,7 +948,7 @@ class Test(unittest.TestCase):
         # new problem case:
         s = converter.parse(testFiles.hectorTheHero)
         # first measure has 2 pickup notes
-        self.assertEqual(len(s.parts[0].getElementsByClass('Measure')[0].notes), 2)
+        self.assertEqual(len(s.parts.first().getElementsByClass('Measure').first().notes), 2)
 
     def testRepeatBracketsB(self):
         from music21.abcFormat import testFiles
diff --git a/music21/alpha/analysis/hasher.py b/music21/alpha/analysis/hasher.py
index cf1245f04..dec8968ab 100644
--- a/music21/alpha/analysis/hasher.py
+++ b/music21/alpha/analysis/hasher.py
@@ -825,9 +825,9 @@ class TestExternal(unittest.TestCase):
         h = Hasher()
         h.hashDuration = False
         h.hashOffset = False
-        s1 = corpus.parse('schoenberg', 6).parts[0]
-        s2 = corpus.parse('schoenberg', 2).parts[0]
-        s3 = corpus.parse('bwv66.6').parts[0]
+        s1 = corpus.parse('schoenberg', 6).parts.first()
+        s2 = corpus.parse('schoenberg', 2).parts.first()
+        s3 = corpus.parse('bwv66.6').parts.first()
         hashes1 = h.hashStream(s1)
         hashes2 = h.hashStream(s2)
         hashes3 = h.hashStream(s3)
@@ -852,8 +852,8 @@ class TestExternal(unittest.TestCase):
     def testInterval(self):
         from music21 import corpus
         h = Hasher()
-        s3 = corpus.parse('bwv66.6').parts[0]
-        s4 = corpus.parse('bwv66.6').parts[0].transpose('M2')
+        s3 = corpus.parse('bwv66.6').parts.first()
+        s4 = corpus.parse('bwv66.6').parts.first().transpose('M2')
 
         hashes3 = h.hashStream(s3)
         hashes4 = h.hashStream(s4)
diff --git a/music21/alpha/analysis/ornamentRecognizer.py b/music21/alpha/analysis/ornamentRecognizer.py
index 310ea72a7..af2180fa0 100644
--- a/music21/alpha/analysis/ornamentRecognizer.py
+++ b/music21/alpha/analysis/ornamentRecognizer.py
@@ -10,8 +10,9 @@
 # ------------------------------------------------------------------------------
 import unittest
 from copy import deepcopy
-from typing import Union
+from typing import List, Optional, Union
 
+from music21.common.numberTools import opFrac
 from music21 import duration
 from music21 import expressions
 from music21 import interval
@@ -26,7 +27,11 @@ class OrnamentRecognizer:
     Simple note(s) refer to the base note of ornament which is often shown
     with the ornament marking on it.
     '''
-    def calculateOrnamentNoteQl(self, busyNotes, simpleNotes=None):
+    def calculateOrnamentNoteQl(
+        self,
+        busyNotes,
+        simpleNotes=None
+    ):
         '''
         Finds the quarter length value for each ornament note
         assuming busy notes all are an expanded ornament.
@@ -36,9 +41,13 @@ class OrnamentRecognizer:
         '''
         numOrnamentNotes = len(busyNotes)
         totalDurationQuarterLength = self.calculateOrnamentTotalQl(busyNotes, simpleNotes)
-        return totalDurationQuarterLength / numOrnamentNotes
+        return opFrac(totalDurationQuarterLength / numOrnamentNotes)
 
-    def calculateOrnamentTotalQl(self, busyNotes, simpleNotes=None):
+    def calculateOrnamentTotalQl(
+        self,
+        busyNotes: List[note.GeneralNote],
+        simpleNotes: Optional[List[note.GeneralNote]] = None
+    ):
         '''
         Returns total length of trill assuming busy notes are all an expanded trill.
         This is either the time of all busy notes combined or
@@ -48,8 +57,8 @@ class OrnamentRecognizer:
             return simpleNotes[0].duration.quarterLength
         trillQl = 0
         for n in busyNotes:
-            trillQl += n.duration.quarterLength
-        return trillQl
+            trillQl += float(n.duration.quarterLength)
+        return opFrac(trillQl)
 
 
 class TrillRecognizer(OrnamentRecognizer):
diff --git a/music21/analysis/correlate.py b/music21/analysis/correlate.py
index 053bc72e0..315a0ecda 100644
--- a/music21/analysis/correlate.py
+++ b/music21/analysis/correlate.py
@@ -107,7 +107,7 @@ class ActivityMatch:
         No dynamics here.
 
         >>> s = corpus.parse('bach/bwv8.6.xml')
-        >>> am = analysis.correlate.ActivityMatch(s.parts[0].flat)
+        >>> am = analysis.correlate.ActivityMatch(s.parts.first().flat)
         >>> am.pitchToDynamic()
         Traceback (most recent call last):
         music21.analysis.correlate.CorrelateException: cannot create correlation:
@@ -116,7 +116,7 @@ class ActivityMatch:
         Many dynamics
 
         >>> s = corpus.parse('schoenberg/opus19/movement2')
-        >>> am = analysis.correlate.ActivityMatch(s.parts[0].flat)
+        >>> am = analysis.correlate.ActivityMatch(s.parts.first().flat)
         >>> data = am.pitchToDynamic()
         >>> len(data)
         39
diff --git a/music21/analysis/floatingKey.py b/music21/analysis/floatingKey.py
index 61ed58338..143e8904b 100644
--- a/music21/analysis/floatingKey.py
+++ b/music21/analysis/floatingKey.py
@@ -70,7 +70,7 @@ class KeyAnalyzer:
 
         self.weightAlgorithm = divide
         if s.hasPartLikeStreams():
-            p = s.parts[0]
+            p = s.parts.first()
         else:
             p = s
         self.numMeasures = len(p.getElementsByClass('Measure'))  # could be wrong for endings, etc.
diff --git a/music21/analysis/reduceChordsOld.py b/music21/analysis/reduceChordsOld.py
index ae3448410..88e4b80b5 100644
--- a/music21/analysis/reduceChordsOld.py
+++ b/music21/analysis/reduceChordsOld.py
@@ -74,7 +74,7 @@ class ChordReducer:
         ...    weightAlgorithm=cr.qlbsmpConsonance, trimBelow = 0.3)
         >>> newS.show('text')
         {0.0} <music21.chord.Chord C4 E4 G4 C5>
-        >>> newS.notes[0].quarterLength
+        >>> newS.notes.first().quarterLength
         4.0
         '''
         from music21 import note
@@ -235,8 +235,11 @@ class ChordReducer:
         '''
         i = 0
         p = stream.Part()
+        p0 = inStream.parts.first()
+        if not p0:
+            return p
         self._lastPitchedObject = None
-        lenMeasures = len(inStream.parts[0].getElementsByClass('Measure'))
+        lenMeasures = len(p0.getElementsByClass('Measure'))
         self._lastTs = None
         for i in range(lenMeasures):
             mI = inStream.measure(i, indicesNotNumbers=True)
@@ -254,7 +257,9 @@ class ChordReducer:
                 if i % 20 == 0 and i != 0:
                     print("")
         p.coreElementsChanged()
-        p.getElementsByClass('Measure')[0].insert(0, clef.bestClef(p, allowTreble8vb=True))
+        m = p.getElementsByClass('Measure').first()
+        if m:
+            m.insert(0, clef.bestClef(p, allowTreble8vb=True))
         p.makeNotation(inPlace=True)
         return p
 
@@ -289,7 +294,7 @@ class ChordReducer:
             cLastEnd = newOffset + cElCopy.quarterLength
             m.coreInsert(newOffset, cElCopy)
 
-        tsContext = mI.parts[0].getContextByClass('TimeSignature')
+        tsContext = mI.parts.first().getContextByClass('TimeSignature')
         if tsContext is not None:
             if round(tsContext.barDuration.quarterLength - cLastEnd, 6) != 0.0:
                 cLast.quarterLength += tsContext.barDuration.quarterLength - cLastEnd
@@ -313,7 +318,7 @@ class ChordReducer:
                         self._lastPitchedObject.tie = tie.Tie('start')
         self._lastPitchedObject = m[-1]
 
-        sourceMeasureTs = mI.parts[0].getElementsByClass('Measure')[0].timeSignature
+        sourceMeasureTs = mI.parts.first().getElementsByClass('Measure').first().timeSignature
         if sourceMeasureTs != self._lastTs:
             m.timeSignature = copy.deepcopy(sourceMeasureTs)
             self._lastTs = sourceMeasureTs
@@ -349,11 +354,11 @@ class TestExternal(unittest.TestCase):  # pragma: no cover
         # fix clef
         fixClef = True
         if fixClef:
-            startClefs = c.parts[1].getElementsByClass('Measure')[0].getElementsByClass('Clef')
+            startClefs = c.parts[1].getElementsByClass('Measure').first().getElementsByClass('Clef')
             if startClefs:
                 clef1 = startClefs[0]
-                c.parts[1].getElementsByClass('Measure')[0].remove(clef1)
-            c.parts[1].getElementsByClass('Measure')[0].insert(0, clef.Treble8vbClef())
+                c.parts[1].getElementsByClass('Measure').first().remove(clef1)
+            c.parts[1].getElementsByClass('Measure').first().insert(0, clef.Treble8vbClef())
 
 
         cr = ChordReducer()
diff --git a/music21/analysis/reduction.py b/music21/analysis/reduction.py
index f75f5746d..e6aacfd57 100644
--- a/music21/analysis/reduction.py
+++ b/music21/analysis/reduction.py
@@ -344,9 +344,9 @@ class ScoreReduction:
             oneVoice = True
 
         if self._score:
-            mTemplate = self._score.parts[0].template(retainVoices=False)
+            mTemplate = self._score.parts.first().template(retainVoices=False)
         else:
-            mTemplate = self._chordReduction.parts[0].template(retainVoices=False)
+            mTemplate = self._chordReduction.parts.first().template(retainVoices=False)
 
         # for each defined reductive group
         for gName in self._reductiveGroups:
diff --git a/music21/analysis/windowed.py b/music21/analysis/windowed.py
index 21347af02..2b057cc70 100644
--- a/music21/analysis/windowed.py
+++ b/music21/analysis/windowed.py
@@ -76,12 +76,12 @@ class WindowedAnalysis:
         >>> post = wa.getMinimumWindowStream()
         >>> len(post.getElementsByClass('Measure'))
         42
-        >>> post.getElementsByClass('Measure')[0]
+        >>> post.getElementsByClass('Measure').first()
         <music21.stream.Measure 1 offset=0.0>
 
         Time signature set to 1/4 time signature
 
-        >>> post.getElementsByClass('Measure')[0].timeSignature
+        >>> post.getElementsByClass('Measure').first().timeSignature
         <music21.meter.TimeSignature 1/4>
 
         leaves one note in this measure
diff --git a/music21/audioSearch/transcriber.py b/music21/audioSearch/transcriber.py
index 955a0db54..65d1abf13 100644
--- a/music21/audioSearch/transcriber.py
+++ b/music21/audioSearch/transcriber.py
@@ -135,7 +135,7 @@ def monophonicStreamFromFile(fileName, useScale=None):
         durationList) = audioSearchBase.joinConsecutiveIdenticalPitches(detectedPitchObjects)
     myScore, unused_length_part = audioSearchBase.notesAndDurationsToStream(
         notesList, durationList, removeRestsAtBeginning=True)
-    return myScore.parts[0]
+    return myScore.parts.first()
 
 
 class TestExternal(unittest.TestCase):  # pragma: no cover
diff --git a/music21/base.py b/music21/base.py
index 8bc079d09..2626ddcc0 100644
--- a/music21/base.py
+++ b/music21/base.py
@@ -1184,12 +1184,12 @@ class Music21Object(prebase.ProtoM21Object):
         Let's get the last two notes of the piece, the B and high c:
 
         >>> m4 = p.measure(4)
-        >>> c = m4.notes[0]
+        >>> c = m4.notes.first()
         >>> c
         <music21.note.Note C>
 
         >>> m3 = p.measure(3)
-        >>> b = m3.notes[-1]
+        >>> b = m3.notes.last()
         >>> b
         <music21.note.Note B>
 
@@ -1904,7 +1904,7 @@ class Music21Object(prebase.ProtoM21Object):
         <music21.note.Note A>
         >>> n.measureNumber
         3
-        >>> n is m3.notes[0]
+        >>> n is m3.notes.first()
         True
         >>> n.next()
         <music21.note.Note B>
@@ -3445,7 +3445,7 @@ class Music21Object(prebase.ProtoM21Object):
         >>> m = stream.Measure()
         >>> m.timeSignature = meter.TimeSignature('3/4')
         >>> m.repeatAppend(n, 6)
-        >>> n0 = m.notes[0]
+        >>> n0 = m.notes.first()
         >>> n0.beatDuration
         <music21.duration.Duration 1.0>
 
@@ -3504,7 +3504,7 @@ class Music21Object(prebase.ProtoM21Object):
 
         The first note of a measure is (generally?) always beat strength 1.0:
 
-        >>> m.notes[0].beatStrength
+        >>> m.notes.first().beatStrength
         1.0
 
         Notes on weaker beats have lower strength:
@@ -4193,18 +4193,18 @@ class Test(unittest.TestCase):
 
         # clef/ks can get its beat; these objects are in a pickup,
         # and this give their bar offset relative to the bar
-        eClef = p1.flat.getElementsByClass('Clef')[0]
+        eClef = p1.flat.getElementsByClass('Clef').first()
         self.assertEqual(eClef.beat, 4.0)
         self.assertEqual(eClef.beatDuration.quarterLength, 1.0)
         self.assertEqual(eClef.beatStrength, 0.25)
 
-        eKS = p1.flat.getElementsByClass('KeySignature')[0]
+        eKS = p1.flat.getElementsByClass('KeySignature').first()
         self.assertEqual(eKS.beat, 4.0)
         self.assertEqual(eKS.beatDuration.quarterLength, 1.0)
         self.assertEqual(eKS.beatStrength, 0.25)
 
         # ts can get beatStrength, beatDuration
-        eTS = p1.flat.getElementsByClass('TimeSignature')[0]
+        eTS = p1.flat.getElementsByClass('TimeSignature').first()
         self.assertEqual(eTS.beatDuration.quarterLength, 1.0)
         self.assertEqual(eTS.beatStrength, 0.25)
 
@@ -4388,7 +4388,7 @@ class Test(unittest.TestCase):
         s = corpus.parse('bach/bwv103.6')
 
         p = s.parts['soprano']
-        m1 = p.getElementsByClass('Measure')[0]
+        m1 = p.getElementsByClass('Measure').first()
 
         self.assertEqual([n.offset for n in m1.notesAndRests], [0.0, 0.5])
         self.assertEqual(m1.paddingLeft, 3.0)
@@ -4445,10 +4445,10 @@ class Test(unittest.TestCase):
         s3.append(n3)
 
         # only get n1 here, as that is only level available
-        self.assertEqual(s1.recurse().getElementsByClass('Note')[0], n1)
-        self.assertEqual(s2.recurse().getElementsByClass('Note')[0], n2)
-        self.assertEqual(s1.recurse().getElementsByClass('Clef')[0], c1)
-        self.assertEqual(s2.recurse().getElementsByClass('Clef')[0], c2)
+        self.assertEqual(s1.recurse().getElementsByClass('Note').first(), n1)
+        self.assertEqual(s2.recurse().getElementsByClass('Note').first(), n2)
+        self.assertEqual(s1.recurse().getElementsByClass('Clef').first(), c1)
+        self.assertEqual(s2.recurse().getElementsByClass('Clef').first(), c2)
 
         # attach s2 to s1
         s2.append(s1)
@@ -4621,8 +4621,8 @@ class Test(unittest.TestCase):
         s2 = stream.Stream()
         s2.insert(0, tempo.MetronomeMark(number=120))
         s2.append(note.Note())
-        s2.notes[0].seconds = 2.0
-        self.assertEqual(s2.notes[0].quarterLength, 4.0)
+        s2.notes.first().seconds = 2.0
+        self.assertEqual(s2.notes.first().quarterLength, 4.0)
         self.assertEqual(s2.duration.quarterLength, 4.0)
 
         s2.append(note.Note('C4', type='half'))
@@ -4711,7 +4711,7 @@ class Test(unittest.TestCase):
             s.append(n)
             notes.append(n)  # keep for reference and testing
 
-        self.assertEqual(notes[0], s[0])
+        self.assertEqual(notes[0], s[0])  # leave as get index query.
         s0Next = s[0].next()
         self.assertEqual(notes[1], s0Next)
         self.assertEqual(notes[0], s[1].previous())
diff --git a/music21/braille/segment.py b/music21/braille/segment.py
index 8ce0da7b6..d7f5b1518 100644
--- a/music21/braille/segment.py
+++ b/music21/braille/segment.py
@@ -1549,7 +1549,7 @@ def prepareSlurredNotes(music21Part, **keywords):
     >>> import copy
     >>> from music21.braille import segment
     >>> short = converter.parse('tinynotation: 3/4 c4 d e')
-    >>> s1 = spanner.Slur(short.flat.notes[0], short.flat.notes[-1])
+    >>> s1 = spanner.Slur(short.flat.notes.first(), short.flat.notes.last())
     >>> short.append(s1)
     >>> short.show('text')
     {0.0} <music21.stream.Measure 1 offset=0.0>
@@ -1576,7 +1576,7 @@ def prepareSlurredNotes(music21Part, **keywords):
 
 
     >>> long = converter.parse('tinynotation: 3/4 c8 d e f g a')
-    >>> s2 = spanner.Slur(long.flat.notes[0], long.flat.notes[-1])
+    >>> s2 = spanner.Slur(long.flat.notes.first(), long.flat.notes.last())
     >>> long.append(s2)
     >>> long.show('text')
     {0.0} <music21.stream.Measure 1 offset=0.0>
@@ -2054,7 +2054,7 @@ def prepareBeamedNotes(music21Measure):
             if (isinstance(afterStopNote, note.Rest)
                     and (int(afterStopNote.beat) == int(stopNote.beat))):
                 allNotesOfSameValue = False
-        except exceptions21.StreamException:  # stopNote is last note of measure.
+        except IndexError:  # stopNote is last note of measure.
             pass
         if not allNotesOfSameValue:
             continue
@@ -2064,7 +2064,7 @@ def prepareBeamedNotes(music21Measure):
             # grouping may not be used, unless the eighth is located in a new measure.
             if allNotesAndRests[stopIndex + 1].quarterLength == 0.5:
                 continue
-        except exceptions21.StreamException:  # stopNote is last note of measure.
+        except IndexError:  # stopNote is last note of measure.
             pass
 
         startNote.beamStart = True
diff --git a/music21/braille/translate.py b/music21/braille/translate.py
index 30d6a7b00..0f3b51ef5 100644
--- a/music21/braille/translate.py
+++ b/music21/braille/translate.py
@@ -178,7 +178,7 @@ def metadataToString(music21Metadata, returnBrailleUnicode=False):
     '''
     >>> from music21.braille import translate
     >>> corelli = corpus.parse('monteverdi/madrigal.3.1.rntxt')
-    >>> mdObject = corelli.getElementsByClass('Metadata')[0]
+    >>> mdObject = corelli.getElementsByClass('Metadata').first()
     >>> mdObject.__class__
     <class 'music21.metadata.Metadata'>
     >>> print(translate.metadataToString(mdObject))
diff --git a/music21/chord/__init__.py b/music21/chord/__init__.py
index 4b595c77b..0f4cf98fb 100644
--- a/music21/chord/__init__.py
+++ b/music21/chord/__init__.py
@@ -5295,9 +5295,9 @@ def fromForteClass(notation):
     inv = None
     if isinstance(notation, str):
         if '-' in notation:
-            parts = notation.split('-')
-            card = int(parts[0])
-            num, chars = common.getNumFromStr(parts[1])
+            notationParts = notation.split('-')
+            card = int(notationParts[0])
+            num, chars = common.getNumFromStr(notationParts[1])
             num = int(num)
             if 'a' in chars.lower():
                 inv = 1
diff --git a/music21/converter/__init__.py b/music21/converter/__init__.py
index 57a35f3a8..254c2725d 100644
--- a/music21/converter/__init__.py
+++ b/music21/converter/__init__.py
@@ -1090,13 +1090,13 @@ def parse(value: Union[bundles.MetadataEntry, bytes, str, pathlib.Path],
     Data is preceded by an identifier such as "tinynotation:"
 
     >>> s = converter.parse("tinyNotation: 3/4 E4 r f# g=lastG trip{b-8 a g} c", makeNotation=False)
-    >>> s.getElementsByClass(meter.TimeSignature)[0]
+    >>> s.getElementsByClass(meter.TimeSignature).first()
     <music21.meter.TimeSignature 3/4>
 
     or the format can be passed directly:
 
     >>> s = converter.parse("2/16 E4 r f# g=lastG trip{b-8 a g} c", format='tinyNotation').flat
-    >>> s.getElementsByClass(meter.TimeSignature)[0]
+    >>> s.getElementsByClass(meter.TimeSignature).first()
     <music21.meter.TimeSignature 2/16>
 
     .. tip::
@@ -1606,7 +1606,7 @@ class Test(unittest.TestCase):
         a = parse(testPrimitive.systemLayoutTwoPart)
         # a.show()
 
-        part = a.getElementsByClass(stream.Part)[0]
+        part = a.getElementsByClass(stream.Part).first()
         systemLayoutList = part.flat.getElementsByClass(layout.SystemLayout)
         measuresWithSL = []
         for e in systemLayoutList:
diff --git a/music21/duration.py b/music21/duration.py
index af9463ef4..3fb067c11 100644
--- a/music21/duration.py
+++ b/music21/duration.py
@@ -3131,13 +3131,13 @@ class TupletFixer:
         >>> humdrum.spineParser.flavors['JRP'] = True
         >>> s = converter.parse(humdrumLines, format='humdrum')
 
-        >>> m1 = s.parts[0].measure(1)
+        >>> m1 = s.parts.first().measure(1)
         >>> tf = duration.TupletFixer(m1)
         >>> tupletGroups = tf.findTupletGroups(incorporateGroupings=True)
         >>> tf.fixBrokenTupletDuration(tupletGroups[-1])
-        >>> m1[-1].duration.tuplets[0]
+        >>> m1.last().duration.tuplets[0]
         <music21.duration.Tuplet 3/2/whole>
-        >>> m1[-1].duration.quarterLength
+        >>> m1.last().duration.quarterLength
         Fraction(4, 3)
         '''
         if not tupletGroup:
diff --git a/music21/features/jSymbolic.py b/music21/features/jSymbolic.py
index 44f874941..05ed7a4e0 100644
--- a/music21/features/jSymbolic.py
+++ b/music21/features/jSymbolic.py
@@ -3436,7 +3436,7 @@ class NotePrevalenceOfPitchedInstrumentsFeature(
             raise JSymbolicFeatureException('input lacks notes')
         for p in s.parts:
             # always one instrument
-            i = p.getElementsByClass('Instrument')[0]
+            i = p.getElementsByClass('Instrument').first()
             pNotes = p.recurse().notes
             if pNotes:
                 self.feature.vector[i.midiProgram] = len(pNotes) / total
@@ -3541,7 +3541,7 @@ class VariabilityOfNotePrevalenceOfPitchedInstrumentsFeature(
         coll = []
         for p in s.parts:
             # always one instrument
-            i = p.iter.getElementsByClass('Instrument')[0]
+            i = p.getElementsByClass('Instrument').first()
             pNotes = p.recurse().notes
             if pNotes:
                 coll.append(len(pNotes) / total)
@@ -3691,7 +3691,7 @@ class InstrumentFractionFeature(featuresModule.FeatureExtractor):
         if not total:
             raise JSymbolicFeatureException('input lacks notes')
         for p in s.parts:
-            i = p.getElementsByClass('Instrument')[0]
+            i = p.getElementsByClass('Instrument').first()
             if i.midiProgram in self._targetPrograms:
                 count += len(p.flat.notes)
         self.feature.vector[0] = count / total
diff --git a/music21/figuredBass/checker.py b/music21/figuredBass/checker.py
index d19e42f0b..69bf27aa5 100644
--- a/music21/figuredBass/checker.py
+++ b/music21/figuredBass/checker.py
@@ -46,7 +46,7 @@ def getVoiceLeadingMoments(music21Stream):
     allParts = music21Stream.getElementsByClass('Part').stream()
     newParts = [allParts[i].flat.getElementsNotOfClass('GeneralNote').stream()
                 for i in range(len(allParts))]
-    paddingLeft = allParts[0].getElementsByClass('Measure')[0].paddingLeft
+    paddingLeft = allParts[0].getElementsByClass('Measure').first().paddingLeft
     for (offsets, notes) in sorted(allHarmonies.items()):
         (initOffset, endTime) = offsets
         for genNoteIndex in range(len(notes)):
diff --git a/music21/figuredBass/examples.py b/music21/figuredBass/examples.py
index 84884f8c2..25a89e638 100644
--- a/music21/figuredBass/examples.py
+++ b/music21/figuredBass/examples.py
@@ -437,7 +437,7 @@ def generateBoogieVamp(blRealization=None, numRepeats=5):
         i = interval.notesToInterval(boogieBassLine[0], n)
         tp = boogieBassLine.transpose(i)
         for lyr in n.lyrics:
-            tp.notes[0].addLyric(lyr.text)
+            tp.notes.first().addLyric(lyr.text)
         for m in tp.notes:
             newBassLine.append(m)
 
@@ -480,7 +480,7 @@ def generateTripletBlues(blRealization=None, numRepeats=5):  # 12/8
         i = interval.notesToInterval(tripletBassLine[0], n)
         tp = tripletBassLine.transpose(i)
         for lyr in n.lyrics:
-            tp.notes[0].addLyric(lyr.text)
+            tp.notes.first().addLyric(lyr.text)
         for m in tp.notes:
             newBassLine.append(m)
 
diff --git a/music21/figuredBass/realizer.py b/music21/figuredBass/realizer.py
index 65de1b107..532b680c1 100644
--- a/music21/figuredBass/realizer.py
+++ b/music21/figuredBass/realizer.py
@@ -293,8 +293,8 @@ class FiguredBassLine:
 
         bl2 = bassLine.makeNotation(inPlace=False, cautionaryNotImmediateRepeat=False)
         if r is not None:
-            m0 = bl2.getElementsByClass('Measure')[0]
-            m0.remove(m0.getElementsByClass('Rest')[0])
+            m0 = bl2.getElementsByClass('Measure').first()
+            m0.remove(m0.getElementsByClass('Rest').first())
             m0.padAsAnacrusis()
         return bl2
 
diff --git a/music21/freezeThaw.py b/music21/freezeThaw.py
index 13a7f7f53..67c91348a 100644
--- a/music21/freezeThaw.py
+++ b/music21/freezeThaw.py
@@ -1157,7 +1157,7 @@ class Test(unittest.TestCase):
                            variantName='rhythmic_switch', replacementDuration=3.0)
 
         # test Variant is in stream
-        unused_v1 = c.parts[0].getElementsByClass('Variant')[0]
+        unused_v1 = c.parts.first().getElementsByClass('Variant').first()
 
         sf = freezeThaw.StreamFreezer(c, fastButUnsafe=True)
         # sf.v = v
diff --git a/music21/graph/axis.py b/music21/graph/axis.py
index d0193f94f..9a5b6777c 100644
--- a/music21/graph/axis.py
+++ b/music21/graph/axis.py
@@ -829,7 +829,7 @@ class OffsetAxis(PositionAxis):
         [(0.0, '0'), (1.0, '1'), (5.0, '2'), (9.0, '3'), (13.0, '4'), (17.0, '5'),
          (21.0, '6'), (25.0, '7'), (29.0, '8')]
 
-        >>> a = graph.plot.PlotStream(s.parts[0].flat)  # on a Part
+        >>> a = graph.plot.PlotStream(s.parts.first().flat)  # on a Part
         >>> plotS = graph.plot.PlotStream(s)
         >>> ax = graph.axis.OffsetAxis(plotS)
         >>> ax.setBoundariesFromData()
diff --git a/music21/graph/plot.py b/music21/graph/plot.py
index b5d10be3c..05006189b 100644
--- a/music21/graph/plot.py
+++ b/music21/graph/plot.py
@@ -951,7 +951,7 @@ class WindowedKey(WindowedAnalysis):
 
     Set the processor class to one of the following for different uses:
 
-    >>> p = graph.plot.WindowedKey(s.parts[0])
+    >>> p = graph.plot.WindowedKey(s.parts.first())
     >>> p.processorClass = analysis.discrete.AardenEssen
     >>> p.processorClass = analysis.discrete.SimpleWeights
     >>> p.processorClass = analysis.discrete.BellmanBudge
@@ -968,7 +968,7 @@ class WindowedAmbitus(WindowedAnalysis):
     Stream plotting of basic pitch span.
 
     >>> s = corpus.parse('bach/bwv66.6')
-    >>> p = graph.plot.WindowedAmbitus(s.parts[0])
+    >>> p = graph.plot.WindowedAmbitus(s.parts.first())
     >>> p.doneAction = None #_DOCS_HIDE
     >>> p.run()  # with defaults and proper configuration, will open graph
 
diff --git a/music21/harmony.py b/music21/harmony.py
index 2eea62bbe..fc574b056 100644
--- a/music21/harmony.py
+++ b/music21/harmony.py
@@ -2288,7 +2288,7 @@ class NoChord(ChordSymbol):
     {11.0 - 12.0} <music21.note.Note C>
     {12.0 - 12.0} <music21.bar.Barline type=final>
 
-    >>> c_major = s.getElementsByClass(ChordSymbol)[0]
+    >>> c_major = s.getElementsByClass(ChordSymbol).first()
     >>> c_major.duration
     <music21.duration.Duration 4.0>
     >>> c_major.offset
diff --git a/music21/layout.py b/music21/layout.py
index 398c5b364..ca4ae9b5c 100644
--- a/music21/layout.py
+++ b/music21/layout.py
@@ -660,7 +660,7 @@ def divideByPages(scoreIn, printUpdates=False, fastMeasures=False):
         for el in thisPageAll:
             if 'Part' not in el.classes and 'StaffGroup' not in el.classes:
                 thisPage.insert(thisPageAll.elementOffset(el), el)
-        firstMeasureOfFirstPart = thisPageAll.parts[0].iter.getElementsByClass('Measure')[0]
+        firstMeasureOfFirstPart = thisPageAll.parts.first().getElementsByClass('Measure').first()
         for el in firstMeasureOfFirstPart:
             if 'PageLayout' in el.classes:
                 thisPage.pageLayout = el
@@ -746,11 +746,11 @@ def getRegionMeasureNumbers(scoreIn, region='Page'):
     else:
         raise ValueError('region must be one of Page or System')
 
-    firstPart = scoreIn.parts[0]
+    firstPart = scoreIn.parts.first()
     # first measure could be 1 or 0 (or something else)
     allMeasures = firstPart.getElementsByClass('Measure')
-    firstMeasureNumber = allMeasures[0].number
-    lastMeasureNumber = allMeasures[-1].number
+    firstMeasureNumber = allMeasures.first().number
+    lastMeasureNumber = allMeasures.last().number
     measureStartList = [firstMeasureNumber]
     measureEndList = []
     allAppropriateLayout = firstPart.flat.getElementsByClass(classesToReturn)
@@ -862,7 +862,7 @@ class LayoutScore(stream.Opus):
 
         >>> #_DOCS_SHOW g = corpus.parse('luca/gloria')
         >>> #_DOCS_SHOW m22 = g.parts[0].iter.getElementsByClass('Measure')[22]
-        >>> #_DOCS_SHOW m22.iter.getElementsByClass('PageLayout')[0].leftMargin = 204.0
+        >>> #_DOCS_SHOW m22.getElementsByClass('PageLayout').first().leftMargin = 204.0
         >>> #_DOCS_SHOW gl = layout.divideByPages(g)
         >>> #_DOCS_SHOW gl.getMarginsAndSizeForPageId(1)
         >>> layout.PageSize(171.0, 204.0, 171.0, 171.0, 1457.0, 1886.0) #_DOCS_HIDE
@@ -1189,9 +1189,8 @@ class LayoutScore(stream.Opus):
 
         # override global information with staff specific pageLayout
         thisStaff = self.pages[pageId].systems[systemId].staves[staffId]
-        try:
-            firstMeasureOfStaff = thisStaff.iter.getElementsByClass('Measure')[0]
-        except IndexError:
+        firstMeasureOfStaff = thisStaff.getElementsByClass('Measure').first()
+        if firstMeasureOfStaff is None:
             firstMeasureOfStaff = stream.Stream()
             environLocal.warn(
                 f'No measures found in pageId {pageId}, systemId {systemId}, staffId {staffId}'
@@ -1239,9 +1238,8 @@ class LayoutScore(stream.Opus):
             return staffSizeCache[cacheKey]
 
         thisStaff = self.pages[pageId].systems[systemId].staves[staffId]
-        try:
-            firstMeasureOfStaff = thisStaff.getElementsByClass('Measure')[0]
-        except IndexError:
+        firstMeasureOfStaff = thisStaff.getElementsByClass('Measure').first()
+        if firstMeasureOfStaff is None:
             firstMeasureOfStaff = stream.Stream()
             environLocal.warn(
                 f'No measures found in pageId {pageId}, systemId {systemId}, staffId {staffId}'
diff --git a/music21/meter.py b/music21/meter.py
index 253a47a0a..a4cd6362f 100644
--- a/music21/meter.py
+++ b/music21/meter.py
@@ -4207,7 +4207,7 @@ class TimeSignature(base.Music21Object):
         is in a `Measure`'s :attr:`~music21.stream.Measure.paddingLeft` property.
 
         >>> c = corpus.parse('bwv1.6')
-        >>> for m in c.parts[0].getElementsByClass('Measure'):
+        >>> for m in c.parts.first().getElementsByClass('Measure'):
         ...     ts = m.timeSignature or m.getContextByClass('TimeSignature')
         ...     print('%s %s' % (m.number, ts.getOffsetFromBeat(4.5) - m.paddingLeft))
         0 0.5
diff --git a/music21/midi/translate.py b/music21/midi/translate.py
index 9eb5484cb..845662876 100644
--- a/music21/midi/translate.py
+++ b/music21/midi/translate.py
@@ -3206,7 +3206,7 @@ class Test(unittest.TestCase):
         from music21 import corpus, interval, instrument
         s = corpus.parse('bwv66.6')
         p1 = s.parts[0]
-        p1.remove(p1.getElementsByClass('Instrument')[0])
+        p1.remove(p1.getElementsByClass('Instrument').first())
         p2 = copy.deepcopy(p1)
         p3 = copy.deepcopy(p1)
 
diff --git a/music21/musedata/translate.py b/music21/musedata/translate.py
index 02dc2e036..1612b1dba 100644
--- a/music21/musedata/translate.py
+++ b/music21/musedata/translate.py
@@ -313,7 +313,7 @@ def musedataPartToStreamPart(museDataPart, inputM21=None):
 
     if museDataPart.stage == 1:
         # cannot yet get stage 1 clef data
-        p.getElementsByClass('Measure')[0].clef = clef.bestClef(p, recurse=True)
+        p.getElementsByClass('Measure').first().clef = clef.bestClef(p, recurse=True)
         p.makeBeams(inPlace=True)
         # will call overridden method on Part
         p.makeAccidentals(inPlace=True)
@@ -529,7 +529,7 @@ class Test(unittest.TestCase):
 #         s = corpus.parse('k168', 1)
 #
 #         self.assertEqual(len(s.parts), 4)
-#         self.assertEqual(str(s.parts[0].flat.getElementsByClass('TimeSignature')[0]),
+#         self.assertEqual(str(s.parts[0].flat.getElementsByClass('TimeSignature').first()),
 #                '<music21.meter.TimeSignature 4/4>')
 #
 #         self.assertEqual([n.offset for
diff --git a/music21/musicxml/m21ToXml.py b/music21/musicxml/m21ToXml.py
index bd3c1b803..e1444c4c3 100644
--- a/music21/musicxml/m21ToXml.py
+++ b/music21/musicxml/m21ToXml.py
@@ -478,7 +478,7 @@ class GeneralObjectExporter:
             st2.metadata = copy.deepcopy(getMetadataFromContext(st))
             return self.fromScore(st2)
 
-        elif st.getElementsByClass('Stream')[0].isFlat:  # like a part w/ measures...
+        elif st.getElementsByClass('Stream').first().isFlat:  # like a part w/ measures...
             st2 = stream.Part()
             st2.mergeAttributes(st)
             st2.elements = copy.deepcopy(st)
@@ -6187,20 +6187,17 @@ class Test(unittest.TestCase):
         d = listNotes[1]
         sl1 = spanner.Slur([c, d])
         p.insert(0.0, sl1)
-        # p.getElementsByClass('Measure')[0].insert(0.0, sl1)
 
         f = listNotes[3]
         g = listNotes[4]
         a = listNotes[5]
         sl2 = spanner.Slur([f, g, a])
         p.insert(0.0, sl2)
-        # p.getElementsByClass('Measure')[0].insert(0.0, sl2)
 
         c2 = listNotes[6]
         g2 = listNotes[-1]
         sl3 = spanner.Slur([c2, g2])
         p.insert(0.0, sl3)
-        # p.getElementsByClass('Measure')[1].insert(0.0, sl3)
         self.assertEqual(self.getXml(p).count('<slur '), 6)
 
     def testSpannersWritePartStaffs(self):
@@ -6406,7 +6403,7 @@ class Test(unittest.TestCase):
         self.assertEqual([e.get('number') for e in endings], ['1,2', '1,2', '3', '3'])
 
         # m21 represents lack of bracket numbers as 0; musicxml uses ''
-        s.parts[0].getElementsByClass('RepeatBracket')[0].number = 0
+        s.parts[0].getElementsByClass('RepeatBracket').first().number = 0
         x = self.getET(s)
         endings = x.findall('.//ending')
         self.assertEqual([e.get('number') for e in endings], ['', '', '3', '3'])
diff --git a/music21/musicxml/xmlToM21.py b/music21/musicxml/xmlToM21.py
index a459dd940..8cfcea7eb 100644
--- a/music21/musicxml/xmlToM21.py
+++ b/music21/musicxml/xmlToM21.py
@@ -1828,7 +1828,7 @@ class PartParser(XMLParserBase):
         #     because it should happen on a voice level.
         if measureParser.fullMeasureRest is True:
             # recurse is necessary because it could be in voices...
-            r1 = m.recurse().getElementsByClass('Rest')[0]
+            r1 = m.recurse().getElementsByClass('Rest').first()
             lastTSQl = self.lastTimeSignature.barDuration.quarterLength
             if (r1.fullMeasure is True  # set by xml measure='yes'
                                     or (r1.duration.quarterLength != lastTSQl
@@ -5678,7 +5678,7 @@ class Test(unittest.TestCase):
         from music21.musicxml import testPrimitive
 
         s = converter.parse(testPrimitive.voiceDouble)
-        m1 = s.parts[0].getElementsByClass('Measure')[0]
+        m1 = s.parts[0].getElementsByClass('Measure').first()
         self.assertTrue(m1.hasVoices())
 
         self.assertEqual([v.id for v in m1.voices], ['1', '2'])
@@ -5758,8 +5758,8 @@ class Test(unittest.TestCase):
         s = converter.parse(testPrimitive.mixedVoices1a)
         self.assertEqual(len(s.getElementsByClass('PartStaff')), 2)
         self.assertEqual(len(s.recurse().getElementsByClass('Barline')), 2)
-        lastMeasure = s.parts[0].getElementsByClass('Measure')[-1]
-        lastElement = lastMeasure[-1]
+        lastMeasure = s.parts[0].getElementsByClass('Measure').last()
+        lastElement = lastMeasure.last()
         lastOffset = lastMeasure.elementOffset(lastElement, stringReturns=True)
         self.assertEqual(lastOffset, 'highestTime')
 
@@ -6016,9 +6016,9 @@ class Test(unittest.TestCase):
         from music21 import converter
 
         s = converter.parse(testPrimitive.transposingInstruments72a)
-        i1 = s.parts[0].flat.getElementsByClass('Instrument')[0]
-        i2 = s.parts[1].flat.getElementsByClass('Instrument')[0]
-        unused_i3 = s.parts[2].flat.getElementsByClass('Instrument')[0]
+        i1 = s.parts[0].flat.getElementsByClass('Instrument').first()
+        i2 = s.parts[1].flat.getElementsByClass('Instrument').first()
+        # unused_i3 = s.parts[2].flat.getElementsByClass('Instrument').first()
 
         self.assertEqual(str(i1.transposition), '<music21.interval.Interval M-2>')
         self.assertEqual(str(i2.transposition), '<music21.interval.Interval M-6>')
@@ -6383,7 +6383,7 @@ class Test(unittest.TestCase):
         testFp = thisDir / 'testTrillOnOneNote.xml'
         c = converter.parse(testFp)  # , forceSource=True)
 
-        trillExtension = c.parts[0].getElementsByClass('TrillExtension')[0]
+        trillExtension = c.parts[0].getElementsByClass('TrillExtension').first()
         fSharpTrill = c.recurse().notes[0]
         # print(trillExtension.placement)
         self.assertEqual(fSharpTrill.name, 'F#')
@@ -6399,7 +6399,7 @@ class Test(unittest.TestCase):
         '''
         from music21 import corpus
         c = corpus.parse('luca/gloria')
-        r = c.parts[1].measure(99).getElementsByClass('Rest')[0]
+        r = c.parts[1].measure(99).getElementsByClass('Rest').first()
         bracketAttachedToRest = r.getSpannerSites()[0]
         self.assertIn('Line', bracketAttachedToRest.classes)
         self.assertEqual(bracketAttachedToRest.idLocal, '1')
@@ -6412,7 +6412,7 @@ class Test(unittest.TestCase):
         c = corpus.parse('demos/voices_with_chords.xml')
         m1 = c.parts[0].measure(1)
         # m1.show('text')
-        firstChord = m1.voices.getElementById('2').getElementsByClass('Chord')[0]
+        firstChord = m1.voices.getElementById('2').getElementsByClass('Chord').first()
         self.assertEqual(repr(firstChord), '<music21.chord.Chord G4 B4>')
         self.assertEqual(firstChord.offset, 1.0)
 
@@ -6616,7 +6616,8 @@ class Test(unittest.TestCase):
 
         self.assertEqual('augmented-seventh',
                          s.flat.getElementsByClass('ChordSymbol')[0].chordKind)
-        self.assertEqual('none', s.flat.getElementsByClass('ChordSymbol')[1].chordKind)
+        self.assertEqual('none',
+                         s.flat.getElementsByClass('ChordSymbol')[1].chordKind)
 
         self.assertEqual('random', str(s.flat.getElementsByClass('NoChord')[
             0].chordKindStr))
@@ -6742,7 +6743,7 @@ class Test(unittest.TestCase):
 
         nonconformingInput = testPrimitive.multiDigitEnding.replace("1,2", "ad lib.")
         score2 = converter.parse(nonconformingInput)
-        repeatBracket = score2.recurse().getElementsByClass('RepeatBracket')[0]
+        repeatBracket = score2.recurse().getElementsByClass('RepeatBracket').first()
         self.assertListEqual(repeatBracket.getNumberList(), [1])
 
     def testChordAlteration(self):
diff --git a/music21/noteworthy/translate.py b/music21/noteworthy/translate.py
index 7262e8d6e..b71ca160c 100644
--- a/music21/noteworthy/translate.py
+++ b/music21/noteworthy/translate.py
@@ -854,7 +854,7 @@ class Test(unittest.TestCase):
         myScore = NoteworthyTranslator().parseFile(simplePath)
         self.assertEqual(len(myScore.flat.notes), 1)
         self.assertEqual(str(myScore.flat.notes[0].name), 'E')
-        self.assertEqual(str(myScore.flat.getElementsByClass('Clef')[0]),
+        self.assertEqual(str(myScore.flat.getElementsByClass('Clef').first()),
                          '<music21.clef.BassClef>')
 
     def testKeySignatureAtBeginning(self):
@@ -891,7 +891,7 @@ class Test(unittest.TestCase):
         nwt = NoteworthyTranslator()
         s = nwt.parseString(info)
         # s.show('text')
-        n1 = s.parts[1].getElementsByClass('Measure')[0].notes[0]
+        n1 = s.parts[1].getElementsByClass('Measure').first().notes.first()
         self.assertEqual(n1.pitch.accidental.alter, -1.0)
 
 
diff --git a/music21/repeat.py b/music21/repeat.py
index 782be7c7a..8ec1d56ea 100644
--- a/music21/repeat.py
+++ b/music21/repeat.py
@@ -421,7 +421,7 @@ def insertRepeatEnding(s, start, end, endingNumber=1, *, inPlace=False):
     >>> repeatBrackets = c1.flat.getElementsByClass(spanner.RepeatBracket)
     >>> len(repeatBrackets)
     8
-    >>> len(c1.parts[0].getElementsByClass(spanner.RepeatBracket))
+    >>> len(c1.parts.first().getElementsByClass(spanner.RepeatBracket))
     2
     '''
 
@@ -982,7 +982,7 @@ class Expander:
     def _getRepeatExpressionCommand(self, streamObj):
         '''Get the instance found in this stream; assumes that there is one.
         '''
-        return streamObj.flat.getElementsByClass('RepeatExpressionCommand')[0]
+        return streamObj.flat.getElementsByClass('RepeatExpressionCommand').first()
 
     def _daCapoIsCoherent(self):
         '''Check of a DC statement is coherent.
diff --git a/music21/romanText/translate.py b/music21/romanText/translate.py
index fdb65b13d..8799db8a5 100644
--- a/music21/romanText/translate.py
+++ b/music21/romanText/translate.py
@@ -109,15 +109,16 @@ Now generate the histogram:
 OMIT_FROM_DOCS
 
 >>> x = converter.parse('romantext: m1 a: VI')
->>> [str(p) for p in x.flat.getElementsByClass('RomanNumeral')[0].pitches]
+>>> [str(p) for p in x.flat.getElementsByClass('RomanNumeral').first().pitches]
 ['F5', 'A5', 'C6']
 
 >>> x = converter.parse('romantext: m1 a: vi')
->>> [str(p) for p in x.flat.getElementsByClass('RomanNumeral')[0].pitches]
+>>> [str(p) for p in x.flat.getElementsByClass('RomanNumeral').first().pitches]
 ['F#5', 'A5', 'C#6']
 
 >>> [str(p) for p in
-...  converter.parse('romantext: m1 a: vio').flat.getElementsByClass('RomanNumeral')[0].pitches]
+...  converter.parse('romantext: m1 a: vio'
+...                  ).flat.getElementsByClass('RomanNumeral').first().pitches]
 ['F#5', 'A5', 'C6']
 '''
 import copy
@@ -1179,7 +1180,7 @@ class TestSlow(unittest.TestCase):  # pragma: no cover
         s = romanTextToStreamScore(testFiles.swv23)
         mStream = s.parts[0].getElementsByClass('Measure')
         # the first four measures should all have the same content
-        rn1 = mStream[1].getElementsByClass('RomanNumeral')[0]
+        rn1 = mStream[1].getElementsByClass('RomanNumeral').first()
         self.assertEqual([str(x) for x in rn1.pitches], ['D5', 'F#5', 'A5'])
         self.assertEqual(str(rn1.figure), 'V')
         rn2 = mStream[1].getElementsByClass('RomanNumeral')[1]
@@ -1241,9 +1242,9 @@ class TestSlow(unittest.TestCase):  # pragma: no cover
         rn = m2b.getElementsByClass('RomanNumeral')[1]
         self.assertEqual(str(rn.figure), 'ii')
 
-        rn = m3a.getElementsByClass('RomanNumeral')[0]
+        rn = m3a.getElementsByClass('RomanNumeral').first()
         self.assertEqual(str(rn.figure), 'V/ii')
-        rn = m3b.getElementsByClass('RomanNumeral')[0]
+        rn = m3b.getElementsByClass('RomanNumeral').first()
         self.assertEqual(str(rn.figure), 'V/ii')
 
     def testMeasureCopyingB(self):
@@ -1314,9 +1315,9 @@ m8 I
 '''
         s = converter.parse(testCase, format='romanText')
         m = s.measure(7).flat
-        self.assertEqual(m.getElementsByClass('RomanNumeral')[0].key.name, 'D major')
+        self.assertEqual(m.getElementsByClass('RomanNumeral').first().key.name, 'D major')
         m = s.measure(8).flat
-        self.assertEqual(m.getElementsByClass('RomanNumeral')[0].key.name, 'D major')
+        self.assertEqual(m.getElementsByClass('RomanNumeral').first().key.name, 'D major')
 
     def testPivotInCopyMultiple2(self):
         '''
@@ -1335,7 +1336,7 @@ m8 I
 '''
         s = converter.parse(testCase, format='romanText')
         m = s.measure(5).flat
-        self.assertEqual(m.getElementsByClass('RomanNumeral')[0].key.name, 'G major')
+        self.assertEqual(m.getElementsByClass('RomanNumeral').first().key.name, 'G major')
 
     def testPivotInCopySingle(self):
         from music21 import converter
@@ -1349,7 +1350,7 @@ m6 I
 '''
         s = converter.parse(testCase, format='romanText')
         m = s.measure(6).flat
-        self.assertEqual(m.getElementsByClass('RomanNumeral')[0].key.name, 'D major')
+        self.assertEqual(m.getElementsByClass('RomanNumeral').first().key.name, 'D major')
 
     def testSecondaryInCopyMultiple(self):
         '''
@@ -1368,10 +1369,10 @@ m7 = m3
 
         s = romanTextToStreamScore(testSecondaryInCopy)
         m = s.measure(6).flat
-        self.assertEqual(m.getElementsByClass('RomanNumeral')[0].pitchedCommonName,
+        self.assertEqual(m.getElementsByClass('RomanNumeral').first().pitchedCommonName,
                          'E-dominant seventh chord')
         m = s.measure(7).flat
-        self.assertEqual(m.getElementsByClass('RomanNumeral')[0].pitchedCommonName,
+        self.assertEqual(m.getElementsByClass('RomanNumeral').first().pitchedCommonName,
                          'E-dominant seventh chord')
         # s.show()
 
@@ -1442,11 +1443,11 @@ m3 NC b3 G: V
 '''
         s = converter.parse(src, format='romantext')
         p = s.parts[0]
-        m1 = p.getElementsByClass('Measure')[0]
+        m1 = p.getElementsByClass('Measure').first()
         r1 = m1.notesAndRests[-1]
         self.assertIn('Rest', r1.classes)
         self.assertEqual(r1.quarterLength, 1.0)
-        noChordObj = m1.getElementsByClass('Harmony')[-1]
+        noChordObj = m1.getElementsByClass('Harmony').last()
         self.assertIsInstance(noChordObj, NoChord)
 
         m2 = p.getElementsByClass('Measure')[1]
@@ -1512,7 +1513,7 @@ m1 C: I'''
         src = '''m1 G: I b3 v d: i b4 V'''
         s = converter.parse(src, format='romantext')
         p = s.parts[0]
-        m1 = p.getElementsByClass('Measure')[0]
+        m1 = p.getElementsByClass('Measure').first()
         allRNs = m1.getElementsByClass('RomanNumeral')
         notPChord = allRNs[0]
         pChord = allRNs[1]
diff --git a/music21/romanText/tsvConverter.py b/music21/romanText/tsvConverter.py
index a8769bed5..689556b0c 100644
--- a/music21/romanText/tsvConverter.py
+++ b/music21/romanText/tsvConverter.py
@@ -331,7 +331,7 @@ class TsvHandler:
         self.prepStream()
 
         s = self.preparedStream
-        p = s.parts[0]  # Just to get to the part, not that there are several.
+        p = s.parts.first()  # Just to get to the part, not that there are several.
 
         for thisChord in self.chordList:
             offsetInMeasure = thisChord.beat - 1  # beats always measured in quarter notes
diff --git a/music21/romanText/writeRoman.py b/music21/romanText/writeRoman.py
index 996d8141b..a7ce318f8 100644
--- a/music21/romanText/writeRoman.py
+++ b/music21/romanText/writeRoman.py
@@ -137,7 +137,7 @@ class RnWriter(prebase.ProtoM21Object):
 
             elif isinstance(obj, stream.Score):
                 if obj.parts:
-                    self.container = obj.parts[0]
+                    self.container = obj.parts.first()
                 else:  # score with no parts
                     self.container = obj
 
diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py
index 9b58f6bde..ab859b5f1 100644
--- a/music21/scale/__init__.py
+++ b/music21/scale/__init__.py
@@ -3979,7 +3979,7 @@ Franck Jedrzejewski continued fractions approx. of 12-tet
 
         s = corpus.parse('luca/gloria').measures(70, 79)
         for p in s.parts:
-            inst = p.flat.getElementsByClass(instrument.Instrument)[0]
+            inst = p.recurse().getElementsByClass(instrument.Instrument).first()
             inst.midiProgram = 52
         sc = ScalaScale('F2', 'pyth_12.scl')
         sc.tune(s)
diff --git a/music21/stream/__init__.py b/music21/stream/__init__.py
index 01ec6b62a..a69dde5ec 100644
--- a/music21/stream/__init__.py
+++ b/music21/stream/__init__.py
@@ -329,7 +329,20 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         collect and return elements as a Stream.
 
         >>> a = stream.Part(id='hello')
-        >>> a.repeatInsert(note.Rest(), [0, 1, 2, 3, 4, 5])
+        >>> names = ['C', 'D', 'E', 'F', 'G', 'A']
+        >>> for i in range(6):
+        ...     name = names[i]
+        ...     a.insert(i + 1, note.Note(name))
+        >>> a[0]
+        <music21.note.Note C>
+        >>> a[-1]
+        <music21.note.Note A>
+
+        Out of range notes raise an IndexError:
+
+        >>> a[99]
+        Traceback (most recent call last):
+        IndexError: attempting to access index 99 while elements is of size 6
         >>> subslice = a[2:5]
         >>> subslice
         <music21.stream.Part hello>
@@ -339,9 +352,9 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         >>> len(subslice)
         3
         >>> a[1].offset
-        1.0
+        2.0
         >>> subslice[1].offset
-        3.0
+        4.0
 
         >>> b = note.Note()
         >>> b.id = 'green'
@@ -375,7 +388,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         >>> a['green'] is b
         True
 
-        If not found, a KeyError will be raised:
+        If a string or class is not found, a KeyError will be raised:
 
         >>> a['purple']
         Traceback (most recent call last):
@@ -386,6 +399,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         KeyError: "provided class (<class 'music21.layout.StaffLayout'>) does
             not match any contained Objects"
 
+        Changed in v7. -- out of range indexes now raise an IndexError, not StreamException
         '''
         # need to sort if not sorted, as this call may rely on index positions
         if not self.isSorted and self.autoSort:
@@ -402,7 +416,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
                 try:
                     match = self.elements[k]
                 except IndexError:
-                    raise StreamException(
+                    raise IndexError(
                         f'attempting to access index {k} '
                         + f'while elements is of size {len(self.elements)}'
                     )
@@ -444,6 +458,57 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
             else:
                 raise KeyError(f'provided class ({k}) does not match any contained Objects')
 
+    def first(self):
+        '''
+        Return the first element of a Stream.  (Added for compatibility with StreamIterator)
+        Or None if the Stream is empty.
+
+        Unlike s.iter.first(), which is a significant performance gain, s.first() is the
+        same speed as s[0], except for not raising an IndexError.
+
+        >>> nC = note.Note('C4')
+        >>> nD = note.Note('D4')
+        >>> s = stream.Stream()
+        >>> s.append([nC, nD])
+        >>> s.first()
+        <music21.note.Note C>
+
+        >>> empty = stream.Stream()
+        >>> print(empty.first())
+        None
+
+        New in v7.
+        '''
+        try:
+            return self[0]
+        except IndexError:
+            return None
+
+    def last(self):
+        '''
+        Return the last element of a Stream.  (Added for compatibility with StreamIterator)
+        Or None if the Stream is empty.
+
+        s.first() is the same speed as s[-1], except for not raising an IndexError.
+
+        >>> nC = note.Note('C4')
+        >>> nD = note.Note('D4')
+        >>> s = stream.Stream()
+        >>> s.append([nC, nD])
+        >>> s.last()
+        <music21.note.Note D>
+
+        >>> empty = stream.Stream()
+        >>> print(empty.last())
+        None
+
+        New in v7.
+        '''
+        try:
+            return self[-1]
+        except IndexError:
+            return None
+
     def __contains__(self, el):
         '''
         Returns True if `el` definitely is in the stream and False otherwise.
@@ -930,7 +995,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         {0.0} <music21.layout.StaffLayout distance None, staffNumber None,
                   staffSize None, staffLines 4>
 
-        >>> staffLayout = m.getElementsByClass('StaffLayout')[0]
+        >>> staffLayout = m.getElementsByClass('StaffLayout').first()
         >>> staffLayout.staffLines = 1
         >>> m.staffLines
         1
@@ -3742,8 +3807,8 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         Because bwv66.6 has a pickup measure, and we requested to start at measure 1,
         this is NOT true:
 
-        >>> firstExcerptMeasure = bachExcerpt.getElementsByClass('Measure')[0]
-        >>> firstBachMeasure = bachIn.parts[0].getElementsByClass('Measure')[0]
+        >>> firstExcerptMeasure = bachExcerpt.getElementsByClass('Measure').first()
+        >>> firstBachMeasure = bachIn.parts[0].getElementsByClass('Measure').first()
         >>> firstExcerptMeasure is firstBachMeasure
         False
         >>> firstBachMeasure.number
@@ -3756,7 +3821,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         there will be no error if there is not a pickup measure.
 
         >>> bachExcerpt = bachIn.parts[0].measures(0, 3)
-        >>> excerptNote = bachExcerpt.getElementsByClass('Measure')[0].notes[0]
+        >>> excerptNote = bachExcerpt.getElementsByClass('Measure').first().notes.first()
         >>> originalNote = bachIn.parts[0].flat.notes[0]
         >>> excerptNote is originalNote
         True
@@ -3793,8 +3858,8 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
 
         The measure elements are the same objects as the original:
 
-        >>> lastExcerptMeasure = bachExcerpt3.getElementsByClass('Measure')[-1]
-        >>> lastOriginalMeasure = bachIn.parts[0].getElementsByClass('Measure')[-1]
+        >>> lastExcerptMeasure = bachExcerpt3.getElementsByClass('Measure').last()
+        >>> lastOriginalMeasure = bachIn.parts[0].getElementsByClass('Measure').last()
         >>> lastExcerptMeasure is lastOriginalMeasure
         True
 
@@ -4382,7 +4447,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         # core routines for a single Stream
         else:
             if self.hasMeasures():
-                return self.getElementsByClass('Measure')[-1].rightBarline
+                return self.getElementsByClass('Measure').last().rightBarline
             elif hasattr(self, 'rightBarline'):
                 return self.rightBarline
             else:
@@ -4402,7 +4467,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
 
         # core routines for a single Stream
         if self.hasMeasures():
-            self.getElementsByClass('Measure')[-1].rightBarline = value
+            self.getElementsByClass('Measure').last().rightBarline = value
         elif hasattr(self, 'rightBarline'):
             self.rightBarline = value  # pylint: disable=attribute-defined-outside-init
         # do nothing for other streams
@@ -4956,7 +5021,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
             {1.5} <music21.note.Note D>
 
         >>> qjFlat = qj.flat
-        >>> k1 = qjFlat.getElementsByClass(key.KeySignature)[0]
+        >>> k1 = qjFlat.getElementsByClass(key.KeySignature).first()
         >>> k3flats = key.KeySignature(-3)
         >>> qjFlat.replace(k1, k3flats, allDerived=True)
         >>> qj.getElementsByClass(stream.Measure)[1].insert(0, key.KeySignature(5))
@@ -5828,7 +5893,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         if toSoundingPitch:
             # environLocal.printDebug(['at sounding pitch', allParts[0].atSoundingPitch])
             if (self.hasPartLikeStreams()
-                     and self.getElementsByClass('Stream')[0].atSoundingPitch is False):
+                     and self.getElementsByClass('Stream').first().atSoundingPitch is False):
                 workObj = self.toSoundingPitch(inPlace=False)
             elif self.atSoundingPitch is False:
                 workObj = self.toSoundingPitch(inPlace=False)
@@ -5838,7 +5903,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
             workObj = self
 
         if self.hasPartLikeStreams():
-            templateStream = workObj.getElementsByClass('Stream')[0]
+            templateStream = workObj.getElementsByClass('Stream').first()
         else:
             templateStream = workObj
 
@@ -6286,7 +6351,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         >>> sMeasures = s.makeNotation()
         >>> len(sMeasures.getElementsByClass('Measure'))
         4
-        >>> sMeasures.getElementsByClass('Measure')[-1].rightBarline.type
+        >>> sMeasures.getElementsByClass('Measure').last().rightBarline.type
         'final'
         '''
         # determine what is the object to work on first
@@ -9045,7 +9110,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         True
         >>> s.parts[0].isWellFormedNotation()
         True
-        >>> s.parts[0].getElementsByClass('Measure')[0].isWellFormedNotation()
+        >>> s.parts[0].getElementsByClass('Measure').first().isWellFormedNotation()
         True
 
         >>> s = stream.Score()
@@ -10394,7 +10459,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
 
         Swap voice ids in first measure:
 
-        >>> m0 = c.parts[0].getElementsByClass('Measure')[0]
+        >>> m0 = c.parts[0].getElementsByClass('Measure').first()
         >>> m0.voices[0].id, m0.voices[1].id
         ('3', '4')
         >>> m0.voices[0].id = '4'
@@ -10535,7 +10600,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
             # best clef will be assigned later
             if p.hasMeasures():
                 # place in first measure
-                p.getElementsByClass('Measure')[0].clef = clef.bestClef(p, recurse=True)
+                p.getElementsByClass('Measure').first().clef = clef.bestClef(p, recurse=True)
         return s
 
     def explode(self):
@@ -12101,7 +12166,7 @@ class Measure(Stream):
         Test round tripping:
 
         >>> s2 = converter.parseData(xml)
-        >>> print(s2.semiFlat.getElementsByClass('Measure')[0].measureNumberWithSuffix())
+        >>> print(s2.semiFlat.getElementsByClass('Measure').first().measureNumberWithSuffix())
         4A
 
         Note that we use print here because in parsing the data will become a unicode string.
@@ -13022,7 +13087,7 @@ class Score(Stream):
             {0.0} <music21.chord.Chord E2 G3 B3 E4>
             {4.0} <music21.bar.Barline type=final>
 
-        >>> lastChord = excerptChords.recurse().getElementsByClass('Chord')[-1]
+        >>> lastChord = excerptChords.recurse().getElementsByClass('Chord').last()
         >>> lastChord
         <music21.chord.Chord E2 G3 B3 E4>
 
@@ -13203,7 +13268,7 @@ class Score(Stream):
         >>> post = s.partsToVoices(voiceAllocation=4)
         >>> len(post.parts)
         1
-        >>> len(post.parts[0].getElementsByClass('Measure')[0].voices)
+        >>> len(post.parts.first().getElementsByClass('Measure').first().voices)
         4
         >>> len(post.flat.notes)
         165
diff --git a/music21/stream/iterator.py b/music21/stream/iterator.py
index 3bf52cd89..f2351c590 100644
--- a/music21/stream/iterator.py
+++ b/music21/stream/iterator.py
@@ -15,7 +15,7 @@ this class contains iterators and filters for walking through streams
 StreamIterators are explicitly allowed to access private methods on streams.
 '''
 import copy
-from typing import TypeVar, List, Union, Callable
+from typing import TypeVar, List, Union, Callable, Optional, Dict
 import unittest
 import warnings
 
@@ -29,6 +29,7 @@ from music21.sites import SitesException
 
 
 _SIter = TypeVar('_SIter')
+FilterType = Union[Callable, filters.StreamFilter]
 
 # -----------------------------------------------------------------------------
 
@@ -88,12 +89,12 @@ class StreamIterator(prebase.ProtoM21Object):
     Changed in v.5.2 -- all arguments except srcStream are keyword only.
     '''
     def __init__(self,
-                 srcStream,
+                 srcStream: 'music21.stream.Stream',
                  *,
-                 filterList=None,
-                 restoreActiveSites=True,
-                 activeInformation=None,
-                 ignoreSorting=False):
+                 filterList: Union[List[FilterType], FilterType, None] = None,
+                 restoreActiveSites: bool = True,
+                 activeInformation: Optional[Dict] = None,
+                 ignoreSorting: bool = False):
         if not ignoreSorting and srcStream.isSorted is False and srcStream.autoSort:
             srcStream.sort()
         self.srcStream: 'music21.stream.Stream' = srcStream
@@ -105,7 +106,7 @@ class StreamIterator(prebase.ProtoM21Object):
 
         # this information can help in speed later
         self.elementsLength = len(self.srcStream._elements)
-        self.sectionIndex = -1
+        self.sectionIndex = -1  # where we are within a given section (_elements or _endElements)
         self.iterSection = '_elements'
 
         self.cleanupOnStop = False
@@ -122,7 +123,7 @@ class StreamIterator(prebase.ProtoM21Object):
         # self.filters is a list of expressions that
         # return True or False for an element for
         # whether it should be yielded.
-        self.filters: List[Union[Callable, filters.StreamFilter]] = filterList
+        self.filters: List[FilterType] = filterList
         self._len = None
         self._matchingElements = None
 
@@ -131,7 +132,7 @@ class StreamIterator(prebase.ProtoM21Object):
         if activeInformation is not None:
             self.activeInformation = activeInformation
         else:
-            self.activeInformation = {}
+            self.activeInformation = {}  # in Py3.8 make a TypedDict
             self.updateActiveInformation()
 
     def _reprInternal(self):
@@ -430,6 +431,94 @@ class StreamIterator(prebase.ProtoM21Object):
         )
         return out
 
+    def first(self) -> Optional[base.Music21Object]:
+        '''
+        Efficiently return the first matching element, or None if no
+        elements match.
+
+        Does not require creating the whole list of matching elements.
+
+        >>> s = converter.parse('tinyNotation: 3/4 D4 E2 F4 r2 G2 r4')
+        >>> s.recurse().notes.first()
+        <music21.note.Note D>
+        >>> s.recurse().getElementsByClass('Rest').first()
+        <music21.note.Rest rest>
+
+        If no elements match, returns None:
+
+        >>> print(s.recurse().getElementsByClass('Chord').first())
+        None
+
+        New in v7.
+
+        OMIT_FROM_DOCS
+
+        Ensure that next continues after the first note running:
+
+        >>> notes = s.recurse().notes
+        >>> notes.first()
+        <music21.note.Note D>
+        >>> next(notes)
+        <music21.note.Note E>
+
+        Now reset on new iteration:
+
+        >>> for n in notes:
+        ...     print(n)
+        <music21.note.Note D>
+        <music21.note.Note E>
+        ...
+
+        An Empty stream:
+
+        >>> s = stream.Stream()
+        >>> s.iter.notes.first() is None
+        True
+        '''
+        iter(self)
+        try:
+            return next(self)
+        except StopIteration:
+            return None
+
+    def last(self) -> Optional[base.Music21Object]:
+        '''
+        Returns the last matching element, or None if no elements match.
+
+        Currently is not efficient (does not iterate backwards, for instance),
+        but easier than checking for an IndexError.  Might be refactored later
+        to iterate the stream backwards instead if it gets a lot of use.
+
+        >>> s = converter.parse('tinyNotation: 3/4 D4 E2 F4 r2 G2 r4')
+        >>> s.recurse().notes.last()
+        <music21.note.Note G>
+        >>> s.recurse().getElementsByClass('Rest').last()
+        <music21.note.Rest rest>
+
+        New in v7.
+
+        OMIT_FROM_DOCS
+
+        Check on empty Stream:
+
+        >>> s2 = stream.Stream()
+        >>> s2.iter.notes.last() is None
+        True
+
+        Next has a different feature from first(), will start again from beginning.
+        This behavior may change.
+
+        >>> notes = s.recurse().notes
+        >>> notes.last()
+        <music21.note.Note G>
+        >>> next(notes)
+        <music21.note.Note D>
+        '''
+        fe = self.matchingElements()
+        if not fe:
+            return None
+        return fe[-1]
+
     # ---------------------------------------------------------------
     # start and stop
     def updateActiveInformation(self):
@@ -455,8 +544,6 @@ class StreamIterator(prebase.ProtoM21Object):
         self.updateActiveInformation()
         for f in self.filters:
             if hasattr(f, 'reset'):
-                # for some reason, PyCharm thinks this is a string...
-                # noinspection PyCallingNonCallable
                 f.reset()
 
     def resetCaches(self):
diff --git a/music21/variant.py b/music21/variant.py
index 7d7a7d283..ce6598d89 100644
--- a/music21/variant.py
+++ b/music21/variant.py
@@ -64,10 +64,10 @@ def mergeVariants(streamX, streamY, variantName='variant', *, inPlace=False):
     {3.0} <music21.variant.Variant object of length 1.0>
     {3.0} <music21.note.Note D>
 
-    >>> v0 = mergedStream.getElementsByClass('Variant')[0]
+    >>> v0 = mergedStream.getElementsByClass('Variant').first()
     >>> v0
     <music21.variant.Variant object of length 1.0>
-    >>> v0[0]
+    >>> v0.first()
     <music21.note.Note B->
 
     >>> streamZ = converter.parse('tinynotation: 4/4 a4 b c d e f g a', makeNotation=False)
@@ -830,7 +830,7 @@ def mergePartAsOssia(mainPart, ossiaPart, ossiaName,
                 if recurseInMeasures is True:
                     returnMeasure = returnObj.iter.getElementsByOffset(
                         ossiaOffset
-                    ).getElementsByClass(stream.Measure)[0]
+                    ).getElementsByClass(stream.Measure).first()
                     mergeVariantsEqualDuration(
                         [returnMeasure, ossiaMeasure],
                         [ossiaName],
@@ -1882,11 +1882,11 @@ def _getNextElements(s, v, numberOfElements=1):
     lengthType = v.lengthType
     # Get class of elements in variant or replaced Region
     if lengthType == 'elongation':
-        vClass = type(v.getElementsByClass(['Measure', 'Note', 'Rest'])[0])
+        vClass = type(v.getElementsByClass(['Measure', 'Note', 'Rest']).first())
         if isinstance(vClass, note.GeneralNote):
             vClass = note.GeneralNote
     else:
-        vClass = type(replacedElements.getElementsByClass(['Measure', 'Note', 'Rest'])[0])
+        vClass = type(replacedElements.getElementsByClass(['Measure', 'Note', 'Rest']).first())
         if isinstance(vClass, note.GeneralNote):
             vClass = note.GeneralNote
 
@@ -2385,7 +2385,7 @@ class Variant(base.Music21Object):
         vStart = self.getOffsetBySite(contextStream)
 
         if includeSpacers is True:
-            spacerDuration = self.getElementsByClass('SpacerRest')[0].duration.quarterLength
+            spacerDuration = self.getElementsByClass('SpacerRest').first().duration.quarterLength
         else:
             spacerDuration = 0.0
 
diff --git a/music21/voiceLeading.py b/music21/voiceLeading.py
index 825a68ac1..633f8ec4c 100644
--- a/music21/voiceLeading.py
+++ b/music21/voiceLeading.py
@@ -1293,7 +1293,7 @@ def getVerticalityFromObject(music21Obj, scoreObjectIsFrom, classFilterList=None
     (under development)
 
     >>> c = corpus.parse('bach/bwv66.6')
-    >>> n1 = c.flat.getElementsByClass(note.Note)[0]
+    >>> n1 = c.flat.getElementsByClass(note.Note).first()
     >>> voiceLeading.getVerticalityFromObject(n1, c)
     <music21.voiceLeading.Verticality
         contentDict={0: [<music21.instrument.Instrument 'P1: Soprano: Instrument 1'>,
@@ -1343,11 +1343,13 @@ def getVerticalityFromObject(music21Obj, scoreObjectIsFrom, classFilterList=None
 
 class Verticality(base.Music21Object):
     '''
+    DEPRECATED in v7 in favor of tree.verticality.Verticality
+
     A Verticality (previously called "vertical slice")
     object provides more accessible information about
     vertical moments in a score. A Verticality is
     instantiated by passing in a dictionary of
-    the form {partNumber : [ music21Objects ] }
+    the form {partNumber: [ music21Objects ] }
 
     Verticalities are useful to provide direct and easy access to objects in a part.
     A list of Verticalities, although similar to the list of chords from a chordified score,
@@ -1358,7 +1360,7 @@ class Verticality(base.Music21Object):
     score is the same as modifying the elements
     of the Verticality in the score directly.
 
-    >>> vs1 = voiceLeading.Verticality({0:[note.Note('A4'), harmony.ChordSymbol('Cm')],
+    >>> vs1 = voiceLeading.Verticality({0: [note.Note('A4'), harmony.ChordSymbol('Cm')],
     ...                                 1: [note.Note('F2')]})
     >>> vs1.getObjectsByClass(note.Note)
     [<music21.note.Note A>, <music21.note.Note F>]
@@ -1393,17 +1395,18 @@ class Verticality(base.Music21Object):
 
         >>> V = voiceLeading.Verticality
         >>> N = note.Note
-        >>> V({0:N('A4'), 1:N('B4'), 2:N('A4')}).isConsonant()
+        >>> V({0: N('A4'), 1: N('B4'), 2: N('A4')}).isConsonant()
         False
-        >>> V({0:N('A4'), 1:N('B4'), 2:N('C#4')}).isConsonant()
+        >>> V({0: N('A4'), 1: N('B4'), 2: N('C#4')}).isConsonant()
         False
-        >>> V({0:N('C3'), 1:N('G5'), 2:chord.Chord(['C3', 'E4', 'G5'])}).isConsonant()
+        >>> V({0: N('C3'), 1: N('G5'), 2: chord.Chord(['C3', 'E4', 'G5'])}).isConsonant()
         True
-        >>> V({0:N('A3'), 1:N('B3'), 2:N('C4')}).isConsonant()
+        >>> V({0: N('A3'), 1: N('B3'), 2: N('C4')}).isConsonant()
         False
-        >>> V({0:N('C1'), 1:N('C2'), 2:N('C3'), 3:N('G1'), 4:N('G2'), 5:N('G3')}).isConsonant()
+        >>> V({0: N('C1'), 1: N('C2'), 2: N('C3'),
+        ...    3: N('G1'), 4: N('G2'), 5: N('G3')}).isConsonant()
         True
-        >>> V({0:N('A3'), 1:harmony.ChordSymbol('Am')}).isConsonant()
+        >>> V({0: N('A3'), 1: harmony.ChordSymbol('Am')}).isConsonant()
         True
         '''
         return self.getChord().isConsonant()
@@ -1539,8 +1542,8 @@ class Verticality(base.Music21Object):
         the single object if only one. Optionally specify which
         type of objects to return with classFilterList
 
-        >>> vs1 = voiceLeading.Verticality({0:[note.Note('A4'), harmony.ChordSymbol('C')],
-        ...                                 1:[note.Note('C')]})
+        >>> vs1 = voiceLeading.Verticality({0: [note.Note('A4'), harmony.ChordSymbol('C')],
+        ...                                 1: [note.Note('C')]})
         >>> vs1.getObjectsByPart(0, classFilterList=['Harmony'])
         <music21.harmony.ChordSymbol C>
         >>> vs1.getObjectsByPart(0)
@@ -1601,55 +1604,55 @@ class Verticality(base.Music21Object):
         '''
         return a list of all the music21 objects in the Verticality
 
-        >>> vs1 = voiceLeading.Verticality({0:[harmony.ChordSymbol('C'), note.Note('A4'),],
-        ...                                 1:[note.Note('C')]})
+        >>> vs1 = voiceLeading.Verticality({0: [harmony.ChordSymbol('C'), note.Note('A4'),],
+        ...                                 1: [note.Note('C')]})
         >>> vs1.objects
         [<music21.harmony.ChordSymbol C>, <music21.note.Note A>, <music21.note.Note C>]
         '''
         retList = []
         for unused_part, objList in self.contentDict.items():
             for m21object in objList:
-                if m21object is not None:
-                    retList.append(m21object)
+                retList.append(m21object)
         return retList
 
-    def getStream(self, streamVSCameFrom=None):
+    def getStream(self):
         '''
-        returns the stream representation of this Verticality. Optionally pass in
-        the full stream that this verticality was extracted from, and correct key, meter, and time
-        signatures will be included
-        (under development)
+        returns a stream representation of this Verticality. Correct key, meter, and time
+        signatures will be included if they are found in the context of the first part
 
-        >>> vs1 = voiceLeading.Verticality({0:[harmony.ChordSymbol('C'), note.Note('A4'),],
-        ...                                 1:[note.Note('C')]})
-        >>> len(vs1.getStream().flat.getElementsByClass(note.Note))
+        >>> vs1 = voiceLeading.Verticality({0: [harmony.ChordSymbol('C'), note.Note('A4'),],
+        ...                                 1: [note.Note('C')]})
+        >>> vsStream = vs1.getStream()
+        >>> vsStream.show('text')
+        {0.0} <music21.stream.Part part-0>
+            {0.0} <music21.harmony.ChordSymbol C>
+            {0.0} <music21.note.Note A>
+        {0.0} <music21.stream.Part part-1>
+            {0.0} <music21.note.Note C>
+
+        >>> len(vsStream.flat.getElementsByClass(note.Note))
         2
-        >>> len(vs1.getStream().flat.getElementsByClass('Harmony'))
+        >>> len(vsStream.flat.getElementsByClass('Harmony'))
         1
         '''
         from music21 import stream
         retStream = stream.Score()
-        for unused_partNum, elementList in self.contentDict.items():
-            p = stream.Part()
-            if streamVSCameFrom:
-                foundObj = elementList[0]
-
-                ks = foundObj.getContextByClass('KeySignature')
-                ts = foundObj.getContextByClass('TimeSignature')
-                cl = foundObj.getContextByClass('Clef')
-
-                if cl:
-                    p.append(cl)
-                if ks:
-                    p.append(ks)
-                if ts:
-                    p.append(ts)
-                p.append(foundObj)
-            if len(elementList) > 1:
-                for el in elementList:
-                    p.insert(stream.Voice([el]))  # probably wrong! Need to fix!!!
-            else:
-                p.insert(elementList[0])
+        for partNum, elementList in self.contentDict.items():
+            p = stream.Part(id=f'part-{partNum}')
+            foundObj = elementList[0]
+
+            cl = foundObj.getContextByClass('Clef')
+            ks = foundObj.getContextByClass('KeySignature')
+            ts = foundObj.getContextByClass('TimeSignature')
+
+            if cl:
+                p.append(cl)
+            if ks:
+                p.append(ks)
+            if ts:
+                p.append(ts)
+            for el in elementList:
+                p.insert(0, el)  # probably wrong! Need to fix!!!
             retStream.insert(p)
         return retStream
 
@@ -1686,6 +1689,8 @@ class Verticality(base.Music21Object):
         >>> vs.offset(leftAlign=False)
         1.0
         '''
+        if not self.objects:
+            return 0.0
         if leftAlign:
             return sorted(self.objects, key=lambda m21Obj: m21Obj.offset)[0].offset
         else:
@@ -1700,11 +1705,11 @@ class Verticality(base.Music21Object):
         return newList[0].lyric
 
     lyric = property(_getLyric, _setLyric, doc='''
-        sets each element on the Verticality to have the passed in lyric
+        sets each object on the Verticality to have the passed in lyric
 
-        >>> h = voiceLeading.Verticality({1:note.Note('C'), 2:harmony.ChordSymbol('C')})
+        >>> h = voiceLeading.Verticality({1: note.Note('C'), 2: harmony.ChordSymbol('C')})
         >>> h.lyric = 'Verticality 1'
-        >>> h.getStream().flat.getElementsByClass(note.Note)[0].lyric
+        >>> h.getStream().flat.getElementsByClass(note.Note).first().lyric
         'Verticality 1'
         ''')
 
diff --git a/music21/volume.py b/music21/volume.py
index 2839b55fd..66e4afdbb 100644
--- a/music21/volume.py
+++ b/music21/volume.py
@@ -675,7 +675,8 @@ class Test(unittest.TestCase):
                 oTarget = j * durUnit
                 # placing dynamics in Measure requires extra handling
                 m = p.getElementsByOffset(oTarget,
-                                          mustBeginInSpan=False).getElementsByClass('Measure')[0]
+                                          mustBeginInSpan=False,
+                                          ).getElementsByClass('Measure').first()
                 oInsert = oTarget - m.getOffsetBySite(p)
                 m.insert(oInsert, dynamics.Dynamic(d))
             # shift 2 places each time


Test patch:
diff --git a/music21/braille/test.py b/music21/braille/test.py
index 7526f05fb..258825c33 100644
--- a/music21/braille/test.py
+++ b/music21/braille/test.py
@@ -1234,7 +1234,7 @@ class Test(unittest.TestCase):
             "tinynotation: 4/4 a2 g8 f8 e4 d4 e4 f8 g8 a4 g4 c'8 b8 a4 g4 f4. e8 d2 "
             "c4 e4 a4 e'4 e'4 d'4 c'8 b8 a4 a'4 g'8 f'8 e'4 d'4 c'4 a8 b8 c'2",
             makeNotation=False)
-        bm.replace(bm.getElementsByClass('TimeSignature')[0], meter.TimeSignature('c'))
+        bm.replace(bm.getElementsByClass('TimeSignature').first(), meter.TimeSignature('c'))
         bm.insert(0, tempo.TempoText('Andante maestoso'))
         bm.insert(0, tempo.MetronomeMark(number=92, referent=note.Note(type='quarter')))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
@@ -1306,7 +1306,7 @@ class Test(unittest.TestCase):
                              "a2 d'4 c'4 b-4 a4 b-4 c'4 d'2 e'-4 f'4 "
                              "g'2 e'-4 c'4 f'2 d'4 b-4 e'-2 c'4 f4 d'2 b-4 b-4 c'2 "
                              "b-4 c'4 d'4 b-4 c'4 d'4 b-4 c'4 b-4 a4 b-2", makeNotation=False)
-        bm.replace(bm.getElementsByClass('TimeSignature')[0], meter.TimeSignature('cut'))
+        bm.replace(bm.getElementsByClass('TimeSignature').first(), meter.TimeSignature('cut'))
         bm.insert(0, key.KeySignature(-2))
         bm.insert(0, tempo.TempoText('Ben marcato'))
         bm.insert(0, tempo.MetronomeMark(number=112, referent=note.Note(type='half')))
@@ -1543,7 +1543,7 @@ class Test(unittest.TestCase):
                              "e'4~ e'8 f' e' b c' d' a b c' g a2~ a8 f "
                              "g c' b a d' c' b e' d'2~ d'8 g' f' c' d' e' b c' d'4 a8 g a2.~ a8 r",
                              makeNotation=False)
-        bm.replace(bm.getElementsByClass('TimeSignature')[0], meter.TimeSignature('c'))
+        bm.replace(bm.getElementsByClass('TimeSignature').first(), meter.TimeSignature('c'))
 
         bm.insert(0, tempo.TempoText('Adagio e molto legato'))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
@@ -1998,7 +1998,7 @@ class Test(unittest.TestCase):
         bm.insert(0, tempo.TempoText('Con brio'))
         bm.insert(25.0, clef.TrebleClef())
         bm.insert(32.0, clef.BassClef())
-        bm.recurse().getElementsByClass('TimeSignature')[0].symbol = 'common'
+        bm.recurse().getElementsByClass('TimeSignature').first().symbol = 'common'
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
         m = bm.getElementsByClass('Measure')
         m[0].padAsAnacrusis(useInitialRests=True)
@@ -2311,8 +2311,8 @@ Barline final ⠣⠅
         bm = converter.parse("tinynotation: 3/4 f'2.~ f'8 c' d' c' b- a").flat
         bm.insert(0, key.KeySignature(-1))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        ml = bm.getElementsByClass('Measure')[-1]
-        ml.append(spanner.Slur(ml.notes[0], ml.notes[-1]))
+        ml = bm.getElementsByClass('Measure').last()
+        ml.append(spanner.Slur(ml.notes.first(), ml.notes.last()))
         ml.rightBarline = None
         import copy
         bmm = copy.deepcopy(bm)
@@ -2701,9 +2701,9 @@ Barline final ⠣⠅
         m1 = bm.getElementsByClass('Measure')[1]
         m2 = bm.getElementsByClass('Measure')[2]
         m3 = bm.getElementsByClass('Measure')[3]
-        mLast = bm.getElementsByClass('Measure')[-1]
+        mLast = bm.getElementsByClass('Measure').last()
 
-        m0.append(spanner.Slur(m0.notes[0], m0.notes[-1]))
+        m0.append(spanner.Slur(m0.notes.first(), m0.notes.last()))
         m0.notes[0].articulations.append(articulations.Accent())
         m1.notes[0].articulations.append(articulations.Staccato())
         m1.notes[1].articulations.append(articulations.Staccato())
@@ -2722,15 +2722,17 @@ Barline final ⠣⠅
 
     def test_example14_5(self):
         bm = converter.parse("tinynotation: 2/2 D8 r F r A r d r B-2 A4 r", makeNotation=False)
-        bm.getElementsByClass('TimeSignature')[0].symbol = 'cut'
+        bm.getElementsByClass('TimeSignature').first().symbol = 'cut'
         bm.insert(0, key.KeySignature(-1))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        m0 = bm.getElementsByClass('Measure')[0]
+        m0 = bm.getElementsByClass('Measure').first()
         m0.notes[0].articulations.append(articulations.Staccato())
         m0.notes[1].articulations.append(articulations.Staccato())
         m0.notes[2].articulations.append(articulations.Staccato())
         m0.notes[3].articulations.append(articulations.Staccato())
-        bm.getElementsByClass('Measure')[1].notes[0].articulations.append(articulations.Accent())
+        bm.getElementsByClass('Measure')[1].notes.first().articulations.append(
+            articulations.Accent()
+        )
         bm.getElementsByClass('Measure')[-1].rightBarline = None
         self.methodArgs = {'showFirstMeasureNumber': False}
         self.s = bm
@@ -2796,10 +2798,10 @@ Barline final ⠣⠅
     def test_example14_7(self):
         bm = converter.parse('tinynotation: 3/4 C4 E F').flat
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        for n in bm.getElementsByClass('Measure')[0].notes:
+        for n in bm.getElementsByClass('Measure').first().notes:
             n.articulations.append(articulations.Accent())
             n.articulations.append(articulations.Staccato())
-        bm.getElementsByClass('Measure')[0].rightBarline = None
+        bm.getElementsByClass('Measure').first().rightBarline = None
         self.methodArgs = {'showFirstMeasureNumber': False}
         self.s = bm
         self.b = '''
@@ -2810,11 +2812,11 @@ Barline final ⠣⠅
     def test_example14_8(self):
         bm = converter.parse('tinynotation: 3/4 G4 B c').flat
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        for n in bm.getElementsByClass('Measure')[0].notes:
+        for n in bm.getElementsByClass('Measure').first().notes:
             # pass
             n.articulations.append(articulations.Tenuto())
             n.articulations.append(articulations.Accent())
-        bm.getElementsByClass('Measure')[0].rightBarline = None
+        bm.getElementsByClass('Measure').first().rightBarline = None
         self.methodArgs = {'showFirstMeasureNumber': False}
         self.s = bm
         self.b = '''
@@ -2863,10 +2865,10 @@ Barline final ⠣⠅
                              makeNotation=False)
         bm.insert(0, key.KeySignature(1))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        bm.getElementsByClass('Measure')[0].padAsAnacrusis(useInitialRests=True)
+        bm.getElementsByClass('Measure').first().padAsAnacrusis(useInitialRests=True)
         for m in bm.getElementsByClass('Measure'):
             m.number -= 1
-        bm.getElementsByClass('Measure')[-1].rightBarline = None
+        bm.getElementsByClass('Measure').last().rightBarline = None
         self.s = bm
         self.b = '''
         ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠩⠼⠃⠲⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
@@ -2919,12 +2921,12 @@ Barline final ⠣⠅
                              "b8. c'#8 e'8. d'16 c'#16 b16 a4").flat
         bm.insert(0, key.KeySignature(3))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        bm.getElementsByClass('Measure')[0].padAsAnacrusis(useInitialRests=True)
+        bm.getElementsByClass('Measure').first().padAsAnacrusis(useInitialRests=True)
         # bm.getElementsByClass('Measure')[3][1].pitch.accidental.displayStatus = False
         # remove cautionary accidental display
         for m in bm:
             m.number -= 1
-        bm.getElementsByClass('Measure')[-1].rightBarline = bar.Barline('double')
+        bm.getElementsByClass('Measure').last().rightBarline = bar.Barline('double')
         self.s = bm
         self.b = '''
         ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠩⠩⠩⠼⠉⠦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
@@ -3010,11 +3012,11 @@ Barline final ⠣⠅
         bm = converter.parse("tinynotation: 12/8 r1 r4 r8 b-8 e-16 e'- g- g'- b- b'- bn b'n "
                              "b- b'- bn b'n b- b'- a'- f' d' b- e'-4.").flat
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        lastMeasure = bm.getElementsByClass('Measure')[-1]
+        lastMeasure = bm.getElementsByClass('Measure').last()
         lastMeasure.rightBarline = None
         for m in bm.getElementsByClass('Measure'):
             m.number -= 1
-        m0 = bm.getElementsByClass('Measure')[0]
+        m0 = bm.getElementsByClass('Measure').first()
         for i in range(3):
             m0.pop(2)
         lastMeasure.notes[7].pitch.accidental = pitch.Accidental('natural')
@@ -3035,8 +3037,9 @@ Barline final ⠣⠅
         bm = converter.parse("tinynotation: 2/4 trip{c8 e a} g4 trip{B8 d a} g4").flat
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
         bm.getElementsByClass('Measure')[-1].rightBarline = None
-        bm.getElementsByClass('Measure')[0].notes[0].articulations.append(articulations.Accent())
-        bm.getElementsByClass('Measure')[1].notes[0].articulations.append(articulations.Accent())
+        for i in (0, 1):
+            m = bm.getElementsByClass('Measure')[i]
+            m.notes.first().articulations.append(articulations.Accent())
         self.methodArgs = {'showFirstMeasureNumber': False}
         self.s = bm
         self.b = '''
@@ -3062,10 +3065,10 @@ Barline final ⠣⠅
                              "trip{b- c' b-} e-4").flat
         bm.insert(0, key.KeySignature(-4))
         bm.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        m0 = bm.getElementsByClass('Measure')[0]
+        m0 = bm.getElementsByClass('Measure').first()
         m0.insert(0.0, dynamics.Dynamic('p'))
         m0.insert(0.0, expressions.TextExpression('legato'))
-        m0.append(spanner.Slur(m0.notes[0], m0.notes[-1]))
+        m0.append(spanner.Slur(m0.notes.first(), m0.notes.last()))
         bm.getElementsByClass('Measure')[-1].rightBarline = None
         self.methodArgs = {'showFirstMeasureNumber': False}
         self.s = bm
@@ -3183,7 +3186,7 @@ Barline final ⠣⠅
         self.method = measureToBraille
         rightHand = converter.parse('tinynotation: 4/4 c2 e2').flat
         rightHand.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
-        m = rightHand.getElementsByClass('Measure')[0]
+        m = rightHand.getElementsByClass('Measure').first()
         m.rightBarline = None
         m.insert(0.0, dynamics.Dynamic('f'))
         self.methodArgs = {'showHand': 'right', 'showHeading': True}
@@ -3198,7 +3201,7 @@ Barline final ⠣⠅
         leftHand = converter.parse('tinynotation: 2/4 C8 r8 E8 r8').flat
         leftHand.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False)
 
-        m = leftHand.getElementsByClass('Measure')[0]
+        m = leftHand.getElementsByClass('Measure').first()
         m.rightBarline = None
         self.methodArgs = {'showHand': 'left', 'showHeading': True}
         self.s = m
diff --git a/music21/test/testStream.py b/music21/test/testStream.py
index f358fc7ad..250aedfd1 100644
--- a/music21/test/testStream.py
+++ b/music21/test/testStream.py
@@ -1322,8 +1322,8 @@ class Test(unittest.TestCase):
         b = a.parts[3].measures(4, 6)
         self.assertEqual(len(b.getElementsByClass('Measure')), 3)
         # b.show('t')
-        # first measure now has keu sig
-        unused_bMeasureFirst = b.getElementsByClass('Measure')[0]
+        # first measure now has key sig
+        unused_bMeasureFirst = b.getElementsByClass('Measure').first()
 
         self.assertEqual(len(b.flat.getElementsByClass(
             key.KeySignature)), 1)
@@ -1975,7 +1975,7 @@ class Test(unittest.TestCase):
         # default is no normal barlines, but a final barline
         barred1 = s.makeMeasures()
         self.assertEqual(
-            str(barred1.getElementsByClass('Measure')[-1].rightBarline),
+            str(barred1.getElementsByClass('Measure').last().rightBarline),
             '<music21.bar.Barline type=final>')
         # barred1.show()
 
@@ -2080,9 +2080,9 @@ class Test(unittest.TestCase):
     def testReplaceA1(self):
         from music21 import corpus
         sBach = corpus.parse('bach/bwv324.xml')
-        partSoprano = sBach.parts[0]
+        partSoprano = sBach.parts.first()
 
-        c1 = partSoprano.flat.getElementsByClass('Clef')[0]
+        c1 = partSoprano.flat.getElementsByClass('Clef').first()
         self.assertIsInstance(c1, clef.TrebleClef)
 
         # now, replace with a different clef
@@ -2090,7 +2090,7 @@ class Test(unittest.TestCase):
         partSoprano.flat.replace(c1, c2, allDerived=True)
 
         # all views of the Stream have been updated
-        cTest = sBach.parts[0].flat.getElementsByClass('Clef')[0]
+        cTest = sBach.parts.first().flat.getElementsByClass('Clef').first()
         self.assertIsInstance(cTest, clef.AltoClef)
 
     def testReplaceB(self):
@@ -2133,7 +2133,7 @@ class Test(unittest.TestCase):
         dc = list(qj_flat.derivation.chain())
         self.assertIs(dc[0], qj)
 
-        k1 = qj_flat.getElementsByClass(key.KeySignature)[0]
+        k1 = qj_flat.getElementsByClass(key.KeySignature).first()
         self.assertEqual(k1.sharps, -1)
         k3flats = key.KeySignature(-3)
 
@@ -2144,11 +2144,11 @@ class Test(unittest.TestCase):
         # here's the big one
         qj_flat.replace(k1, k3flats, allDerived=True)
 
-        kWhich = qj_flat.getElementsByClass(key.KeySignature)[0]
+        kWhich = qj_flat.getElementsByClass(key.KeySignature).first()
         self.assertIs(kWhich, k3flats)
         self.assertEqual(kWhich.sharps, -3)
 
-        kWhich2 = qj.recurse().getElementsByClass(key.KeySignature)[0]
+        kWhich2 = qj.recurse().getElementsByClass(key.KeySignature).first()
         self.assertIs(kWhich2, k3flats)
         self.assertEqual(kWhich2.sharps, -3)
 
@@ -4011,7 +4011,7 @@ class Test(unittest.TestCase):
             s.insert(0, p)
 
         # create measures in the first part
-        s.getElementsByClass('Stream')[0].makeNotation(
+        s.getElementsByClass('Stream').first().makeNotation(
             inPlace=True,
             meterStream=stream.Stream([meter.TimeSignature('3/4')]))
 
@@ -4047,7 +4047,7 @@ class Test(unittest.TestCase):
         sPost = s.makeNotation()
 
         self.assertEqual(len(sPost.getElementsByClass('Measure')), 1)
-        m1 = sPost.getElementsByClass('Measure')[0]
+        m1 = sPost.getElementsByClass('Measure').first()
         self.assertEqual(m1.keySignature.sharps, sharpsInKey)
 
     def testMakeNotationKeySignatureMultiVoice(self):
@@ -4071,12 +4071,8 @@ class Test(unittest.TestCase):
 
         sPost = s.makeNotation()
 
-        # self.assertTrue(post.hasPartLikeStreams())
-        # print("sPost.getElementsByClass('Measure')", sPost.getElementsByClass('Measure'))
         self.assertEqual(len(sPost.getElementsByClass('Measure')), 1)
-        m1 = sPost.getElementsByClass('Measure')[0]
-        # print("sPost.getElementsByClass('Measure')[0]", m1)
-        # print('m1.keySignature',m1.keySignature.sharps)
+        m1 = sPost.getElementsByClass('Measure').first()
         assert(m1.keySignature is not None)
         self.assertEqual(m1.keySignature.sharps, sharpsInKey)
 
@@ -5126,7 +5122,7 @@ class Test(unittest.TestCase):
         s.insert(0, p2)
         post = s.chordify()
         self.assertEqual(len(post.getElementsByClass('Chord')), 12)
-        self.assertEqual(str(post.getElementsByClass('Chord')[0].pitches),
+        self.assertEqual(str(post.getElementsByClass('Chord').first().pitches),
                          '(<music21.pitch.Pitch C4>, <music21.pitch.Pitch G4>)')
 
         p1 = stream.Part()
@@ -5142,7 +5138,7 @@ class Test(unittest.TestCase):
         s.insert(0, p2)
         post = s.chordify()
         self.assertEqual(len(post.getElementsByClass('Chord')), 2)
-        self.assertEqual(str(post.getElementsByClass('Chord')[0].pitches),
+        self.assertEqual(str(post.getElementsByClass('Chord').first().pitches),
                          '(<music21.pitch.Pitch C4>, <music21.pitch.Pitch G4>)')
         # post.show()
 
@@ -5177,7 +5173,7 @@ class Test(unittest.TestCase):
         # s.show()
         post = s.chordify()
         self.assertEqual(len(post.getElementsByClass('Measure')), 2)
-        m1 = post.getElementsByClass('Measure')[0]
+        m1 = post.getElementsByClass('Measure').first()
         # test that padding has been maintained
         self.assertEqual(m1.paddingLeft, 3.0)
         # post.show()
@@ -5189,7 +5185,7 @@ class Test(unittest.TestCase):
         from music21 import corpus
         s = corpus.parse('schoenberg/opus19/movement6')
         # s.show('text')
-        m1 = s.parts[0].getElementsByClass('Measure')[0]
+        m1 = s.parts.first().getElementsByClass('Measure').first()
         # m1.show('text')
 
         self.assertEqual(m1.highestTime, 1.0)
@@ -5199,7 +5195,7 @@ class Test(unittest.TestCase):
         # s.parts[0].show()
         post = s.chordify()
         # pst.show('text', addEndTimes=True)
-        self.assertEqual(post.getElementsByClass('Measure')[0].paddingLeft, 3.0)
+        self.assertEqual(post.getElementsByClass('Measure').first().paddingLeft, 3.0)
         # self.assertEqual(len(post.flat), 3)
         # post.show()
 
@@ -5508,7 +5504,7 @@ class Test(unittest.TestCase):
 
         for p in s1.parts:
             # need to look in measures to get at voices
-            self.assertEqual(len(p.getElementsByClass('Measure')[0].voices), 2)
+            self.assertEqual(len(p.getElementsByClass('Measure').first().voices), 2)
             self.assertEqual(len(p.measure(2).voices), 2)
             self.assertEqual(len(p.measures(
                 1, 3).getElementsByClass('Measure')[2].voices), 2)
@@ -5810,12 +5806,13 @@ class Test(unittest.TestCase):
         self.assertEqual([n.quarterLength for n in s3.flat.notesAndRests],
                          [1.0, 2.0, 2.0, 2.0, 1.0])
 
-        self.assertEqual([n.offset for n in s3.getElementsByClass('Measure')[0].notesAndRests],
+        first_m_notesAndRests = s3.getElementsByClass('Measure').first().notesAndRests
+        self.assertEqual([n.offset for n in first_m_notesAndRests],
                          [0.0, 1.0, 3.0])
         self.assertEqual([n.quarterLength
-                            for n in s3.getElementsByClass('Measure')[0].notesAndRests],
+                            for n in first_m_notesAndRests],
                          [1.0, 2.0, 2.0])
-        self.assertEqual([n.beatStr for n in s3.getElementsByClass('Measure')[0].notesAndRests],
+        self.assertEqual([n.beatStr for n in first_m_notesAndRests],
                          ['1', '2', '4'])
 
         self.assertEqual(
@@ -6041,7 +6038,7 @@ class Test(unittest.TestCase):
 
         # try imported
         s = corpus.parse('bwv66.6')
-        p = s.iter.getElementsByClass('Part')[0]  # for test, not .parts
+        p = s.iter.getElementsByClass('Part').first()  # for test, not .parts, use .iter
         m = p.iter.getElementsByClass('Measure')[2]  # for test, not .getElementsByClass('Measure')
         rn = m[2]
 
@@ -6329,11 +6326,11 @@ class Test(unittest.TestCase):
 
     def testFlatCachingC(self):
         from music21 import corpus, stream
-        qj = corpus.parse('ciconia/quod_jactatur').parts[0]
+        qj = corpus.parse('ciconia/quod_jactatur').parts.first()
         unused_idFlat1 = id(qj.flat)
         # environLocal.printDebug(['idFlat1', idFlat1])
 
-        k1 = qj.flat.getElementsByClass(key.KeySignature)[0]
+        k1 = qj.flat.getElementsByClass(key.KeySignature).first()
         qj.flat.replace(k1, key.KeySignature(-3))
 
         unused_idFlat2 = id(qj.flat)