Sunday, 15 March 2015

python - Why does this function not work when used as a decorator? -



python - Why does this function not work when used as a decorator? -

update: noted mr. fooz, functional version of wrapper has bug, reverted original class implementation. i've set code on github:

https://github.com/nofatclips/timeout/commits/master

there 2 commits, 1 working (using "import" workaround) sec 1 broken.

the source of problem seems pickle#dumps function, spits out identifier when called on function. time phone call process, identifier points decorated version of function, rather original one.

original message:

i trying write function decorator wrap long task in process killed if timeout expires. came (working not elegant) version:

from multiprocessing import process threading import timer functools import partial sys import stdout def safeexecution(function, timeout): thread = none def _break(): #stdout.flush() #print (thread) thread.terminate() def start(*kw): timer = timer(timeout, _break) timer.start() thread = process(target=function, args=kw) ret = thread.start() # todo: capture homecoming value thread.join() timer.cancel() homecoming ret homecoming start def settimeout(timeout): homecoming partial(safeexecution, timeout=timeout) #@settimeout(1) def calculateprimes(maxprimes): primes = [] in range(2, maxprimes): prime = true prime in primes: if (i % prime == 0): prime = false break if (prime): primes.append(i) print ("found prime: %s" % i) if __name__ == '__main__': print (calculateprimes) = settimeout(1) calculateprime = a(calculateprimes) calculateprime(24000)

as can see, commented out decorator , assigned modified version of calculateprimes calculateprime. if tried reassign same variable, i'd "can't pickle : attribute lookup builtins.function failed" error when trying phone call decorated version.

anybody has thought of happening under hood? original function beingness turned different when assign decorated version identifier referencing it?

update: reproduce error, alter main part to

if __name__ == '__main__': print (calculateprimes) = settimeout(1) calculateprimes = a(calculateprimes) calculateprimes(24000) #sleep(2)

which yields:

traceback (most recent phone call last): file "c:\users\mm\desktop\ing.sw\python\thread2.py", line 49, in <module> calculateprimes(24000) file "c:\users\mm\desktop\ing.sw\python\thread2.py", line 19, in start ret = thread.start() file "c:\python33\lib\multiprocessing\process.py", line 111, in start self._popen = popen(self) file "c:\python33\lib\multiprocessing\forking.py", line 241, in __init__ dump(process_obj, to_child, highest_protocol) file "c:\python33\lib\multiprocessing\forking.py", line 160, in dump forkingpickler(file, protocol).dump(obj) _pickle.picklingerror: can't pickle <class 'function'>: attribute lookup builtin s.function failed traceback (most recent phone call last): file "<string>", line 1, in <module> file "c:\python33\lib\multiprocessing\forking.py", line 344, in main self = load(from_parent) eoferror

p.s. wrote class version of safeexecution, has same behaviour.

move function module that's imported script.

functions picklable in python if they're defined @ top level of module. ones defined in scripts not picklable default. module-based functions pickled 2 strings: name of module, , name of function. they're unpickled dynamically importing module looking function object name (hence restriction on top-level-only functions).

it's possible extend pickle handlers back upwards semi-generic function , lambda pickling, doing can tricky. in particular, can hard reconstruct total namespace tree if want handle things decorators , nested functions. if want this, it's best utilize python 2.7 or later or python 3.3 or later (earlier versions have bug in dispatcher of cpickle , pickle that's unpleasant work around).

is there easy way pickle python function (or otherwise serialize code)?

python: pickling nested functions

http://bugs.python.org/issue7689

edit:

at to the lowest degree in python 2.6, pickling works fine me if script contains if __name__ block, script imports calculateprimes , settimeout module, , if inner start function's name monkey-patched:

def safeexecution(function, timeout): ... def start(*kw): ... start.__name__ = function.__name__ # add together line homecoming start

there's sec problem that's related python's variable scoping rules. assignment thread variable within start creates shadow variable scope limited 1 evaluation of start function. does not assign thread variable found in enclosing scope. can't utilize global keyword override scope because want , intermediate scope , python has total back upwards manipulating local-most , global-most scopes, not intermediate ones. can overcome problem placing thread object in container that's housed in intermediate scope. here's how:

def safeexecution(function, timeout): thread_holder = [] # create container def _break(): #stdout.flush() #print (thread) thread_holder[0].terminate() # reach container def start(*kw): ... thread = process(target=function, args=kw) thread_holder.append(thread) # mutate container ... start.__name__ = function.__name__ # makes pickling work homecoming start

python multiprocessing pickle

No comments:

Post a Comment