Replace handrolled cached property with the built-in
This commit is contained in:
parent
6c42477d7a
commit
42d4cfb427
1 changed files with 20 additions and 34 deletions
|
|
@ -1,23 +1,9 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
from functools import cached_property
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
class cache_property:
|
|
||||||
"""
|
|
||||||
Property that only computes its value once when first accessed, and caches the result.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, function):
|
|
||||||
self.function = function
|
|
||||||
self.name = function.__name__
|
|
||||||
self.__doc__ = function.__doc__
|
|
||||||
|
|
||||||
def __get__(self, obj, type=None) -> object:
|
|
||||||
obj.__dict__[self.name] = self.function(obj)
|
|
||||||
return obj.__dict__[self.name]
|
|
||||||
|
|
||||||
|
|
||||||
class SetClass(list):
|
class SetClass(list):
|
||||||
"""
|
"""
|
||||||
Musical set class, containing zero or more pitch classes.
|
Musical set class, containing zero or more pitch classes.
|
||||||
|
|
@ -64,7 +50,7 @@ class SetClass(list):
|
||||||
def pitch_classes(self) -> list(int):
|
def pitch_classes(self) -> list(int):
|
||||||
return list(self)
|
return list(self)
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def tonality(self) -> int:
|
def tonality(self) -> int:
|
||||||
"""
|
"""
|
||||||
Returns the number of (equal) divisions of the octave. The default value is 12, which
|
Returns the number of (equal) divisions of the octave. The default value is 12, which
|
||||||
|
|
@ -72,17 +58,17 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return self._tonality
|
return self._tonality
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def cardinality(self) -> int:
|
def cardinality(self) -> int:
|
||||||
"""Returns the cardinality of the set class, i.e. the number of pitch classes."""
|
"""Returns the cardinality of the set class, i.e. the number of pitch classes."""
|
||||||
return len(self.pitch_classes)
|
return len(self.pitch_classes)
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def brightness(self) -> int:
|
def brightness(self) -> int:
|
||||||
"""Returns the brightness of the set class, defined as the sum of the pitch class values."""
|
"""Returns the brightness of the set class, defined as the sum of the pitch class values."""
|
||||||
return sum(self.pitch_classes)
|
return sum(self.pitch_classes)
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def decimal(self) -> int:
|
def decimal(self) -> int:
|
||||||
"""
|
"""
|
||||||
Returns the decimal value of the pitch classes expressed as a binary bit mask, i.e. the sum
|
Returns the decimal value of the pitch classes expressed as a binary bit mask, i.e. the sum
|
||||||
|
|
@ -92,7 +78,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return sum([2**i for i in self.pitch_classes])
|
return sum([2**i for i in self.pitch_classes])
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def adjacency_intervals(self) -> list(int):
|
def adjacency_intervals(self) -> list(int):
|
||||||
"""Adjacency intervals between the pitch classes, used for Leonard notation subscripts."""
|
"""Adjacency intervals between the pitch classes, used for Leonard notation subscripts."""
|
||||||
if not self.pitch_classes:
|
if not self.pitch_classes:
|
||||||
|
|
@ -106,7 +92,7 @@ class SetClass(list):
|
||||||
intervals.append(self.tonality - prev)
|
intervals.append(self.tonality - prev)
|
||||||
return intervals
|
return intervals
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def z_relations(self) -> list:
|
def z_relations(self) -> list:
|
||||||
"""
|
"""
|
||||||
Return all distinct set classes with the same interval vector (Allen Forte: "Z-related").
|
Return all distinct set classes with the same interval vector (Allen Forte: "Z-related").
|
||||||
|
|
@ -115,7 +101,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return [i for i in SetClass.darkest_of_cardinality(self.cardinality) if i.interval_vector == self.interval_vector]
|
return [i for i in SetClass.darkest_of_cardinality(self.cardinality) if i.interval_vector == self.interval_vector]
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def interval_vector(self) -> list:
|
def interval_vector(self) -> list:
|
||||||
"""
|
"""
|
||||||
An ordered tuple containing the multiplicities of each interval class in the set class.
|
An ordered tuple containing the multiplicities of each interval class in the set class.
|
||||||
|
|
@ -147,7 +133,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return min(SetClass.ordered_interval(a, b), SetClass.ordered_interval(b, a))
|
return min(SetClass.ordered_interval(a, b), SetClass.ordered_interval(b, a))
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def versions(self) -> list(SetClass):
|
def versions(self) -> list(SetClass):
|
||||||
"""
|
"""
|
||||||
Returns all possible zero-normalised versions (clock rotations) of this set class,
|
Returns all possible zero-normalised versions (clock rotations) of this set class,
|
||||||
|
|
@ -165,7 +151,7 @@ class SetClass(list):
|
||||||
versions.sort(key=lambda x: x.brightness)
|
versions.sort(key=lambda x: x.brightness)
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def rahn_normal_form(self) -> SetClass:
|
def rahn_normal_form(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Return the Rahn normal form of the set class; Leonard describes this as "most dispersed from
|
Return the Rahn normal form of the set class; Leonard describes this as "most dispersed from
|
||||||
|
|
@ -182,7 +168,7 @@ class SetClass(list):
|
||||||
n += 1
|
n += 1
|
||||||
return versions[0]
|
return versions[0]
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def packed_left(self) -> SetClass:
|
def packed_left(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Return the form of the set class that is most packed to the left (smallest adjacency
|
Return the form of the set class that is most packed to the left (smallest adjacency
|
||||||
|
|
@ -199,7 +185,7 @@ class SetClass(list):
|
||||||
n += 1
|
n += 1
|
||||||
return versions[0]
|
return versions[0]
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def prime_form(self) -> SetClass:
|
def prime_form(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Return the prime form of the set class. Find the forms with the smallest outside interval,
|
Return the prime form of the set class. Find the forms with the smallest outside interval,
|
||||||
|
|
@ -222,7 +208,7 @@ class SetClass(list):
|
||||||
n += 1
|
n += 1
|
||||||
return versions[0]
|
return versions[0]
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def darkest_form(self) -> SetClass:
|
def darkest_form(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Returns the version with the smallest brightness value, most packed to the left.
|
Returns the version with the smallest brightness value, most packed to the left.
|
||||||
|
|
@ -244,7 +230,7 @@ class SetClass(list):
|
||||||
n += 1
|
n += 1
|
||||||
return versions[0]
|
return versions[0]
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def brightest_form(self) -> SetClass:
|
def brightest_form(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Returns the version with the largest brightness value.
|
Returns the version with the largest brightness value.
|
||||||
|
|
@ -252,7 +238,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return self.versions[-1] if self.versions else self
|
return self.versions[-1] if self.versions else self
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def inversion(self) -> SetClass:
|
def inversion(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Returns the inversion of this set class, equivalent of reflection through the 0 axis on a
|
Returns the inversion of this set class, equivalent of reflection through the 0 axis on a
|
||||||
|
|
@ -260,7 +246,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return SetClass(*[self.tonality - i for i in self.pitch_classes], tonality=self.tonality)
|
return SetClass(*[self.tonality - i for i in self.pitch_classes], tonality=self.tonality)
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def is_symmetrical(self) -> bool:
|
def is_symmetrical(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Returns whether this set class is symmetrical upon inversion, for example Forte 5-Z17:
|
Returns whether this set class is symmetrical upon inversion, for example Forte 5-Z17:
|
||||||
|
|
@ -268,7 +254,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return self.darkest_form == self.inversion.darkest_form
|
return self.darkest_form == self.inversion.darkest_form
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def complement(self) -> SetClass:
|
def complement(self) -> SetClass:
|
||||||
"""
|
"""
|
||||||
Returns the set class containing all pitch classes absent in this one (rotated so the
|
Returns the set class containing all pitch classes absent in this one (rotated so the
|
||||||
|
|
@ -276,7 +262,7 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return SetClass(*[i for i in range(self.tonality) if i not in self.pitch_classes], tonality=self.tonality)
|
return SetClass(*[i for i in range(self.tonality) if i not in self.pitch_classes], tonality=self.tonality)
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def dozenal_notation(self) -> str:
|
def dozenal_notation(self) -> str:
|
||||||
"""
|
"""
|
||||||
If tonality is no greater than 12, return a string representation using Dozenal Society
|
If tonality is no greater than 12, return a string representation using Dozenal Society
|
||||||
|
|
@ -284,14 +270,14 @@ class SetClass(list):
|
||||||
"""
|
"""
|
||||||
return f"{self}" if self.tonality > 12 else f"{self}".replace('10', '↊').replace('11', '↋')
|
return f"{self}" if self.tonality > 12 else f"{self}".replace('10', '↊').replace('11', '↋')
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def duodecimal_notation(self) -> str:
|
def duodecimal_notation(self) -> str:
|
||||||
"""
|
"""
|
||||||
If tonality is no greater than 12, replace 10 and 11 with 'T' and 'E'.
|
If tonality is no greater than 12, replace 10 and 11 with 'T' and 'E'.
|
||||||
"""
|
"""
|
||||||
return f"{self}" if self.tonality > 12 else f"{self}".replace('10', 'T').replace('11', 'E')
|
return f"{self}" if self.tonality > 12 else f"{self}".replace('10', 'T').replace('11', 'E')
|
||||||
|
|
||||||
@cache_property
|
@cached_property
|
||||||
def leonard_notation(self) -> str:
|
def leonard_notation(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns a string representation of this set class using subscripts to denote the adjacency
|
Returns a string representation of this set class using subscripts to denote the adjacency
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue