2015-02-24 77 views
3

我有一個非常大的Python 2.7.6項目,我需要將其轉換爲Python 3.4。我用2to3腳本,但'元類'處理似乎被打破。使用元類將Python2轉換爲Python3導致錯誤流程

我過濾了代碼以縮短並查明問題。

class Base(object): 
    class __metaclass__(type): 
     def __new__(cls, classname, bases, dict): 
      new = type.__new__(cls, classname, bases, dict) 
      new.classname = classname 
      print ("Base::__metaclass__::new. Called.") 
      return new     

class Heir(Base): 
    class __metaclass__(Base.__metaclass__): 
     def __new__(self, *args): 
      new = Base.__metaclass__.__new__(self, *args) 
      print ("Heir::__metaclass__::new. Called.") 
      return new 

    @classmethod 
    def define(cls, nexttype): 
     print ("Heir::define. Called.") 

class HeirOfHeir(Heir): 
    pass 

Heir.define(HeirOfHeir) 

代碼打印效果與預期:

Base::__metaclass__::new. Called. 
Base::__metaclass__::new. Called. 
Heir::__metaclass__::new. Called. 
Base::__metaclass__::new. Called. 
Heir::__metaclass__::new. Called. 
Heir::define. Called. 

但與Python 3.4中運行的代碼時,我只有最後一次打印:

Heir::define. Called. 
下面的片段與Python 2.7.6效果很好

2to3錯誤計算或需要一些手動工作。不幸的是,我對元類沒有多少經驗。

回答

7

你原來的代碼使用的事實,這是__metaclass__在類體內被用作元類,但2to3定影液只查找直分配

__metaclass__ = MetaClassName 

,而不是class __metaclass__聲明或其他定義名稱的方式(from somemodule import MetaClassName as __metaclass__將在Python 2類主體中工作,而2to3也會錯過)。

您可以通過移動元類解決這個問題分開class定義:

class BaseMeta(type): 
    def __new__(cls, classname, bases, dict): 
     new = type.__new__(cls, classname, bases, dict) 
     new.classname = classname 
     print ("BaseMeta::new. Called.") 
     return new     

class Base(object): 
    __metaclass__ = BaseMeta 

class HeirMeta(BaseMeta): 
    def __new__(self, *args): 
     new = BaseMeta.__new__(self, *args) 
     print ("HeirMeta::new. Called.") 
     return new 

class Heir(Base):  
    __metaclass__ = HeirMeta 

    @classmethod 
    def define(cls, nexttype): 
     print ("Heir::define. Called.") 

class HeirOfHeir(Heir): 
    pass 

Heir.define(HeirOfHeir) 

做到這一點在Python 3 反正定義元類,作爲機制來定義元類改爲在之前確定元類而不是在期間運行類體(以便元類也可以影響該步驟)。

現在2to3將正確地檢測到存在於你的班__metaclass__屬性和重寫那些使用新的Python 3語法:

stackoverflow-2.7 $ bin/python -m lib2to3 fixed.py 
RefactoringTool: Skipping implicit fixer: buffer 
RefactoringTool: Skipping implicit fixer: idioms 
RefactoringTool: Skipping implicit fixer: set_literal 
RefactoringTool: Skipping implicit fixer: ws_comma 
RefactoringTool: Refactored fixed.py 
--- fixed.py (original) 
+++ fixed.py (refactored) 
@@ -5,8 +5,8 @@ 
     print ("BaseMeta::new. Called.") 
     return new     

-class Base(object): 
- __metaclass__ = BaseMeta 
+class Base(object, metaclass=BaseMeta): 
+ pass 

class HeirMeta(BaseMeta): 
    def __new__(self, *args): 
@@ -14,9 +14,7 @@ 
     print ("HeirMeta::new. Called.") 
     return new 

-class Heir(Base):  
- __metaclass__ = HeirMeta 
- 
+class Heir(Base, metaclass=HeirMeta):  
    @classmethod 
    def define(cls, nexttype): 
     print ("Heir::define. Called.") 
RefactoringTool: Files that need to be modified: 
RefactoringTool: fixed.py 

和重構的代碼按預期工作:

stackoverflow-2.7 $ bin/python -m lib2to3 -o ../stackoverflow-3.4 -nw --no-diffs fixed.py 
lib2to3.main: Output in '../stackoverflow-3.4' will mirror the input directory '' layout. 
RefactoringTool: Skipping implicit fixer: buffer 
RefactoringTool: Skipping implicit fixer: idioms 
RefactoringTool: Skipping implicit fixer: set_literal 
RefactoringTool: Skipping implicit fixer: ws_comma 
RefactoringTool: Refactored fixed.py 
RefactoringTool: Writing converted fixed.py to ../stackoverflow-3.4/fixed.py. 
RefactoringTool: Files that were modified: 
RefactoringTool: fixed.py 
stackoverflow-2.7 $ cd ../stackoverflow-3.4 
stackoverflow-3.4 $ bin/python -V 
Python 3.4.2 
stackoverflow-3.4 $ bin/python fixed.py 
BaseMeta::new. Called. 
BaseMeta::new. Called. 
HeirMeta::new. Called. 
BaseMeta::new. Called. 
HeirMeta::new. Called. 
Heir::define. Called. 
+0

我還建議第六單元(https://pythonhosted.org/six/)用於編寫與Py2和Py3兼容的代碼。在這種情況下,你只需要在class Heir定義之前使用'@ six.add_metaclass(HeirMeta)'裝飾器。 – 2015-02-24 14:25:09

+0

我無法使用任何編碼範例,因爲整個項目非常龐大,需要太多時間才能使其兼容2/3。但是我有大約12-15個模塊,只有元類,我會嘗試採用上述方法。 – OGP 2015-02-25 04:56:42

相關問題