Как можно помешать внешней модификации переменной экземпляра в Python? - PullRequest
0 голосов
/ 18 января 2019

Насколько я понимаю, в Python нет действительно закрытых методов / атрибутов, а это означает, что, пока вы знаете имя метода или атрибута, вы всегда сможете получить к нему доступ и / или изменить его (возможно, я неправильно понимаю понятие приватности).

Принимая во внимание структуру, описанную выше, я столкнулся с ситуацией, которую я не могу полностью обернуть вокруг себя. При создании matplotlib.pyplot сюжета:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib

fig, ax = plt.subplots()

x = np.arange(100)
ax.plot(x, np.sin(x), label='sinus')
ax.legend()

Я получаю объект matplotlib.legend.Legend, содержащий список всех matplotlib.text.Text объектов, которые напоминают текстовые записи, отображаемые в легенде:

>>> fig.axes[0].legend()
<matplotlib.legend.Legend at 0x28f6aa4d898>
>>> fig.axes[0].legend().get_texts()
<a list of 1 Text objects>
>>> fig.axes[0].legend().get_texts()[0]
<matplotlib.text.Text at 0x28f6aa17198>
>>> print(fig.axes[0].legend().get_texts()[0])
Text(0,0,'sinus')

Согласно исходному коду, мне кажется, что список, возвращаемый методом matplotlib.legend.Legend.get_texts(), заполнен содержимым matplotlib.legend.Legend переменной экземпляра self.texts, которая сама является списком. Доступ и изменение этой переменной экземпляра не работает:

>>> fig.axes[0].legend().texts
[<matplotlib.text.Text at 0x28f6420db38>]
>>> print(fig.axes[0].legend().texts[0])
Text(0,0,'sinus')
>>> fig.axes[0].legend().texts = [matplotlib.text.Text(0,0,'foo')]
>>> print(fig.axes[0].legend().texts[0])
Text(0,0,'sinus')

Я не эксперт в Python, но я не ожидал такого поведения, и я не понимаю, как это происходит на уровне объекта / свойства, и я не следил глубже, если есть какие-то особые ограничения в конструкции переменной экземпляра matplotlib.legend.Legend.texts.

Единственная общая причина, по которой я мог это сделать, заключалась в том, что на некотором уровне глубины существует некая «призрачная» установка, которая просто не изменяет свойство класса:

class Foo:

    def __init__(self, value):
        self._x = value

    @property
    def x(self): 
        return self._x

    @x.setter
    def x(self, value):
        # This setter blocks outside access
        pass

Этот сеттер блокирует управление извне для изменения значения переменной:

>>> f = Foo(3)
>>> f.x
3
f.x = 5
>>> f.x
3

Тем не менее, matplotlib.legend.Legend переменная экземпляра self.texts, похоже, определена как обычная переменная экземпляра, и я не смог найти ее, определенную как свойство или любые методы получения или установки, связанные с ним.

Итак, учитывая эту ситуацию, у меня есть три вопроса:

1) Является ли этот маленький пример класса приемлемым / законным способом получения «своего рода» конфиденциальности в том смысле, что атрибут не может быть изменен?

2) Существуют ли другие / эквивалентные способы блокировки доступа / контроля над атрибутами или методами в Python?

3) Как это работает или организовано в конкретном случае matplotlib.legend.Legend объектов (фокус на переменной экземпляра self.texts)?

Вопросы:

1) Я пытался найти ответы на эти вопросы и не смог. В частности, вопрос о том, как это поведение реализовано в matplotlib.legend.Legend объектах, остается пока без ответа.

2) Я посмотрел на исходный код matplotlib.legend.Legend и вижу, что функция matplotlib.legend.Legend.get_texts() возвращает объект silent_list, который, по-видимому, является просто объектом списка с переопределенным методом __repr__. Все еще не помогает мне понять, что я скучаю.

3) Мне известно о наборе высокоуровневых методов в matplotlib.legend.Legend объектах, которые позволяют мне изменять легенду многими / всеми возможными способами. Я просто хочу понять, как работает механизм под капотом.

Большое спасибо заранее за ваше время и помощь.

1 Ответ

0 голосов
/ 18 января 2019

Это не имеет ничего общего с атрибутом машины. Вы просто получаете разные объекты от звонка legend() каждый раз. Эти объекты имеют разные атрибуты, поэтому использование одного возвращаемого значения legend() не влияет автоматически на другое.

...