用户指南,第15章:回归基础:Music21Object
到目前为止,我们所使用的几乎所有对象,如Note对象、Chord对象、Stream对象等,都是一个被称为Music21Object的对象的子类,暂且将其称为Music21Object。
Music21Object是可以放入Stream中的对象,它知道自己在Stream中的位置,并具有.duration属性表示持续时间。
当然,并不是Python中的每个对象都是Music21Object对象,但有点令人惊讶的是,并不是music21中的每个对象都是"Music21Object"。例如,Pitch对象就不是Music21Object对象。如果你尝试将Pitch对象放入Stream中,会出现错误:
from music21 import *
p = pitch.Pitch("A-2")
s = stream.Stream()
s.insert(0, p)
输出:
StreamException: The object you tried to add to the Stream, <music21.pitch.Pitch A-2>, is not a Music21Object. Use an ElementWrapper object if this is what you intend.
Duration对象也不是Music21Object对象:
d = duration.Duration('half')
s.insert(0, d)
输出:
StreamException: The object you tried to add to the Stream, <music21.duration.Duration 2.0>, is not a Music21Object. Use an ElementWrapper object if this is what you intend.
为什么我们不将所有对象都设置为Music21Object对象呢?这样做会增加一些开销,如果这样做的话,系统运行速度可能会比现在慢10倍左右。但是,当一个音符基本上是音高和持续时间的组合时,将音高或持续时间放入Stream中是没有意义的。以下方法更好地实现了这一点:
n = note.Note('A-2', type='half')
s.insert(0, n)
s.show('text')
输出:
{0.0} <music21.note.Note A->
我们如何判断Note对象是否是Music21Object对象呢?我们可以阅读文档(Note)中的内容,其中提到:
Note的基类:
- NotRest
- GeneralNote
- Music21Object
或者我们可以使用isinstance(obj, class)操作符来检查给定音符的类。我们要查找的类是base.Music21Object。我们仍然有我们的A♭音符n,所以我们可以这样做:
isinstance(n, base.Music21Object)
输出:
True
请注意,我们需要先有一个Note对象,我们不能测试类本身:
isinstance(note.Note, base.Music21Object)
输出:
False
还有另一种判断对象是否为Music21Object对象的方法,就是检查对象的.classes中是否包含Music21Object:
'Music21Object' in n.classes
输出:
True
但这有点取巧。那些不是Music21Object对象的东西通常没有.classes属性,所以这种方法不适用:
import datetime
dt = datetime.datetime(2015, 9, 27)
'Music21Object' in dt.classes
输出:
AttributeError: 'datetime.datetime' object has no attribute 'classes'
但这是一种检查你知道是Music21Object对象的特定类的简单有效的方法:
'Chord' in n.classes
输出:
False
实际上,这非常有用,我们在music21中的一些对象中也使用了这种方法,这些对象并不是Music21Object对象:
'Duration' in d.classes
输出:
True
对象的类在创建后不能(或者说不应该)更改。因此,可以将其视为完全稳定的。Stream对象有许多方法可以根据类过滤掉Music21Object对象(也称为"元素")。最简单的方法是使用.getElementsByClass:
s