How to keep a function as a generator function when the yield operator is moved into its sub-functions??
weafon
weafon at lbl.gov
Wed Jul 15 12:48:49 EDT 2009
Hi DaveA,
Thank for your responses even though my problem has been solved based on
Miles' suggestion. I am writing programs by using the SimPy library,
which is a discrete-event simulator library. Below is my actual code segment
class RAID(Process):
def ReqServ(self):
while(now()<TM_End):
yield get, self, self.queue, 1
orig_req=self.got[0]
....
for devno in range (5):
...
#---- Segment A begins
new_loc= calcfunc(orig_req.loc)
new_len= calcfunc(orig_req.len)
new_req1= Req(self.cn_req, new_loc, new_len)
yield put, self, self.disks[devno].queue,[new_req]
self.cn_req+=1
new_req2= Req(self.cn_req, new_loc, new_len)
yield put, self, self.disks[devno+5].queue,[new_req]
self.cn_req+=1
#--- Segment A ends
...
In the above example, ReqServ may pause at three lines of yield and
return something. However, if I move the code segment A into a second
function as following, then ReqServ will not pause and return things
back to its caller after calling SegmentA().
class RAID(Process):
def ReqServ(self):
while(now()<TM_End):
yield get, self, self.queue, 1
orig_req=self.got[0]
....
for devno in range (5):
...
self.SegmentA(orig_req.loc,orig_req.len)
...
def SegmentA(self,loc,len):
new_loc= calcfunc(loc)
new_len= calcfunc(len)
new_req1= Req(self.cn_req, new_loc, new_len)
yield put, self, self.disks[devno].queue,[new_req]
self.cn_req+=1
new_req2= Req(self.cn_req, new_loc, new_len)
yield put, self, self.disks[devno+5].queue,[new_req]
self.cn_req+=1
Based on Miles's suggestion, we can solve the problem by using 'return'
in SegmentA() and keeping 'yield' in ReqServ(). For example,
class RAID(Process):
def ReqServ(self):
while(now()<TM_End):
yield get, self, self.queue, 1
orig_req=self.got[0]
....
for devno in range (5):
...
yield self.SegmentA(orig_req.loc,orig_req.len,0)
yield self.SegmentA(orig_req.loc,orig_req.len,5)
...
def SegmentA(self,loc,len,shiftno):
new_loc= calcfunc(loc)
new_len= calcfunc(len)
new_req= Req(self.cn_req, new_loc, new_len)
self.cn_req+=1
return put, self, self.disks[devno+shiftno].queue,[new_req]
Regards,
Weafon
Dave Angel wrote:
> weafon wrote:
>> <div class="moz-text-flowed" style="font-family: -moz-fixed">Hi guys,
>>
>> I have a question about the usage of yield. As shown in the below
>> example, in general, if there is a code segment commonly used by two
>> or more functions, we may isolate the segment into a function and
>> then call it from other functions if necessary.
>>
>> def func1():
>> ....
>> while(cond):
>> .....
>> commoncode()
>> ...
>>
>>
>> def func2():
>> ....
>> while(cond):
>> .....
>> commoncode()
>> ...
>>
>> def commoncode()
>> AAAA
>> BBBB
>> CCCC
>>
>> However, if there is a 'yield' operation in the common code segment,
>> the isolation causes that func1 and func2 become a non-generator
>> function!! Although I can prevent such an isolation by just
>> duplicating the segment in func1 and func2 to keep both of them being
>> generator functions, the code may become ugly and hard to maintain
>> particularly when coomoncode() is long.
>>
>> The problem may be resolved if I can define the commoncode() as an
>> inline function or marco. Unfortunately, inline and marco do not
>> seems to be implemented in python. Thus, how can I isolate a common
>> segment into a function when there are yield operations in the common
>> segment?
>>
>> Thanks,
>> Weafon
>>
> You are implying there's something special or unique about yield in
> this. Return has the same problem, and many other flow control
> constructs. Also, variable definitions and scoping.
>
> So you can't just copy any old bunch of adjacent lines out of two
> functions, put it into a third, and call it factoring. Give us a
> specific example you're puzzled about, and we can try to solve it.
>
> DaveA
>
More information about the Python-list
mailing list