ninjaef Ответов: 2

Как предотвратить обновление "частных" данных в Python?


Простой код, в Вместо python2.7, с "индивидуальный" элемент данных "предметов". Я слышал, что на самом деле в Python нет ничего, что можно было бы сделать, чтобы объявить атрибут действительно "частным" ... этот код управляет изменением первого элемента списка элементов из экземпляра группы в строку. Почему и как я могу остановить его / перекодировать ?? Я чувствую боль в кругах Python , когда такие люди, как я, говорят о "частном", но придерживайтесь меня, пожалуйста, потому что я пытаюсь защитить себя здесь от того, что я "культурно" не должен делать - то есть писать в другие классы и экземпляры (как цитируется здесь: класс - есть ли у Python “частные” переменные в классах? - переполнение стека)

class Groups():
    
  def __init__(self):
    self.__items = []
  
  def add(self, name, hidden=None, position=None):
    if name not in self.__items:
      if position is None:
        print("appending %s" % name)
        self.__items.append(Group(name=name, hidden=hidden, position=position))
      else:
        print("inserting %s" % name)
        self.__items.insert(position, Group(name=name, hidden=hidden, position=position))
      print('after add, len=',len(self.__items))
  
  def list(self):
    print("list():")
    print "".join("   item: "+x.name for x in self.__items)
    return self.__items

g=Groups()
print("adding ITEM")
g.add("ITEM")
g.list()
print("changing..")
g.list()[0]="Changed" 
g.list() Should now raise an exception


Метод list() возвращает элементы по ссылке, позволяя прямой доступ к списку, а не передавая по значению (т. е. копию элементов). Кроме того, имя mangling __items кажется неэффективным в том смысле, что я все еще могу изменять данные с помощью list()[0] =

Кстати, то, что я пытаюсь сделать здесь, - это абстрактная реализация __list. Сегодня это простой список Python, завтра я мог бы сделать его классом, но я хочу абстрагировать его в классе Groups.

Мне просто нужно какое-то образование здесь, думает я.

Что я уже пробовал:

ничего - не знаю, что делать, так как я изучаю Python.

2 Ответов

Рейтинг:
19

Jochen Arndt

Я не специалист по Питону, так что мои мысли могут быть не точными.

Ваш list() функция возвращает ссылку на закрытый член. Поскольку функция также является членом, она имеет доступ к массиву. В результате вызывающая сторона "видит" ссылку, которую ей разрешено использовать и изменять.

Вы знаете с++? Там все очень похоже:

class Test {
public:
    Test(int a = 0) { m_a = a; }
    int& get() { return m_a; }
private:
    int m_a;
};

int main()
{
    Test test(1);
    // Allowed because get() returns a reference
    test.get() = 2;
    // This will print 2
    printf("%d\n", test.get());
    
    return 0;
}

Решение состоит в том, чтобы не возвращать список вообще или вернуть копию списка (см. Вопросы и ответы по программированию — документация Python 3.6.6rc1: Как скопировать объект в Python?[^] ):
# Using slicing
return self.__items[:]
# Return a new list
return list(self.__items)
# Using copy.copy() or copy.deepcopy()
return copy.deepcopy(self.__items)

[РЕДАКТИРОВАТЬ]
Лучшим решением было бы вернуть ссылку только для чтения, как в случае с C++ const ключевое слово. Но Python не поддерживает (и не будет поддерживать) это из-за своего дизайна и идеологии.

В Python вызывающий такие функции отвечает за то, чтобы не делать что-то "неправильное" с возвращаемыми ссылками. Это должно быть четко указано в документации по данной функции.
[/РЕДАКТИРОВАТЬ]


ninjaef

да, понимаю с++
спасибо за пример
теперь понятно...просто теперь ты объяснил это таким образом.
да, я слышал о принципах python duckduck и идеологии use-me-dont-abuse me.

РЕДАКТИРОВАТЬ
к сожалению, мой телефон нажмите 4-звездочный, а не 5. имел в виду, чтобы дать вам 5*. извиняюсь

Рейтинг:
0

Richard MacCutchan

Видеть 9. классы — документация Python 3.4.8: частные переменные[^Я предлагаю перейти к первой странице этого учебника и проработать его; действительно полезный учебник.


ninjaef

Естественно, я читаю документацию по python, включая раздел о классах, я чувствовал, что это очевидно, иначе как бы я изучал Python - ссылки на документацию не очень полезны в этом случае, я надеялся на объяснение, а не на ссылку на языковые документы. В частности, почему list()[0] позволяет изменять данные "private" __items ?? Я явно не понимаю, что происходит, несмотря на то, что читаю документацию !

Richard MacCutchan

“Частные” переменные экземпляра, доступ к которым возможен только изнутри объекта не существует в Python Я не думаю, что это утверждение может быть более ясным.

"Почему list()[0] позволяет изменять данные "private" __items ?"
Потому что, как ясно показано в документации, в Python нет такого понятия, как "частный".