#python #reflection
#python #отражение
Вопрос:
Возможно ли получить имя поля рефлексивно в Python (3.2)?
Смотрите следующий пример:
class Something:
def __init__(self):
self.x = 1
def validate():
return validator.max(self.x, 10)
validator.max(self.x, 10)
должно выдать сообщение об ошибке, содержащее имя поля x
в виде строки (в данном случае "x"
).
Ответ №1:
Вам пришлось бы передать имя атрибута в виде строки
def validate():
return validator.max(self, "x", 10)
тогда validator.max может выглядеть следующим образом
def max(ob, attr, max_value):
val = getattr(ob, attr) # val would be self.x now
...
Ответ №2:
Маловероятно. У вещей может даже не быть имен — что такое:
validator.max(3,10)
что предполагается сделать?
Передайте имя, а также значение, если вы хотите, чтобы оно выводилось:
validator.max(self.x,10,"x")
каким бы ни был validator.max, ему нужен другой аргумент, или, если он встроенный, вам нужно его обернуть.
Комментарии:
1. Кроме того, аргументы функции вычисляются перед вызовом функции.
2.
self.x
иx
является своего рода избыточным.
Ответ №3:
В Python выражение self.x
— это просто текущее значение этого элемента, и поэтому информация о том, что значение поступает от объекта, теряется.
Однако вы можете переместить логику проверки на более высокий уровень (базовый класс) и заставить ее работать со всем объектом. При таком подходе «имя» валидатора будет известно функции validate и может использоваться для сообщения об ошибке:
class ValidatedObject:
def validate(self):
for name in dir(self):
if (name.startswith("validate_") and # Is a validator
not getattr(self, name)()): # and failed
raise RuntimeError("%s: %s" %
(name, getattr(self, name).__doc__))
class Something(ValidatedObject):
def __init__(self, x, y):
self.x = x
self.y = y
def validate_x(self):
"Horizontal position shouldn't be that big"
return self.x < 10
def validate_y(self):
"Vertical position must be neither too low nor too high"
return 20 <= self.y <= 30
def validate_sum(self):
"The position must be on the prescribed line"
return self.x self.y == 25
class Something2(Something):
def validate_sum(self):
return True
Something(3, 22).validate() # Ok
Something2(5, 30).validate() # Ok (derived class relaxed checks)
print "About to crash...."
Something2(5, 31).validate() # Not ok (Y is too high - inherited check)
Обратите внимание, конечно, что отключение проверки в производном классе нелогично с точки зрения IS-A, вот просто как пример, показывающий, что dir
это позволит правильно находить унаследованные элементы.
Комментарии:
1. FWIW
validate()
может быть изменен, чтобы извлекать и использовать текст, следующий за"validate_"
именем метода, когда он создает сообщение об ошибке. СУХО.2. @martineau: Использование
__doc__
не является повторением, это может быть удобное для пользователя сообщение, не связанное с именем валидатора. Имя средства проверки уже используется в сообщении перед:
(однако не удаляется"validate_"
). Я собираюсь добавить правку, чтобы сделать намерение более ясным…3. У меня нет проблем с использованием
__doc__
строки — я всего лишь внес предложение, которое позволило бы ей быть более согласованной с «получить имя поля», указанным в вопросе OP. То, что вы придумали, способно к большему, чем простая проверка значения поля (и это хорошо, ИМХО).