Você, que acha que toda linguagem OO '''tem de ter variáveis privadas''' porque aprendeu com uma que tem? Acha que isso é um mandamento sagrado e acha que Python é uma linguagem pecadora porque não tem? Suas orações foram atendidas. Usando o código abaixo você estará privado de todo o mal dos atributos públicos. Exceto para alguém que esteja '''REALMENTE''' disposto a alterá-los, e esse merece ir para o inferno, não? Não? Não acha? Bom... então é melhor deixar isso pra lá e não continuar lendo porque talvez você acabe levando isso a sério. Basta salvar o código abaixo em um módulo, importar a função '''{{{private}}}''' para seu módulo e definir a variável {{{'__metaclass__ = private('var1', 'var2', 'var3', ...) }}} no início, listando todos os atributos que deseja deixar privados. '''OBS:''' aos desavisados, esse código, nos moldes do NoSelf, também '''é uma brincadeira''', feita para mostrar como atributos privados não são uma prioridade e que em Python, se você estiver realmente disposto, é possível restringir o acesso cada vez mais e mais (e aqui nem foi muito longe), mas se o usuário quer mesmo alterar, por que impedir? Crédito ao João S. O. Bueno pela idéia original e algumas dicas. Ele também encontrou algumas maneiras de quebrar (que não mencionarei aqui), e para cada uma delas até encontrei uma maneira de proteger, mas acho que isso já basta para ilustrar a idéia... {{{ #!python numbers=off #!/usr/bin/env python # encoding: utf-8 import inspect import sys import types import unittest class PrivateAttributeError(AttributeError): pass def _check_caller(obj, level): frame = sys._getframe(level) cls = type(obj) values = frame.f_locals.values() if obj not in values: return False funcs = [func for func in cls.__dict__.values() if isinstance(func, types.FunctionType)] for func in funcs: code1 = func.func_code code2 = frame.f_code if code1 is code2: break else: return False return True class Private(object): pass class PrivateAttribute(Private): def __init__(self, name): self.name = name def __get__(self, obj, cls=None): if not _check_caller(obj, 2): raise PrivateAttributeError("can only be used inside a method") try: value = obj.__privdict__[self.name] except KeyError: raise AttributeError("Private attribute '%s' not set" % self.name) return value def __set__(self, obj, value): if not _check_caller(obj, 2): raise PrivateAttributeError("can only be used inside a method") obj.__privdict__[self.name] = value def __delete__(self, obj): if not _check_caller(obj, 2): raise PrivateAttributeError("can only be used inside a method") try: del obj.__privdict__[self.name] except KeyError: raise AttributeError("Private attribute '%s' not set" % self.name) class PrivateMethod(Private): def __init__(self, func): self.func = func def __get__(self, obj, cls=None): if not _check_caller(obj, 2): raise PrivateAttributeError("can only be used inside a method") return types.MethodType(self.func, obj, cls) def __set__(self, obj, value): raise RuntimeError("You can't reasign a private method") def __delete__(self, obj): raise RuntimeError("You can't reasign a private method") class PrivateDict(object): __slots__ = ['owner', '__privdict__'] def __init__(self, owner): self.owner = owner self.__privdict__ = {} def __setitem__(self, key, value): if not _check_caller(self.owner, 3): raise PrivateAttributeError("Are you trying to break this?") self.__privdict__[key] = value def __getitem__(self, key): if not _check_caller(self.owner, 3): raise PrivateAttributeError("Are you trying to break this?") return self.__privdict__[key] def __getattribute__(self, attr): if not _check_caller(self, 2): raise PrivateAttributeError("Are you trying to break this?") return super(PrivateDict, self).__getattribute__(attr) def __setattribute__(self, attr): if not _check_caller(self, 2): raise PrivateAttributeError("Are you trying to break this?") return super(PrivateDict, self).__getattribute__(attr) class MetaEnablePrivate(type): def __call__(cls, *args, **kwds): new = cls.__new__(cls, *args, **kwds) new.__privdict__ = PrivateDict(new) cls.__init__(new, *args, **kwds) return new def private(*args): attrs = dict((name, PrivateAttribute(name)) for name in args) def _metaclass(name, bases, dict): dict.update(attrs) return MetaEnablePrivate(name, bases, dict) return _metaclass # Um testezinho... class Test(object): __metaclass__ = private('foo', 'bar') def __init__(self, name): self.foo = None self.bar = None self.name = name self.wow = None def set_foo(self, value): self.foo = value self.bar = "and I am new bar in %s"%self.name def get_foo(self): return self.foo @PrivateMethod def meth(self): return 'I am supposed to be a private method' def call_meth(self): return self.meth() class TestPrivateAttributes(unittest.TestCase): def setUp(self): self.obja = Test('a') self.objb = Test('b') self.obja.set_foo('I am foo in a') self.objb.set_foo('I am foo in b') def testGettersSetters(self): # get original self.assertEqual(self.obja.get_foo(), 'I am foo in a') self.assertEqual(self.objb.get_foo(), 'I am foo in b') # set self.obja.set_foo('I am new foo in a') self.objb.set_foo('I am new foo in b') # check if it really got set self.assertEqual(self.obja.get_foo(), 'I am new foo in a') self.assertEqual(self.objb.get_foo(), 'I am new foo in b') def testBreakDirectGet(self): self.assertRaises(PrivateAttributeError, getattr, self.obja, 'foo') self.assertRaises(PrivateAttributeError, getattr, self.obja, 'bar') self.assertEqual(self.obja.wow, None) self.assertRaises(PrivateAttributeError, getattr, self.objb, 'foo') self.assertRaises(PrivateAttributeError, getattr, self.objb, 'bar') self.assertEqual(self.objb.wow, None) def testBreakDirectSet(self): self.assertRaises(PrivateAttributeError, setattr, self.obja, 'foo', '') self.assertRaises(PrivateAttributeError, setattr, self.obja, 'bar', '') self.obja.wow = '' self.assertRaises(PrivateAttributeError, setattr, self.objb, 'foo', '') self.assertRaises(PrivateAttributeError, setattr, self.objb, 'bar', '') self.objb.wow = '' def testWithObjectGetattribute(self): self.assertRaises(PrivateAttributeError, object.__getattribute__, self.obja, 'foo') self.assertRaises(PrivateAttributeError, object.__getattribute__, self.obja, 'bar') self.assertRaises(PrivateAttributeError, object.__getattribute__, self.objb, 'foo') self.assertRaises(PrivateAttributeError, object.__getattribute__, self.objb, 'bar') def testWithObjectSetattr(self): self.assertRaises(PrivateAttributeError, object.__setattr__, self.obja, 'foo', '') self.assertRaises(PrivateAttributeError, object.__setattr__, self.obja, 'bar', '') self.assertRaises(PrivateAttributeError, object.__setattr__, self.objb, 'foo', '') self.assertRaises(PrivateAttributeError, object.__setattr__, self.objb, 'bar', '') def testWithObjectPrivdict(self): self.assertRaises(PrivateAttributeError, lambda :self.obja.__privdict__['foo']) self.assertRaises(PrivateAttributeError, lambda :self.obja.__privdict__['bar']) self.assertRaises(PrivateAttributeError, lambda :self.objb.__privdict__['foo']) self.assertRaises(PrivateAttributeError, lambda :self.objb.__privdict__['bar']) if __name__ == '__main__': unittest.main() }}}