Restricting methods in derived classes
Mark McEahern
marklists at mceahern.com
Fri Sep 13 22:45:14 EDT 2002
[Huaiyu Zhu]
> But seriously, your first solution actually contains all I needed. Here's
> what I adopted in the end:
[snip]
> Maybe there is a simple way to wrap up restrict() in a metaclass, so that
> instead of restrict(foo) we can say class foo(dict, restricted): ...
> I'm still not so used to metaclasses to figure that out, however.
I like the solution you adopted and I used it to simplify (imo, anyway) my
metaclass approach (see below), which I still prefer, but I'm not quite sure
why. One thing I don't quite understand is why you'd want to bother messing
with magic methods at all (which you're _common suggests you do). That
seems like an invitation to disaster--but that's a statement that comes more
from ignorance than experience on my part. In the code I attached, if you
wanted to suppress magic methods, you would simply remove the is_magic test.
Thanks for this opportunity to improve my understanding of metaclasses.
Cheers,
// mark
#!/usr/bin/env python
import inspect
def make_undefined(cls, attr):
def undefined(self, *args, **kwargs):
msg = "'%s' object has no attribute '%s'" % (cls.__name__, attr)
raise AttributeError(msg)
return undefined
def is_magic(attr):
prefix = suffix = '__'
return attr.startswith(prefix) and attr.endswith(suffix)
class Restricted(type):
common = ['__class__', '__defined__', '__dict__', '__doc__',
'__getattribute__', '__init__', '__new__']
def __new__(cls, classname, bases, classdict):
defined_key = 'defined'
defined = classdict.get(defined_key, []) + Restricted.common
# If a non-magic attribute from any base class is not in common or
# defined, hide it with a method that raises a descriptive
# AttributeError (mimicking Python).
for base in bases:
for k, v in inspect.getmembers(base):
if not is_magic(k) and k not in defined:
classdict[k] = make_undefined(cls, k)
return type.__new__(cls, classname, bases, classdict)
class RestrictedDict(dict):
__metaclass__ = Restricted
defined = ['put', 'get', 'keys', 'items', 'values']
f = RestrictedDict()
print f.keys
print f.keys()
f['a'] = 'b'
print f.keys()
try:
f.clear()
except AttributeError:
pass
print f.keys()
-
More information about the Python-list
mailing list