Replace handrolled cached property with the built-in

This commit is contained in:
Jonathan Harker 2024-10-02 09:35:19 +13:00
parent 6c42477d7a
commit 42d4cfb427

View file

@ -1,23 +1,9 @@
#!/usr/bin/env python3
from __future__ import annotations
from functools import cached_property
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):
"""
Musical set class, containing zero or more pitch classes.
@ -64,7 +50,7 @@ class SetClass(list):
def pitch_classes(self) -> list(int):
return list(self)
@cache_property
@cached_property
def tonality(self) -> int:
"""
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
@cache_property
@cached_property
def cardinality(self) -> int:
"""Returns the cardinality of the set class, i.e. the number of pitch classes."""
return len(self.pitch_classes)
@cache_property
@cached_property
def brightness(self) -> int:
"""Returns the brightness of the set class, defined as the sum of the pitch class values."""
return sum(self.pitch_classes)
@cache_property
@cached_property
def decimal(self) -> int:
"""
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])
@cache_property
@cached_property
def adjacency_intervals(self) -> list(int):
"""Adjacency intervals between the pitch classes, used for Leonard notation subscripts."""
if not self.pitch_classes:
@ -106,7 +92,7 @@ class SetClass(list):
intervals.append(self.tonality - prev)
return intervals
@cache_property
@cached_property
def z_relations(self) -> list:
"""
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]
@cache_property
@cached_property
def interval_vector(self) -> list:
"""
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))
@cache_property
@cached_property
def versions(self) -> list(SetClass):
"""
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)
return versions
@cache_property
@cached_property
def rahn_normal_form(self) -> SetClass:
"""
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
return versions[0]
@cache_property
@cached_property
def packed_left(self) -> SetClass:
"""
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
return versions[0]
@cache_property
@cached_property
def prime_form(self) -> SetClass:
"""
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
return versions[0]
@cache_property
@cached_property
def darkest_form(self) -> SetClass:
"""
Returns the version with the smallest brightness value, most packed to the left.
@ -244,7 +230,7 @@ class SetClass(list):
n += 1
return versions[0]
@cache_property
@cached_property
def brightest_form(self) -> SetClass:
"""
Returns the version with the largest brightness value.
@ -252,7 +238,7 @@ class SetClass(list):
"""
return self.versions[-1] if self.versions else self
@cache_property
@cached_property
def inversion(self) -> SetClass:
"""
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)
@cache_property
@cached_property
def is_symmetrical(self) -> bool:
"""
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
@cache_property
@cached_property
def complement(self) -> SetClass:
"""
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)
@cache_property
@cached_property
def dozenal_notation(self) -> str:
"""
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', '')
@cache_property
@cached_property
def duodecimal_notation(self) -> str:
"""
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')
@cache_property
@cached_property
def leonard_notation(self) -> str:
"""
Returns a string representation of this set class using subscripts to denote the adjacency