Potrzebuję utworzyć obiekt, który podniósłby niestandardowy wyjątek, UnusableObjectError
, gdy jest używany w jakikolwiek sposób (tworzenie go nie powinno jednak powodować wyjątku).Obiekt, który wywołuje wyjątek, gdy jest używany w jakikolwiek sposób
a = UnusableClass() # No error
b = UnusableClass() # No error
a == 4 # Raises UnusableObjectError
'x' in a # Raises UnusableObjectError
for i in a: # Raises UnusableObjectError
print(i)
# ..and so on
wymyśliłem poniższy kod, który wydaje się zachowywać zgodnie z oczekiwaniami.
class UnusableObjectError(Exception):
pass
CLASSES_WITH_MAGIC_METHODS = (str(), object, float(), dict())
# Combines all magic methods I can think of.
MAGIC_METHODS_TO_CHANGE = set()
for i in CLASSES_WITH_MAGIC_METHODS:
MAGIC_METHODS_TO_CHANGE |= set(dir(i))
MAGIC_METHODS_TO_CHANGE.add('__call__')
# __init__ and __new__ must not raise an UnusableObjectError
# otherwise it would raise error even on creation of objects.
MAGIC_METHODS_TO_CHANGE -= {'__class__', '__init__', '__new__'}
def error_func(*args, **kwargs):
"""(nearly) all magic methods will be set to this function."""
raise UnusableObjectError
class UnusableClass(object):
pass
for i in MAGIC_METHODS_TO_CHANGE:
setattr(UnusableClass, i, error_func)
(niektóre ulepszenia dokonane, jak sugeruje Duncan w komentarzach)
pytania:
Czy istnieje już istniejące klasy, która zachowuje się jak opisano?
Jeśli nie, czy jest jakaś usterka w moim UnusableClass()
(np. Sytuacje, w których użycie wystąpień klasy nie spowodowałoby wystąpienia błędu), a jeśli tak, jak mogę naprawić te błędy?
Setting '__' metody na instancji nie generalnie będzie działał zgodnie z oczekiwaniami. Powinieneś zdefiniować je bezpośrednio w klasie. Przedefiniowanie '__getattribute__' w celu zablokowania dostępu do dowolnego atrybutu innego niż te, które chcesz zatwierdzić, prawdopodobnie byłby prostszym sposobem wykonania tego, co próbujesz. – Duncan
Jeden przykład, który nie zadziała tak, jak oczekujesz, spróbuj wywołać instancję: 'a()' daje obiekt 'TypeError: 'UnusableClass' nie można wywołać' ponieważ ustawienie '__call__' na instancji jest ignorowane. Podobnie 'a [1] = 0'. Oczywiście, ponieważ nie zostaną one zaimplementowane, nadal będą zgłaszać błąd, a nie zwyczajny błąd. Definicja klasy może być z 'def' lub po prostu użyj' setattr' na klasie, zamiast na instancji. – Duncan
To także wydaje się być idealnym przypadkiem użycia dla metaclasses ... – thebjorn