Will python never intend to support private, protected and public?

John Perks and Sarah Mount johnandsarah at estragon.freeserve.co.uk
Sun Oct 2 12:37:03 EDT 2005


> 1) Something that fixes the broken name mangling in the current
> system, but still doesn't try to defeat intentional unmangling.
> Currently, if you have a class with the same name as one of its
> superclasses, the name mangling can fail even its existing purpose of
> preventing accidental collisions.

None of what follows offers any protection against malice, but at least
"normal" use will be safe. Are there any other idioms where __dict__s
are used as dumping grounds for strange objects, in particular
superclasses of that object?

(For this to work the instance needs a __dict__; fully __slots__'d
objects won't be amenable to it)

Instead of mangling in the class name:

class C:
    def __init__(self, x):
        self.__x = x

One could mangle in the class itself:

class C:
    def __init__(self, x):
        self.__dict__[C, 'x'] = x

(and retrieve similarly). Now classes with the same name are still
regarded as distict. A variation on this is to have a single __dict__
entry for the class, which refers to another dict, so we would have
something like

def __init__(self, ...):
   privates = { }
   self.__dict__[C] = privates
   # ...

def f(self...):
    privates = self.__dict__[C]
    # ...

and then get or set privates[varName] as needed. (Or possibly use it
lazily via setdefault if you have a good idea of the what the defaults
should be.)

However this means non-strings end up in dir() which may cause things
like map str.upper, dir(C())) to fail. Thus instead of C as the key we
could use `id(C)`.

The only chance for collision I can see in the `id` solution is if an
object changes its __class__, then the old class is GC'd, a new one is
loaded with the same address as the old, and the __class__ is changed to
(a subclass of) this new one. Frankly __class__ reassignment is fairly
esoteric, and already has the question of how well the __dict__ from the
old type masquerades as a new one.

Other scope for collision: if the classes in question are instances of
some mad metaclass which defines == to mean something other than
identity testing (is). This would only be needed if the objects weren't
just used as types, but also something else as well (e.g. collections of
all their instances, implemented via weakrefs).

Note that this won't quite work for private data in new classes, as
their __dict__ is read-only, but I offer the following peculiar hack:

class K(object):
    __dict__ = {}
    # ...

Any normal accesses to K.__dict__ will reach the wrapping dictproxy
object, but K.__dict__['__dict__'] is all yours to play with. If you
start by assigning __dict__ to locals() in the class initializer, then
writes to K.__dict__['__dict__'] will be visible just through
K.__dict__. Whether that's desirable or not depends on you. (locals()
isn't what you want if you're creating truly dynamic types via
type(names, bases, dict), though.)

Paranoid/super-open-minded types might wish to replace accesses to
__dict__ here with calls to object.__getattribute__(...,'__dict__') in
case any subclasses have strange semantics (which may make perfect sense
as far as they're concerned, but still potentially be a problem for you
having to second-guess them.)

Hope this helps

John

PS Only slightly relevant: when checking out the possibilties for
private attrs on types, I ran up against dictproxies. What need did they
meet over plain dicts, why are they read-only (at the Python and CPython
level), why are they not instantiable directly (though you can always
just create a temporary type and steal its __dict__), and why is type's
__dict__ is read-only but a class's isn't? I just have down'n'dirty type
dict munging to do, and it seems retrograde that it only works with old
(and nominally less flexible) classes.





More information about the Python-list mailing list