f | import string | f | import string |
| | | |
| class Pairs: | | class Pairs: |
| __slots__ = ('_offset',) | | __slots__ = ('_offset',) |
| | | |
| def __init__(self, N): | | def __init__(self, N): |
| if not 1 <= N <= 26: | | if not 1 <= N <= 26: |
| raise ValueError('N must be between 1 and 26 inclusive.') | | raise ValueError('N must be between 1 and 26 inclusive.') |
| self._offset = N - 1 | | self._offset = N - 1 |
| | | |
| def __getattr__(self, name): | | def __getattr__(self, name): |
| if name in string.ascii_lowercase: | | if name in string.ascii_lowercase: |
| index = string.ascii_lowercase.index(name) | | index = string.ascii_lowercase.index(name) |
| elif name in string.ascii_uppercase: | | elif name in string.ascii_uppercase: |
| index = 26 + string.ascii_uppercase.index(name) | | index = 26 + string.ascii_uppercase.index(name) |
| else: | | else: |
| raise AttributeError(f"'{type(self).__name__}' object has no | | raise AttributeError(f"'{type(self).__name__}' object has no |
| attribute '{name}'") | | attribute '{name}'") |
| return (self._offset + index) % 52 + 1 | | return (self._offset + index) % 52 + 1 |
| | | |
| def __setattr__(self, name, value): | | def __setattr__(self, name, value): |
| if name == '_offset': | | if name == '_offset': |
t | super().__setattr__(name, value) | t | object.__setattr__(self, name, value) |
| else: | | else: |
| raise AttributeError(f"Cannot set attribute '{name}' directl | | raise AttributeError(f"Cannot set attribute '{name}' directl |
| y") | | y") |
| | | |
| def __str__(self): | | def __str__(self): |
| sorted_fields = sorted(string.ascii_lowercase + string.ascii_upp | | sorted_fields = sorted(string.ascii_lowercase + string.ascii_upp |
| ercase, key=lambda x: (self.__getattr__(x), x)) | | ercase, key=lambda x: (self.__getattr__(x), x)) |
| return ' '.join(sorted_fields) | | return ' '.join(sorted_fields) |