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