После исследования функции __new__
из MarkM предложенной ссылки , этот подход будет делать то, что я ищу, но я также сомневаюсь, что это правильный подход. См. Следующие разделы обсуждения и решения.
Обсуждение подкласса базовых неизменяемых типов
Однако я также сомневаюсь в необходимости этого, по крайней мере, для простых проверок проверки ввода . При создании подкласса неизменяемого базового класса хорошо то, что вы получаете все преимущества неизменяемости, такие как встроенное хеширование, строковое представление и т. Д. c., Которые просто наследуются напрямую от базового класса. Но вы получите те же преимущества, просто добавив свойство в другой класс, добавив функцию установки и сделав его неизменяемым. и / или дополнительные методы, которые могут применяться ко многим различным классам / модулям, без дополнительной сложности создания отдельного класса, который преобразует их в изменяемые объекты, а затем требует дополнительного уровня доступа к свойствам или методам (т. е. вы делаете "myint "объект из класса" MyInt ", но для доступа к базовому int требуется свойство" value "или что-то подобное, например myint.value
, а не просто myint
).
Решение / Реализация
Так что, возможно, есть лучший способ сделать это, но чтобы ответить на мой собственный вопрос, вот тестовый сценарий, который я написал, чтобы хотя бы заставить это работать.
Обратите внимание, что int может иметь несколько аргументов , при интерпретации строки в специфицированную c базу, например ('1111', 2), который преобразует двоичную строку '1111' в десятичную 15. Базу также можно ввести как kwarg, поэтому требуется передача * args и ** kwargs полностью в функцию int __new__
.
Кроме того, я сначала позвонил в int перед выполнением проверки, чтобы он сначала преобразовал числа с плавающей запятой и строки в int, прежде чем пытаться выполнить проверку.
Обратите внимание, что, поскольку MyInt подклассы int, вы должны вернуть значение типа int - вы не можете вернуть «None» в случае ошибки (хотя вы можете вернуть 0 или -1). Это заставило меня вызвать ValueError и обработать ошибки обратно в основном скрипте.
class MyInt(int):
def __new__(cls, *args, **kwargs):
value = super().__new__(cls, *args, **kwargs)
argstr = ', '.join([str(arg) for arg in args]) # Only for prototype test
print('MyInt({}); Returned {}'.format(argstr, value)) # Only for prototype test
if value < 0 or value > 100:
raise ValueError(' ERROR!! Out of range! Must be 0-100, was {}'.format(value))
return value
if __name__ == '__main__':
myint = MyInt('1111', 2) # Test conversion from binary string, base 2
print('myint = {} (type: {})\n'.format(myint, type(myint)))
for index, arg in enumerate([-99, -0.01, 0, 0.01, 0.5, 0.99, 1.5, 100, 100.1, '101']):
try:
a = MyInt(arg)
except ValueError as ex:
print(ex)
a = None
finally:
print(' a : {} = {}'.format(type(a), a))