Я понимаю, что прошел месяц с тех пор, как об этом спросили, но я столкнулся с похожей проблемой (т.е. pow(float('nan'), 1)
выдает исключение в некоторых реализациях Python, например Jython 2.52b2), и я обнаружил, что приведенные выше ответы были не совсем тем, что я искал.
Использование типа MissingData, предложенного 6502, кажется правильным, но мне нужен был конкретный пример. Я попробовал класс NullType Итана Фурмана, но обнаружил, что он не работает с какими-либо арифметическими операциями, поскольку не приводит к принудительному принуждению типов данных (см. ниже), и мне также не понравилось, что он явно называет каждую арифметическую функцию, которая была переопределена.
Начиная с примера Итана и настройки кода, я нашел здесь , я прибыл в классе ниже. Хотя класс сильно прокомментирован, вы можете видеть, что на самом деле в нем всего несколько строк функционального кода.
Ключевые моменты: 1. Используйте coerce(), чтобы вернуть два объекта NoData для смешанных арифметических операций (например, NoData + float) и две строки для строковых операций (например, concat) операции. 2. Используйте getattr() для возврата вызываемого объекта NoData() для доступа ко всем другим атрибутам/методам 3. Используйте call() для реализации всех других методов объекта NoData(): возвращая объект NoData()
Вот несколько примеров его использования.
>>> nd = NoData()
>>> nd + 5
NoData()
>>> pow(nd, 1)
NoData()
>>> math.pow(NoData(), 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: nb_float should return float object
>>> nd > 5
NoData()
>>> if nd > 5:
... print "Yes"
... else:
... print "No"
...
No
>>> "The answer is " + nd
'The answer is NoData()'
>>> "The answer is %f" % (nd)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float argument required, not instance
>>> "The answer is %s" % (nd)
'The answer is '
>>> nd.f = 5
>>> nd.f
NoData()
>>> nd.f()
NoData()
Я заметил, что использование pow с NoData() вызывает оператор ** и, следовательно, работает с NoData, но использование math.pow не работает, поскольку сначала он пытается преобразовать объект NoData() в число с плавающей запятой. Я доволен использованием нематематического pow - надеюсь, 6502 и т. д. использовали math.pow, когда у них были проблемы с pow в их комментариях выше.
Другая проблема, которую я не могу придумать, - это использование с оператором формата (%f)... В этом случае не вызываются никакие методы NoData, оператор просто терпит неудачу, если вы не предоставляете число с плавающей запятой. Во всяком случае, вот сам класс.
class NoData():
"""NoData object - any interaction returns NoData()"""
def __str__(self):
#I want '' returned as it represents no data in my output (e.g. csv) files
return ''
def __unicode__(self):
return ''
def __repr__(self):
return 'NoData()'
def __coerce__(self, other_object):
if isinstance(other_object, str) or isinstance(other_object, unicode):
#Return string objects when coerced with another string object.
#This ensures that e.g. concatenation operations produce strings.
return repr(self), other_object
else:
#Otherwise return two NoData objects - these will then be passed to the appropriate
#operator method for NoData, which should then return a NoData object
return self, self
def __nonzero__(self):
#__nonzero__ is the operation that is called whenever, e.g. "if NoData:" occurs
#i.e. as all operations involving NoData return NoData, whenever a
#NoData object propagates to a test in branch statement.
return False
def __hash__(self):
#prevent NoData() from being used as a key for a dict or used in a set
raise TypeError("Unhashable type: " + self.repr())
def __setattr__(self, name, value):
#This is overridden to prevent any attributes from being created on NoData when e.g. "NoData().f = x" is called
return None
def __call__(self, *args, **kwargs):
#if a NoData object is called (i.e. used as a method), return a NoData object
return self
def __getattr__(self,name):
#For all other attribute accesses or method accesses, return a NoData object.
#Remember that the NoData object can be called (__call__), so if a method is called,
#a NoData object is first returned and then called. This works for operators,
#so e.g. NoData() + 5 will:
# - call NoData().__coerce__, which returns a (NoData, NoData) tuple
# - call __getattr__, which returns a NoData object
# - call the returned NoData object with args (self, NoData)
# - this call (i.e. __call__) returns a NoData object
#For attribute accesses NoData will be returned, and that's it.
#print name #(uncomment this line for debugging purposes i.e. to see that attribute was accessed/method was called)
return self
person
jcdude
schedule
03.05.2012