1(調 := ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')), (音程 := ('unison', 'minor 2nd', 'major 2nd', 'minor 3rd', 'major 3rd', 'perfect 4th', 'diminished 5th', 'perfect 5th', 'minor 6th', 'major 6th', 'minor 7th', 'major 7th')), (胤 := isinstance), (Tone := type('Tone', (), {'__init__': lambda _, t: setattr(_, 'i', 調.index(t)), '__str__': lambda _: 調[_.i], '__add__': lambda _, o: Chord(_, o) if 胤(o, Tone) else ti(_.i + o.i) if 胤(o, Interval) else NotImplemented, '__radd__': lambda _, o: o + _ if 胤(o, Chord) else exec('raise TypeError(\'Invalid operation\')'), '__sub__': lambda _, o: Interval(_.i - o.i) if 胤(o, Tone) else ti(_.i - o.i) if 胤(o, Interval) else NotImplemented, '__rsub__': lambda _, o: exec('raise TypeError(\'Invalid operation\')')})), (ti := lambda i: Tone(調[i % len(調)])), (Interval := type('Interval', (), {'__init__': lambda _, i, d=1: (setattr(_, 'i', i % len(音程)), setattr(_, 'd', d))[1], '__str__': lambda _: 音程[_.i], '__add__': lambda _, o: Interval(_.i + o.i) if 胤(o, Interval) else NotImplemented, '__neg__': lambda _: Interval(_.i, -_.d), 'f': lambda _: _.i * _.d})), (Ci := type('Ci', (), {'__init__': lambda _, s, t: (setattr(_, 'i', 0), setattr(_, 't', list(map(lambda x: ti(x[0] + s), filter(lambda x: x[1], enumerate(t[s:] + t[:s]))))))[0], '__next__': lambda _: exec('raise StopIteration') if _.i == len(_.t) else _.t[(_.i, setattr(_, 'i', _.i + 1))[0]]})), (Chord := type('Chord', (), {'__init__': lambda _, b, *t: exec('raise TypeError(\'Cannot have a chord made of only 1 unique tone\')') if len({b.i} | set(t_.i for t_ in t)) < 2 else (setattr(_, 'b', b.i), setattr(_, 't', [i in {b.i} | set(t_.i for t_ in t) for i in range(len(調))]))[0], '__iter__': lambda _: Ci(_.b, _.t), '__str__': lambda _: '-'.join(str(t) for t in _), 'is_minor': lambda _: _.t[(_.b + 3) % len(調)], 'is_major': lambda _: _.t[(_.b + 4) % len(調)], 'is_power_chord': lambda _: not _.is_minor() and not _.is_major(), '__add__': lambda _, o: (c := _.__copy__(), c.t.__setitem__(o.i, True))[0] if 胤(o, Tone) else (c := _.__copy__(), setattr(c, 't', list(map(any, zip(c.t, o.t)))), c)[2] if 胤(o, Chord) else NotImplemented, '__sub__': lambda _, o: exec(f'raise TypeError(\'Cannot remove tone {o} from chord {_}\')') if not _.t[o.i] else (b := ti(_.b) if o.i != _.b else (i := iter(_), next(i), next(i))[2], tx := _.t.copy(), tx.__setitem__(o.i, False), Chord(b, *list(map(lambda x: ti(x[0]), filter(lambda x: x[1], enumerate(tx))))))[-1], '__copy__': lambda _: (c := Chord(Tone('A'), Tone('A#')), setattr(c, 'b', _.b) or setattr(c, 't', _.t))[0], 'transposed': lambda _, i: (c := _.__copy__(), setattr(c, 'b', c.b + i.f()) or setattr(c, 't', c.t[-i.f():] + c.t[:-i.f()]))[0]}))
...........F.........................
======================================================================
FAIL: test_interval_negative (test.TestBasicIntervalFunctionality.test_interval_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 51, in test_interval_negative
self.assertEqual(str(minor_2nd), "minor 2nd")
AssertionError: 'major 7th' != 'minor 2nd'
- major 7th
+ minor 2nd
----------------------------------------------------------------------
Ran 37 tests in 0.003s
FAILED (failures=1)
Виктор Бечев
07.11.2024 01:03А, да, знаех си, че имаше схема с code обектите - и преди съм го ползвал. :smile:
```
type(lambda: 0)(type((lambda: 0).__code__)(1, 0, 0, 1, 1, 67, b'|\0\202\1', (), (), ('x',), '', '', '', 1, b'', b''), {})(TypeError("String, baby!"))
```
Обяснението на горното е супер добро, утре мога да ви го преразкажа.
Има и по-лесен вариант, но той не е толкова забавен...
```
(lambda: (_ for _ in ()).throw(TypeError('String, baby!')))()
dir((_ for _ in ()))
# [..., 'gi_frame', 'gi_running', 'gi_suspended', 'gi_yieldfrom', 'send', 'throw']
```
Защо генератор експрешъните имат метод `throw`? Fuck if I know. :smile:
П.П. Тъй де, то си пише в документацията, ама защо това е публично...?
|
Виктор Бечев
07.11.2024 00:36Отвратен съм, Жорка. Евалата.
|
Георги Кунчев
06.11.2024 21:29Малко фийдбек, че ми стана интересно.
Да, ясно е, че да `raise`-неш изключение без `exec` е доста трудно начинание, но пък и едноредови решени с `exec` си е компромис. Реших да видя дали мога да се справя с проблема.
За `StopIteration` има лесен вариант. Не знам за какво ти е, но очевидно не те интересува текста, така че... `next(iter([]))`.
За `TypeError` не знам трик. Може би Виктор ще излезе с някакъв екзорсизъм, но това, което аз се сетих, е, че някъде във вградените библиотеки може да има `raise TypeError(value)`, за което да се закача. Т.е. `TypeError`, който сляпо връща подадена стойност, без да я украсява. Свалих сорс кода на Питон, потърсих и [бинго](https://github.com/python/cpython/blob/a1c57bcfd2bcbc55ff858407e09c1d8d8cee44e6/Lib/plistlib.py#L859).
Вярвам, че това можеш да пренапишеш в един ред. Днес работи, утре не, но едва ли утре някой ще ти рънва тестовете пак, така че си струва единия час, който загубих да го търся и сглобя:
```
import plistlib
class Dummy:
def __init__(self, text):
self._text = text
def __str__(self):
return self._text
a = plistlib._BinaryPlistWriter(None, None, None)
a._getrefnum = lambda *_: None
a._object_offsets = {None: None}
a._fp = type('', (), {'tell': lambda: None})
a._write_object(Dummy("Raising a TypeError with custom message without the raise keyword"))
```
|
Георги Кунчев
06.11.2024 20:45Решението е качено след крайния срок, от мен.
Точките се запазват, защото колегата Русалов вече завърши курса.
Тук е, за да покаже защо (не) мразим решенията му.
|