2017-02-01 47 views
1

我必須端口遺留代碼(〜60K LOC)從Python的2〜3中像下面兩三千結構:如何從Python的2端口`__slots__` 3

class Sample(object): 
    __slots__ = ('both', 'advertise') 
    class __metaclass__(type): 
     __instancecheck__ = classmethod(
       lambda cls, inst: inst in ('both', 'advertise')) 
    both = 'both' 
    advertise = 'advertise' 

這代碼工作正常使用Python 2,但是不與Python 3編譯並解決它,我需要將其更改爲

class Sample(object): 
    __slots__ = ('both', 'advertise') 
    class __metaclass__(type): 
     __instancecheck__ = classmethod(
       lambda cls, inst: inst in ('both', 'advertise')) 
    def __init__(self): 
     both = 'both' 
     advertise = 'advertise' 

什麼是處理這種變化給出一個有效的方式,它有重新上漆這麼大的文件多次?

我們必須考慮可能已經或可能不會有一個__init__函數定義已經爲類,並且也可以嵌套類定義。

這是我到目前爲止嘗試過的。

  • 2to3不認爲這是一個問題,因此不會改變它。
  • 一種可能的方法是使用ast模塊修改內存中的分析樹,然後使用unparse來回寫修改後的代碼。但這並不簡單。
  • 如果沒有其他工作,我會考慮編寫一個簡單的Shell/Python腳本,它將讀取源文件,進行更改並將其寫回。

有沒有另一個快速簡單的方法來處理這種變化。

+1

[元類已經在Python 3改變(https://docs.python.org/3/reference/datamodel.html),'__metaclass__'沒有按不再工作了。你也可以用一個共同的元類替換元類(這裏每個類都有一個),並使用'cls .__ slots __中的'lambda cls,inst:inst',這應該適用於所有類。 –

+1

你也可以用'__init__'替換__slots__中的插槽:setattr(self,slot,slot)' –

回答

2

我不知道有什麼比編寫小腳本更好的方法。我認爲這些變化足夠小,你可以用一些很好的啓發式方法逃脫,並且不需要ast的全部功能。

但是,如果你有這麼多重複的代碼,我會從你的代碼中完全刪除類。您可以用代碼生成器替換它們,或者爲這些類編寫工廠函數。這將會對將來的任何更改進行驗證。

這樣的工廠可能看起來像這樣:

class HasStringInstances(type): 
    def __instancecheck__(cls, instance): 
     return instance in cls.__slots__ 

def create_special_class(*slots): 
    class SpecialClass(object, metaclass=HasStringInstances): 
     __slots__ = slots 

     def __init__(self): 
      for slot in self.__slots__: 
       # assign name as value 
       setattr(self, slot, slot) 

    return SpecialClass 

Sample = create_special_class('both', 'advertise') 
+0

謝謝。這聽起來像是一個很好的反饋。是的,「ast」似乎對此太重了。此外,'ast.NodeVisitor'類中的節點沒有指向父節點的指針/鏈接,所以在解析樹中移動節點似乎很困難。 – ViFI