Python @property (метод установки), который ограничен установкой данных только в методе __init__

Я хотел бы настроить объект, который импортирует некоторые raw_data на этапе инициализации объекта (т.е. во время метода __init__()). Однако я хотел бы, чтобы он читался только с этого момента. Я думал об использовании свойства setter self.raw_data со следующей логикой:

@raw_data.setter
def raw_data(self, dataframe):
    <IF calling from __init__>?
        self.__raw_data = df

Есть ли способ для метода установки узнать, вызывается ли он из __init__? Блокирование всех других попыток изменить данные.


person sanguineturtle    schedule 24.07.2014    source источник
comment
Попробуйте этот рецепт.   -  person shx2    schedule 24.07.2014
comment
Почему бы просто не установить self.__raw_data напрямую?   -  person Blender    schedule 24.07.2014
comment
Я хотел бы иметь возможность установить его в методе __init__(), но больше нигде, чтобы эффективно превратить переменную .__raw_data в атрибут только для чтения. Я хотел бы гарантировать его состояние, чтобы позже непреднамеренно не назначить __raw_data.   -  person sanguineturtle    schedule 24.07.2014
comment
Я должен быть немного яснее. Я согласен, что self.__raw_data исправляет внешний доступ, делая raw_data закрытым. Однако я хотел бы защитить его от других внутренних методов, работающих с данными в том же классе.   -  person sanguineturtle    schedule 24.07.2014


Ответы (2)


Ничто из того, что вы делаете в установщике raw_data, не остановит прямое назначение __raw_data. Я бы рекомендовал не определять сеттер и использовать __raw_data для инициализации. Это заблокирует запись в raw_data, но не в __raw_data.

Если вы хотите более строгого соблюдения, то по замыслу у вас не так много вариантов. Один из вариантов — написать свой класс на C или Cython. Другой вариант проще, но он имеет неудобные побочные эффекты. Этот вариант заключается в подклассе неизменяемого встроенного типа, такого как tuple, и создании предварительно инициализированных экземпляров с помощью __new__ вместо их преобразования в инициализированное состояние с помощью __init__:

class Immutable(tuple):
    __slots__ = [] # Prevents creation of instance __dict__
    def __new__(cls, *whatever_args):
        attribute1 = compute_it_however()
        attribute2 = likewise()
        return super(cls, Immutable).__new__(cls, attribute1, attribute2)
    @property
    def attribute1(self):
        return self[0]
    @property
    def attribute2(self):
        return self[1]

Это делает ваши объекты неизменяемыми, но неловкий побочный эффект заключается в том, что ваши объекты теперь являются кортежами.

person user2357112 supports Monica    schedule 24.07.2014
comment
Да спасибо. Я мог бы просто написать простой скрипт, который анализирует исходный код Python, проверяя любые __raw_data= назначения вне метода init. Тогда все, что мне нужно, это Immutable pandas DataFrame? - person sanguineturtle; 24.07.2014
comment
@sanguineturtle: Может быть. Я не знаком с пандами. - person user2357112 supports Monica; 24.07.2014

Самое близкое, что вы можете получить, это разрешить устанавливать self._raw_data только в том случае, если он еще не установлен, т.е.:

class Foo(object):
    def __init__(self, dataframe):
        self.raw_data = dataframe

    @property
    def raw_data(self):
         return getattr(self, '_raw_data', None)

    @raw_data.setter
    def raw_data(self, dataframe):
        if hasattr(self, '_raw_data'):
            raise AttributeError, "Attribute is read-only")
        self._raw_data = dataframe

Что делает установщик в основном бесполезным, поэтому вы получите тот же результат с меньшим количеством пропуска кода (что сделает свойство доступным только для чтения):

class Foo(object):
    def __init__(self, dataframe):
        self._raw_data = dataframe

    @property
    def raw_data(self):
         return self._raw_data

Но имейте в виду, что ни одно из этих решений не помешает вам напрямую установить _raw_data.

person bruno desthuilliers    schedule 24.07.2014