RELEASED Python 2.4, alpha 2

Heiko Wundram heikowu at ceosg.de
Thu Aug 5 18:51:08 CEST 2004


Am Donnerstag, 5. August 2004 18:29 schrieb Christopher T King:
> They purport to solve the problems of function type declaration
> (class/static), function attributes, runtime type checking, and general
> function mangling, when each of these (save general function mangling)
> already have distinct solutions in nearly every other language.  The first
> three problems are currently implemented as hacks in Python that happen to
> fall under the category of "general function mangling".  Streamlining the
> hack is not the answer.

I don't think they try to solve all the things you state. Rather, it's only 
about general function mangling at compile time. Whatever you need to do for 
function mangling, that's up to you.

And, at least for me, as I stated elsewhere, the syntax is just fine. I've 
tried it out yesterday, porting some code to 2.4a2 which used thread locks 
extensively, and just writing a little class InstanceSynchronizer() which is 
just a Class which defines __call__ (when decorating a function) and gets the 
first parameter from the function call to acquire an instance specific lock 
is certainly the right way to go.

Think of the following: (old style)

class x(object):
	def __init__(self):
		self.lock = threading.RLock()

	def synchronized_method(self):
		self.lock.acquire()
		try:
			<bla>
		finally:
			self.lock.release()

That's just plain horrible compared to what @ decorators can do:

class x(object):
	synchronized = InstanceSynchronizer()

	@synchronized
	def synchronized_method(self):
		<bla>

Writing the InstanceSynchronizer is pretty easy too:

class InstanceSynchronizer(object):

	def __init__(self):
		self._locks = {}
		self._refs = {}

	def _delete_ref(self,ref):
		del self._locks[self._refs[id(ref)][1]]
		del self._refs[id(ref)]

	def __call__(self,f):
		def fsyn(fself,*args,**kwargs):
			try:
				lock = self._locks[id(fself)]
			except KeyError:
				lock = threading.RLock()
				fselfref = weakref.ref(fself,self._delete_ref)
				self._locks[id(fself)] = lock
				self._refs[id(fselfref)] = (fselfref,id(fself))
			lock.acquire()
			try:
				return f(fself,*args,**kwargs)
			finally:
				lock.release()
		return fsyn

This little class takes care of everything needed for instance locks. Writing 
a class that takes care of class locks for functions (in case you need to 
update class data) is easy as pie too.

class ClassSynchronizer(object):

	def __init__(self):
		self._lock = threading.RLock()

	def __call__(self,f):
		def fsyn(*args,**kwargs):
			self._lock.acquire()
			try:
				return f(*args,**kwargs)
			finally:
				self._lock.release()
		return fsyn

Now, if you have these two utility classes at your disposal, you can do the 
following:

class someobject(object):
	__instances__ = {}
	isynchronized = InstanceSynchronizer()
	csynchronized = ClassSynchronizer()

	@csynchronized
	def __init__(self):
		<work on self.__instances__>

	@isynchronized
	@csynchronized
	def do_something(self):
		<work on self.__instances__ and on self>

	@isynchronized
	def do_somethingelse(self):
		<work only on self>

Now tell me that using decorators to do synchronization isn't a lot easier to 
read than the first (old) example is, and also less error-prone (resp. 
acquiring/releasing locks properly and without deadlocks).

Heiko.



More information about the Python-list mailing list