2014-05-15 56 views
1

,試圖實現C-Python中的for循環試驗後,下面的功能被開發:爲什麼我的本地人不在rof之外更新?

import sys 

def rof(init, cond, post): 
    init, cond, post, context = compile(init, '<rof>', 'exec'), \ 
           compile(cond, '<rof>', 'eval'), \ 
           compile(post, '<rof>', 'exec'), \ 
           sys._getframe(1) 
    context = context.f_globals, context.f_locals 
    exec(init, *context) 
    while eval(cond, *context): 
     yield None 
     exec(post, *context) 

正如任何程序員都知道,需要被測試了新的功能,以確保它的工作原理:

設置

class Employee: 

    def __init__(self, employee_id, category, hired, salary, years): 
     vars(self).update(locals()) 

    def __repr__(self): 
     return '{}({})'.format(self.__class__.__name__, 
           ', '.join(map(repr, self))) 

    def __iter__(self): 
     yield self.employee_id 
     yield self.category 
     yield self.hired 
     yield self.salary 
     yield self.years 

database = [Employee(123, 'P', 2014, 2000, 0), 
      Employee(234, 'F', 2000, 20000, 14), 
      Employee(123, 'F', 2010, 10000, 4)] 

的代碼運行,而無需在某些情況下錯誤(如下面的一個):

試驗1

for _ in rof('a = 0', 'a < len(database)', 'a += 1'): 
    employee_id = database[a].employee_id 
    for _ in rof('b = len(database) - 1', 'b > a', 'b -= 1'): 
     if database[b].employee_id == employee_id: 
      print(database[b], 'is being removed.') 
      del database[b] 

然而,當循環是一個單獨的功能,這是行不通的。

試驗2

def remove_duplicates(database): 
    a = b = int 
    for _ in rof('a = 0', 'a < len(database)', 'a += 1'): 
     employee_id = database[a].employee_id 
     for _ in rof('b = len(database) - 1', 'b > a', 'b -= 1'): 
      if database[b].employee_id == employee_id: 
       print(database[b], 'is being removed.') 
       del database[b] 

remove_duplicates(database) 

一個錯誤,而不是(TypeError: list indices must be integers, not type)generatated。


我們都同意,這個代碼不Python的,但任何人都可以找出是什麼原因造成的問題,以及如何解決它?

+0

請問什麼原因究竟是什麼你想達到這種行爲? –

+0

請包含完整的Traceback。 – dano

+2

你想用'a = b = int'達到什麼目的?我確信這就是它的根本原因。 –

回答

3

在Python 3中,不可能在locals()中創建新的局部變量,因爲在編譯時會扣除一組局部變量。特別是如果您修改remove_duplicates以使其沒有a = b = int行,Python不會將這些名稱視爲指向本地變量,而是指向全局變量。有了這條線,他們被認爲是一個局部變量,是的。

此外,通過框架對象不可能更改局部變量,如在Python 3中,局部變量不再存儲在字典中。相反,在CPython 3上,frame.f_locals訪問使用PyFrame_FastToLocals創建變量的副本,但它通常是單向旅程。因此,儘管你可以讀取變量的值,任何更改都不會被傳播,並ab繼續is int。但是,(模塊)全局變量仍然存儲在可通過frame.f_globals直接訪問的字典中;並且字典可以隨時更改。

然而,就如何實現這一目標上的CPython 3. PyDev的維護者是a blog post因此以下rof實施似乎這樣的伎倆

def apply(frame): 
    ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame), ctypes.c_int(0)) 

def rof(init, cond, post): 
    init, cond, post, context = compile(init, '<rof>', 'exec'), \ 
           compile(cond, '<rof>', 'eval'), \ 
           compile(post, '<rof>', 'exec'), \ 
           sys._getframe(1) 

    exec(init, context.f_globals, context.f_locals) 
    apply(context) 
    while eval(cond, context.f_globals, context.f_locals): 
     apply(context) 
     yield None 
     exec(post, context.f_globals, context.f_locals) 
     apply(context) 

我認爲這是代碼所憎惡如果有的話,並建議,而不是這個,假設程序員都知道如何改變for循環爲C型爲C,而環......它從那裏成Python。無論如何,如果不在函數體內爲這些變量賦予初始值,它仍然無法工作。

因此,我提出替代rof實現:

def rof(init, cond, post): 
    print(init) 
    print('while {}:'.format(cond)) 
    print(' # code goes here') 
    print(' ' + post) 

rof('b = len(database) - 1', 'b > a', 'b -= 1') 

打印:

b = len(database) - 1 
while b > a: 
    # code goes here 
    b -= 1 

這應該是什麼反正寫的。

雖然沒有在這種情況下,有太多的錯誤:

for a in range(len(database)): 
    for b in range(len(database) - 1, a, -1): 
     ... 
+0

'list(range(10,20,-1))' - >'[]' –

相關問題