开发者

Python Generators and yield : How to know which line the program is at

开发者 https://www.devze.com 2023-04-05 09:38 出处:网络
Suppose you have a simple generator in Python like this : Update : def f(self): customFunction_1(argList_1)

Suppose you have a simple generator in Python like this :

Update :

def f(self):        
    customFunction_1(argList_1)
    yield
    customFunction_2(argList_2)
    yield
    customFunction_3(argList_3)
    yield
    ...

I call f() 开发者_StackOverflow中文版in another script like :

    h=f()
    while True:
        try:
            h.next()
            sleep(2)
        except KeyboardInterrupt:
                              ##[TODO] tell the last line in f() that was executed

Is there a way that I can do the [TODO] section above? that is knowing the last line in f() that was executed before keyboardInterrupt occurred ?


You can use enumerate() to count:

def f():

    ...
    yield
    ...
    yield
    ... 


for step, value in enumerate(f()):
    try:
        time.sleep(2)
    except KeyboardInterrupt:
        print(step) # step holds the number of the last executed function

(because in your example yield does not yield a value, value will of course be None)

Or very explicit using a verbose indication:

def f():

    ...
    yield 'first function finished'
    ...
    yield 'almost done'
    ... 


for message in f():
    try:
        time.sleep(2)
    except KeyboardInterrupt:
        print(message)


If you want to know the line number for debugging purposes then in CPython you can use h.gi_frame.f_lineno. This is the line which will be executed next and is 1-indexed. I'm not sure if this works on Python implementations other than CPython.

h=f()
while True:
    try:
        h.next()
        sleep(2)
    except KeyboardInterrupt:
        print h.gi_frame.f_lineno - 1 # f_lineno is the line to be executed next.

If you don't want to know this for debugging purposes then Remi's enumerate solution is far cleaner.


Why don't you yield i from f() and use that ?

val = h.next()


def f(self):        
    sleep(10)
    yield
    sleep(10)
    yield
    sleep(10)
    yield


h=f()
while True:
    try:
        h.next()
    except KeyboardInterrupt:
        stack_trace = sys.exc_info()[2]    # first traceback points into this function where the exception was caught
        stack_trace = stack_trace.tb_next  # now we are pointing to where it happened (in this case)
        line_no = stack_trace.tb_lineno    # and here's the line number
        del stack_trace                    # get rid of circular references

I moved the call to sleep() into f as this only works if the exception happens inside f().

0

精彩评论

暂无评论...
验证码 换一张
取 消