Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python: immutable private class variables?

Is there any way to translate this Java code into Python?

class Foo
{
    final static private List<Thingy> thingies = 
       ImmutableList.of(thing1, thing2, thing3);
}

e.g. thingies is an immutable private list of Thingy objects that belongs to the Foo class rather than its instance.

I know how to define static class variables from this question Static class variables in Python but I don't know how to make them immutable and private.

like image 396
Jason S Avatar asked Sep 13 '11 18:09

Jason S


People also ask

Does Python have private class variables?

In Python, there is no existence of “Private” instance variables that cannot be accessed except inside an object.

How are private variables in Python enforced?

In actual terms (practically), python doesn't have anything called private member variable in Python. However, adding two underlines(__) at the beginning makes a variable or a method private is the convention used by most python code.

How do you access a private class variable in Python?

Python doesn't have real private variables, so use the __ prefix (two underlines at the beginning make a variable) from PEP 8. Use instance _class-name__private-attribute try to access private variables outside the class in Python.


2 Answers

In Python the convention is to use a _ prefix on attribute names to mean protected and a __ prefix to mean private. This isn't enforced by the language; programmers are expected to know not to write code that relies on data that isn't public.

If you really wanted to enforce immutability, you could use a metaclass[docs] (the class of a class). Just modify __setattr__ and __delattr__ to raise exceptions when someone attempts to modify it, and make it a tuple (an immutable list) [docs].

class FooMeta(type):
    """A type whose .thingies attribute can't be modified."""

    def __setattr__(cls, name, value):
        if name == "thingies":
            raise AttributeError("Cannot modify .thingies")
        else:
            return type.__setattr__(cls, name, value)

    def __delattr__(cls, name):
        if name == "thingies":
            raise AttributeError("Cannot delete .thingies")
        else:
            return type.__delattr__(cls, name)

thing1, thing2, thing3 = range(3)

class Foo(object):
    __metaclass__ = FooMeta
    thingies = (thing1, thing2, thing3)
    other = [1, 2, 3]

Examples

print Foo.thingies # prints "(0, 1, 2)"
Foo.thingies = (1, 2) # raises an AttributeError
del Foo.thingies # raise an AttributeError
Foo.other = Foo.other + [4] # no exception
print Foo.other # prints "[1, 2, 3, 4]"

It would still technically be possible to modify these by going through the class's internal .__dict__ of attributes, but this should be enough to deter most users, it's very difficult to entirely secure Python objects.

like image 133
Jeremy Avatar answered Sep 20 '22 23:09

Jeremy


You can't do either of those things in Python, not in the sense you do them in Java, anyway.

By convention, names prefixed with an underscore are considered private and should not be accessed outside the implementation, but nothing in Python enforces this convention. It's considered more of a warning that you're messing with an implementation detail that may change without warning in a future version of the code.

like image 36
kindall Avatar answered Sep 20 '22 23:09

kindall