Я пытаюсь настроить подкласс, pd.DataFrame
который имеет два обязательных аргумента при инициализации ( group
и timestamp_col
). Я хочу запустить проверку этих аргументов group
и timestamp_col
, таким образом, у меня есть метод установки для каждого из свойств. Это все работает, пока я не попытаюсь set_index()
и получить TypeError: 'NoneType' object is not iterable
. Похоже, что никакие аргументы не передаются моей функции установки в test_set_index
и test_assignment_with_indexed_obj
. Если я добавлю if g == None: return
к своей функции установки, я могу пройти тестовые случаи, но не думаю, что это правильное решение.
Как мне реализовать проверку свойства для этих обязательных аргументов?
Ниже мой класс:
import pandas as pd
import numpy as np
class HistDollarGains(pd.DataFrame):
@property
def _constructor(self):
return HistDollarGains._internal_ctor
_metadata = ["group", "timestamp_col", "_group", "_timestamp_col"]
@classmethod
def _internal_ctor(cls, *args, **kwargs):
kwargs["group"] = None
kwargs["timestamp_col"] = None
return cls(*args, **kwargs)
def __init__(
self,
data,
group,
timestamp_col,
index=None,
columns=None,
dtype=None,
copy=True,
):
super(HistDollarGains, self).__init__(
data=data, index=index, columns=columns, dtype=dtype, copy=copy
)
self.group = group
self.timestamp_col = timestamp_col
@property
def group(self):
return self._group
@group.setter
def group(self, g):
if g == None:
return
if isinstance(g, str):
group_list = [g]
else:
group_list = g
if not set(group_list).issubset(self.columns):
raise ValueError("Data does not contain " + '[' + ', '.join(group_list) + ']')
self._group = group_list
@property
def timestamp_col(self):
return self._timestamp_col
@timestamp_col.setter
def timestamp_col(self, t):
if t == None:
return
if not t in self.columns:
raise ValueError("Data does not contain " + '[' + t + ']')
self._timestamp_col = t
Вот мои тесты:
import pytest
import pandas as pd
import numpy as np
from myclass import *
@pytest.fixture(scope="module")
def sample():
samp = pd.DataFrame(
[
{"timestamp": "2020-01-01", "group": "a", "dollar_gains": 100},
{"timestamp": "2020-01-01", "group": "b", "dollar_gains": 100},
{"timestamp": "2020-01-01", "group": "c", "dollar_gains": 110},
{"timestamp": "2020-01-01", "group": "a", "dollar_gains": 110},
{"timestamp": "2020-01-01", "group": "b", "dollar_gains": 90},
{"timestamp": "2020-01-01", "group": "d", "dollar_gains": 100},
]
)
return samp
@pytest.fixture(scope="module")
def sample_obj(sample):
return HistDollarGains(sample, "group", "timestamp")
def test_constructor_without_args(sample):
with pytest.raises(TypeError):
HistDollarGains(sample)
def test_constructor_with_string_group(sample):
hist_dg = HistDollarGains(sample, "group", "timestamp")
assert hist_dg.group == ["group"]
assert hist_dg.timestamp_col == "timestamp"
def test_constructor_with_list_group(sample):
hist_dg = HistDollarGains(sample, ["group", "timestamp"], "timestamp")
def test_constructor_with_invalid_group(sample):
with pytest.raises(ValueError):
HistDollarGains(sample, "invalid_group", np.random.choice(sample.columns))
def test_constructor_with_invalid_timestamp(sample):
with pytest.raises(ValueError):
HistDollarGains(sample, np.random.choice(sample.columns), "invalid_timestamp")
def test_assignment_with_indexed_obj(sample_obj):
b = sample_obj.set_index(sample_obj.group + [sample_obj.timestamp_col])
def test_set_index(sample_obj):
# print(isinstance(a, pd.DataFrame))
assert sample_obj.set_index(sample_obj.group + [sample_obj.timestamp_col]).index.names == ['group', 'timestamp']
python
pandas
properties
subclass
cpage
источник
источник
None
это недопустимое значение дляgroup
свойства, вы не должны поднятьValueError
?None
это неверное значение, поэтому мне не нравится выражение if. Но добавив, что None заставляет его пройти тесты. Я ищу, как правильно это исправить без заявления None if.ValueError
. Проблема состоит в том, чтобы выяснить, что пытается установитьgroup
атрибутNone
в первую очередь.Ответы:
set_index()
Метод будет вызыватьself.copy()
внутри , чтобы создать копию объекта DataFrame (просмотреть исходный код здесь ), внутри которого он использует свой собственный алгоритм конструктора_internal_ctor()
, чтобы создать новый объект ( источник ). Обратите внимание, чтоself._constructor()
это идентичноself._internal_ctor()
, что является общим внутренним методом почти для всех классов панд для создания новых экземпляров во время таких операций, как глубокое копирование или нарезка. Ваша проблема на самом деле происходит из этой функции:Я полагаю, вы скопировали этот код из выпуска GitHub . Строки
kwargs["**"] = None
явно указывают конструктору установитьNone
оба параметраgroup
иtimestamp_col
. Наконец установщик / валидатор получаетNone
новое значение и выдает ошибку.Поэтому вы должны установить приемлемое значение
group
иtimestamp_col
.Затем вы можете удалить
if g == None: return
строки в валидаторе.источник