Not possible to hide local variables
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Tue Apr 28 04:37:36 EDT 2015
On Tuesday 28 April 2015 17:33, Cecil Westerhof wrote:
> If I remember correctly you can not hide variables of a class or make
> them read-only?
In Python circles, the preferred terminology for class and instance members
is "attributes" rather than variables. "Variable" is reserved for module-
and function-level name bindings.
But other than that, you are correct. Python practices attribute hiding by
convention. Names beginning with a single underscore like _spam or obj._eggs
are treated as private.
Names beginning with two underscores, but not trailing with underscores, are
also name-mangled: obj.__eggs will be mangled to obj._TheClass__eggs. You
should avoid name-mangling unless you really need it, don't use it "just in
case".
The convention is, if the caller messes with your private attributes or
variables, and their code breaks, they have nobody to blame but themselves,
and we are allowed to laugh at them. We're consenting adults here.
(The only exception is C extension objects and built-ins, where messing with
private data could cause a segfault.)
> I want to rewrite my moving average to python. The init is:
> def __init__(self, length):
> if type(length) != int:
> raise ParameterError, 'Parameter has to be an int'
> if n < 0:
> raise ValueError, 'Parameter should be greater or equal 2'
> self.length = length
> self.old_values = []
> self.current_total = 0
>
> But when someone changes length, old_values, or current_total that
> would wreck havoc with my class instance. What is the best way to
> handle this?
Don't use a class at all. Moving average is best handled as a generator. We
can use a regular generator:
import collections, itertools
def moving_average(data, window=3):
"""Iterate over data, yielding the simple moving average with a fixed
window size.
With a window size of N (defaulting to three), the simple moving average
yields the average of items data[0:N], data[1:N+1], data[2:N+2], ...
>>> list(moving_average([40, 30, 50, 46, 39, 44]))
[40.0, 42.0, 45.0, 43.0]
"""
it = iter(data)
d = collections.deque(itertools.islice(it, window))
if len(d) != window:
raise ValueError('too few data points for given window size')
s = sum(d)
yield s/window
for x in it:
s += x - d.popleft()
d.append(x)
yield s/window
Being an iterator, it can consume data points one at a time and return
results as needed, or here is an example of consuming all the data greedily:
py> data = [1, 2, 3, 2, 3, 5, 4, 7, 3]
py> list(moving_average(data))
[2.0, 2.3333333333333335, 2.6666666666666665, 3.3333333333333335, 4.0,
5.333333333333333, 4.666666666666667]
If you must use a class, flag the internal attributes as private with a
leading underscore. Your callers will respect that, and if they don't, all
promises are null and void.
--
Steve
More information about the Python-list
mailing list