Read Only attributes, auto properties and getters and setters

TechieInsights GDoermann at gmail.com
Thu Feb 12 10:44:57 EST 2009


Ok, so I noticed some of the modules (such as many of the datetime
attributes) are read-only, which means the __setattr__ and __set__
methods are intercepted... pretty easy.  I am looking for a way to
automate this.  The real goal is not to have read only attributes, but
to have getters and setters that are automatically called when a
property is called.  The getting is pretty easily achieved by setting
the metaclass which also creates the properties.  What I have so far
will protect the get_ and set_ methods as well as the properties that
call the get methods.  The reasoning for this is that I don't want
someone accidentally overwriting the property when the class uses a
private class variable.  What I have so far:



class ReadOnlyMeta(type):
	def __new__(cls, name, bases, methoddict):
		pname = '_%s__protected_items' %(name)
		protected = [pname]
		methoddict[pname] = protected
		for key, value in methoddict.items():
			if key.startswith("get_"):
				methoddict[key[4:]] = property(value)
				protected.append(key[4:])
				protected.append(key)
			elif key.startswith("set_"):
				protected.append(key)
		return type.__new__(cls, name, bases, methoddict)

class ReadOnly(object):
	__metaclass__ = ReadOnlyMeta

	def __check_private(self, name, msg = None):
		if name in self.__protected_items:
			if msg is None:
				msg = "'%s' of '%s' is Read only." %(name,
self.__class__.__name__)
			raise AttributeError(msg)

	def __setattr__(self, name, value):
		self.__check_private(name, "attribute '%s' of '%s' objects is not
writable" %(name, self.__class__.__name__))
		self.__dict__[name] = value

	def __delattr__(self, name):
		self.__check_private(name, "attribute '%s' of '%s' objects cannot be
removed" %(name, self.__class__.__name__))
		self.__dict__.pop(name)

	def __set__(self, instance, value):
		self.__check_private(instance, "You cannot remap the method '%s'" %
(instance))
		self.__dict__[instance] = value



I then implement this by creating a subclass of the read only class:

class MyClass(ReadOnly):
	def __init__(self, x):
		self.set_x(x)

	def get_x(self):
		return self.__x

	def set_x(self, x):
		print 'Hello the setter was called!'
		self.__x = x


What I want is to be able to auto-call the set_ methods whenever
someone tries to call a method that has a setter.  This could be done
by each class... tedious!  I want automation!  To do this I have tried
adding a list of setters to the metaclass and then in the __set__ and
__setattr__ methods I check to see if 'set_%s' %(variable) exists in
the list... if it does I call the method.  This would work, however
there are two lists of setters (in the example above), the ReadOnly
list and a MyClass list.  When you print out a dir(self) IN the
ReadOnly class from an implementation (MyClass) it will show the
MyClass attributes, however they cannot be called from the parent
class... so my real question... how can you (or can you ever) call a
child method from a parent class without explicitly passing the
callable?

I hope this hasn't been too confusing... or made your head hurt like
mine does...  If you want more code examples of what I have tried and
the out put... I'd be happy to give them.

Greg







More information about the Python-list mailing list