My understanding was that there are not really private methods/attributes in Python, meaning that as long as you know the name of the method or attribute you will always be able to access and/or modify it (I might be understanding wrongly the concept of privacy).
Taking into account the framework described above, I came across with a situation I cannot quite wrap my head around. When creating a matplotlib.pyplot
plot:
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()
I get a matplotlib.legend.Legend
object holding a list of all matplotlib.text.Text
objects that resemble the text entries displayed in the legend:
>>> 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')
According to the source code, seems to me that the list returned by the method matplotlib.legend.Legend.get_texts()
is filled with the content of the matplotlib.legend.Legend
instance variable self.texts
, which is itself a list. Accessing and modifying this instance variable does not work:
>>> 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')
I am not an expert in Python, but I was not expecting this behavior, and I do not understand how this happens at an object/property level, and I haven't followed deeper if there are any special constraints in the construction of the matplotlib.legend.Legend.texts
instance variable.
The only general reason for this to happen I could come up with has been that at some level of depth there is some kind of "ghost" setter that just does not modify a class property:
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
This setter blocks control from the outside to modify the variable value:
>>> f = Foo(3)
>>> f.x
3
f.x = 5
>>> f.x
3
Nevertheless, the matplotlib.legend.Legend
instance variable self.texts
seems defined like a regular instance variable and I have not been able to find it defined as a property or any getters or setters related to it.
So, given this situation, I have three questions:
1) Is this little class example an accepted/legit way of getting "some sort" of privacy, in the sense that the attribute cannot be modified?
2) Are there some other/equivalent ways of blocking access/control over attributes or methods in Python?
3) How does it work or is it arranged in the particular case of matplotlib.legend.Legend
objects (focus on the self.texts
instance variable)?
Considerations:
1) I have tried to find answers to these questions and have not succeeded. Particularly the question to how is this behavior implemented in matplotlib.legend.Legend
objects remains yet unanswered to me.
2) I have taken a look at the matplotlib.legend.Legend
source code and I can see that the function matplotlib.legend.Legend.get_texts()
returns a silent_list
object, which apparently is just a list object with an overridden __repr__
method. Still does not help me get the understanding that I am missing.
3) I am aware of the bunch of higher-level methods in matplotlib.legend.Legend
objects that allow me to modify the legend in many/all possible ways. I though just want to understand how the mechanism works under the hood.
Thanks very much in advance for your time and help.
答案 0 :(得分:2)
This has nothing to do with the attribute machinery. You're just getting different objects from the legend()
call each time. These objects have different attributes, so screwing with one legend()
return value doesn't automatically affect another.