国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

把項(xiàng)目從Python2.x移植到Python3.x的經(jīng)驗(yàn)總結(jié)

來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 14:39:30
文檔

把項(xiàng)目從Python2.x移植到Python3.x的經(jīng)驗(yàn)總結(jié)

把項(xiàng)目從Python2.x移植到Python3.x的經(jīng)驗(yàn)總結(jié):經(jīng)歷移植jinja2到python3的痛苦之后,我把項(xiàng)目暫時(shí)放一放,因?yàn)槲遗麓蚱苝ython3的兼容。我的做法是只用一個(gè)python2的代碼庫(kù),然后在安裝的時(shí)候用2to3工具翻譯成python3。不幸的是哪怕一點(diǎn)點(diǎn)的改動(dòng)都會(huì)打破迭代開(kāi)發(fā)。如果你選對(duì)了python的版本,你可以專
推薦度:
導(dǎo)讀把項(xiàng)目從Python2.x移植到Python3.x的經(jīng)驗(yàn)總結(jié):經(jīng)歷移植jinja2到python3的痛苦之后,我把項(xiàng)目暫時(shí)放一放,因?yàn)槲遗麓蚱苝ython3的兼容。我的做法是只用一個(gè)python2的代碼庫(kù),然后在安裝的時(shí)候用2to3工具翻譯成python3。不幸的是哪怕一點(diǎn)點(diǎn)的改動(dòng)都會(huì)打破迭代開(kāi)發(fā)。如果你選對(duì)了python的版本,你可以專

經(jīng)歷移植jinja2到python3的痛苦之后,我把項(xiàng)目暫時(shí)放一放,因?yàn)槲遗麓蚱苝ython3的兼容。我的做法是只用一個(gè)python2的代碼庫(kù),然后在安裝的時(shí)候用2to3工具翻譯成python3。不幸的是哪怕一點(diǎn)點(diǎn)的改動(dòng)都會(huì)打破迭代開(kāi)發(fā)。如果你選對(duì)了python的版本,你可以專心做事,幸運(yùn)的避免了這個(gè)問(wèn)題。

來(lái)自MoinMoin項(xiàng)目的Thomas Waldmann通過(guò)我的python-modernize跑jinja2,并且統(tǒng)一了代碼庫(kù),能同時(shí)跑python2,6,2,7和3.3。只需小小清理,我們的代碼就很清晰,還能跑在所有的python版本上,并且看起來(lái)和普通的python代碼并無(wú)區(qū)別。

受到他的啟發(fā),我一遍又一遍的閱讀代碼,并開(kāi)始合并其他代碼來(lái)享受統(tǒng)一的代碼庫(kù)帶給我的快感。

下面我分享一些小竅門,可以達(dá)到和我類似的體驗(yàn)。

放棄python 2.5 3.1和3.2

這是最重要的一點(diǎn),放棄2.5比較容易,因?yàn)楝F(xiàn)在基本沒(méi)人用了,放棄3.1和3.2也沒(méi)太大問(wèn)題,應(yīng)為目前python3用的人實(shí)在是少得可憐。但是你為什么放棄這幾個(gè)版本呢?答案就是2.6和3.3有很多交叉哦語(yǔ)法和特性,代碼可以兼容這兩個(gè)版本。

  • 字符串兼容。2.6和3.3支持相同的字符串語(yǔ)法。你可以用 "foo" 表示原生字符串(2.x表示byte,3.x表示unicode),u"foo" 表示unicode字符串,b"foo" 表示原生字符串或字節(jié)數(shù)組。

  • print函數(shù)兼容,如果你的print語(yǔ)句比較少,那你可以加上"from __future__ import print_function",然后開(kāi)始使用print函數(shù),而不是把它綁定到別的變量上,進(jìn)而避免詭異的麻煩。

  • 兼容的異常語(yǔ)法。Python 2.6引入的 "except Exception as e" 語(yǔ)法也是3.x的異常捕捉語(yǔ)法。

  • 類修飾器都有效。這個(gè)可以用在修改接口而不在類結(jié)構(gòu)定義中留下痕跡。例如可以修改迭代方法名字,也就是把 next 改成 __next__ 或者把 __str__ 改成 __unicode__ 來(lái)兼容python 2.x。

  • 內(nèi)置next調(diào)用__next__或next。這點(diǎn)很有用,因?yàn)樗麄兒椭苯诱{(diào)用方法的速度差不多,所以你不用考慮得太多而去加入運(yùn)行時(shí)檢查和包裝一個(gè)函數(shù)。

  • Python 2.6 加入了和python 3.3接口一樣的bytearray類型。這點(diǎn)也很有用,因?yàn)?.6沒(méi)有 3.3的byteobject類型,雖然有一個(gè)內(nèi)建的名字但那僅僅只是str的別名,并且使用習(xí)慣也有很大差異。

  • Python 3.3又加入了byte到byte和string到string的編碼與解碼,這已經(jīng)在3.1和3.2中去掉了,很不幸,他們的接口很復(fù)雜了,別名也沒(méi)了,但至少更比以前的2.x版本更接近了。

  • 最后一點(diǎn)在流編碼和解碼的時(shí)候很有用,這功能在3.0的時(shí)候去掉了,直到3.3才恢復(fù)。


    沒(méi)錯(cuò),six模塊可以讓你走得遠(yuǎn)一點(diǎn),但是不要低估了代碼工整度的意義。在Python3移植過(guò)程中,我?guī)缀鯇?duì)jinja2失去了興趣,因?yàn)榇a開(kāi)始虐我。就算能統(tǒng)一代碼庫(kù),但還是看起來(lái)很不舒服,影響視覺(jué)(six.b('foo')和six.u('foo')到處飛)還會(huì)因?yàn)橛?to3迭代開(kāi)發(fā)帶來(lái)不必要的麻煩。不用去處理這些麻煩,回到編碼的快樂(lè)享受中吧。jinja2現(xiàn)在的代碼非常清晰,你也不用當(dāng)心python2和3的兼容問(wèn)題,不過(guò)還是有一些地方使用了這樣的語(yǔ)句:if PY2:。

    接下來(lái)假設(shè)這些就是你想支持的python版本,試圖支持python2.5,這是一個(gè)痛苦的事情,我強(qiáng)烈建議你放棄吧。支持3.2還有一點(diǎn)點(diǎn)可能,如果你能在把函數(shù)調(diào)用時(shí)把字符串都包裝起來(lái),考慮到審美和性能,我不推薦這么做。

    跳過(guò)six

    six是個(gè)好東西,jinja2開(kāi)始也在用,不過(guò)最后卻不給力了,因?yàn)橐浦驳絧ython3的確需要它,但還是有一些特性丟失了。你的確需要six,如果你想同時(shí)支持python2.5,但從2.6開(kāi)始就沒(méi)必要使用six了,jinja2搞了一個(gè)包含助手的兼容模塊。包括很少的非python3 代碼,整個(gè)兼容模塊不足80行。

    因?yàn)槠渌麕?kù)或者項(xiàng)目依賴庫(kù)的原因,用戶希望你能支持不同版本,這是six的確能為你省去很多麻煩。

    開(kāi)始使用Modernize

    使用python-modernize移植python是個(gè)很好的還頭,他像2to3一樣運(yùn)行的時(shí)候生成代碼。當(dāng)然,他還有很多bug,默認(rèn)選項(xiàng)也不是很合理,可以避免一些煩人的事情,然你走的更遠(yuǎn)。但是你也需要檢查一下結(jié)果,去掉一些import 語(yǔ)句和不和諧的東西。
    修復(fù)測(cè)試

    做其他事之前先跑一下測(cè)試,保證測(cè)試還能通過(guò)。python3.0和3.1的標(biāo)準(zhǔn)庫(kù)就有很多問(wèn)題是詭異的測(cè)試習(xí)慣改變引起的。

    寫(xiě)一個(gè)兼容的模塊

    因此你將打算跳過(guò)six,你能夠完全拋離幫助文檔么?答案當(dāng)然是否定的。你依然需要一個(gè)小的兼容模塊,但是它足夠小,使得你能夠?qū)⑺鼉H僅放在你的包中,下面是一個(gè)基本的例子,關(guān)于一個(gè)兼容模塊看起來(lái)是個(gè)什么樣子:

    import sys
    PY2 = sys.version_info[0] == 2
    if not PY2:
     text_type = str
     string_types = (str,)
     unichr = chr
    else:
     text_type = unicode
     string_types = (str, unicode)
     unichr = unichr

    那個(gè)模塊確切的內(nèi)容依賴于,對(duì)于你有多少實(shí)際的改變。在Jinja2中,我在這里放了一堆的函數(shù)。它包括ifilter, imap以及類似itertools的函數(shù),這些函數(shù)都內(nèi)置在3.x中。(我糾纏Python 2.x函數(shù),是為了讓讀者能夠?qū)Υa更清楚,迭代器行為是內(nèi)置的而不是缺陷) 。

    為2.x版本做測(cè)試而不是3.x

    總體上來(lái)說(shuō)你現(xiàn)在正在使用的python是2.x版本的還是3.x版本的是需要檢查的。在這種情況下我推薦你檢查當(dāng)前版本是否是python2而把python3放到另外一個(gè)判斷的分支里。這樣等python4面世的時(shí)候你收到的“驚喜”對(duì)你的影響會(huì)小一點(diǎn)

    好的處理:

    if PY2:
     def __str__(self):
     return self.__unicode__().encode('utf-8')

    相比之下差強(qiáng)人意的處理:

    if not PY3:
     def __str__(self):
     return self.__unicode__().encode('utf-8')

    字符串處理
    Python 3的最大變化毫無(wú)疑問(wèn)是對(duì)Unicode接口的更改。不幸的是,這些更改在某些地方非常的痛苦,而且在整個(gè)標(biāo)準(zhǔn)庫(kù)中還得到了不一致地處理。大多數(shù)與字符串處理相關(guān)的時(shí)間函數(shù)的移植將完全被廢止。字符串處理這個(gè)主題本身就可以寫(xiě)成完整的文檔,不過(guò)這兒有移植Jinja2和Werkzeug所遵循的簡(jiǎn)潔小抄:

    'foo'這種形式的字符串總指的是本機(jī)字符串。這種字符串可以用在標(biāo)識(shí)符里、源代碼里、文件名里和其他底層的函數(shù)里。另外,在2.x里,只要限制這種字符串僅僅可使用ASCII字符,那么就允許作為Unicode字符串常量。
    這個(gè)屬性對(duì)統(tǒng)一編碼基礎(chǔ)是非常有用的,因?yàn)镻ython 3的正常方向時(shí)把Unicode引進(jìn)到以前不支持Unicode的某些接口,不過(guò)反過(guò)來(lái)卻從不是這樣的。由于這種字符串常量“升級(jí)”為Unicode,而2.x仍然在某種程度上支持Unicode,因此這種字符串常量怎么用都行。
    例如 datetime.strftime函數(shù)在Python2里嚴(yán)格不支持Unicode,并且只在3.x里支持Unicode。不過(guò)因?yàn)榇蠖鄶?shù)情況下2.x上的返回值只是ASCII編碼,所以像這樣的函數(shù)在2.x和3.x上都確實(shí)運(yùn)行良好。

     >>> u'Current time: %s' % datetime.datetime.utcnow().strftime('%H:%M')
     u'Current time: 23:52'

    傳遞給strftime的字符串是本機(jī)字符串(在2.x里是字節(jié),而在3.0里是Unicode)。返回值也是本機(jī)字符串并且僅僅是ASCII編碼字符。 因此在2.x和3.x上一旦對(duì)字符串進(jìn)行格式化,那么結(jié)果就一定是Unicode字符串。
    u'foo'這種形式的字符串總指的是Unicode字符串,2.x的許多庫(kù)都已經(jīng)有非常好的支持Unicode,因此這樣的字符串常量對(duì)許多人來(lái)說(shuō)都不應(yīng)該感到奇怪。

    b'foo'這種形式的字符串總指的是只以字節(jié)形式存儲(chǔ)的字符串。由于2.6確實(shí)沒(méi)有類似Python 3.3所具有的字節(jié)對(duì)象,而且Python 3.3缺乏一個(gè)真正的字節(jié)字符串,因此這種常量的可用性確實(shí)受到小小的限制。當(dāng)與在2.x和3.x上具有同樣接口的字節(jié)數(shù)組對(duì)象綁定在一起時(shí)候,它立刻變得更可用了。
    由于這種字符串是可以更改的,因此對(duì)原始字節(jié)的更改是非常有效的,然后你再次通過(guò)使用inbytes()封裝最終結(jié)果,從而轉(zhuǎn)換結(jié)果為更易讀的字符串。

    除了這些基本的規(guī)則,我還對(duì)上面我的兼容模塊添加了 text_type,unichr 和 string_types 等變量。通過(guò)這些有了大的變化:

  • isinstance(x, basestring) 變成 isinstance(x, string_types).

  • isinstance(x, unicode) 變成 isinstance(x, text_type).

  • isinstance(x, str) 為表明捕捉字節(jié)的意圖,現(xiàn)在變成 isinstance(x, bytes) 或者 isinstance(x, (bytes, bytearray)).

  • 我還創(chuàng)建了一個(gè) implements_to_string 裝飾類,來(lái)幫助實(shí)現(xiàn)帶有 __unicode__ 或 __str__ 的方法的類:

    if PY2:
     def implements_to_string(cls):
     cls.__unicode__ = cls.__str__
     cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
     return cls
    else:
     implements_to_string = lambda x: x

    這個(gè)想法是,你只要按2.x和3.x的方式實(shí)現(xiàn) __str__,讓它返回Unicode字符串(是的,在2.x里看起來(lái)有點(diǎn)奇怪),裝飾類在2.x里會(huì)自動(dòng)把它重命名為 __unicode__,然后添加新的 __str__ 來(lái)調(diào)用 __unicode__ 并把其返回值用 UTF-8 編碼再返回。在過(guò)去,這種模式在2.x的模塊中已經(jīng)相當(dāng)普遍。例如 Jinja2 和 Django 中都這樣用。

    下面是一個(gè)這種用法的實(shí)例:

    @implements_to_string
    class User(object):
     def __init__(self, username):
     self.username = username
     def __str__(self):
     return self.username

    元類語(yǔ)法的更改
    由于Python 3更改了定義元類的語(yǔ)法,并且以一種不兼容的方式調(diào)用元類,所以這使移植比未更改時(shí)稍稍難了些。Six有一個(gè)with_metaclass函數(shù)可以解決這個(gè)問(wèn)題,不過(guò)它在繼承樹(shù)中產(chǎn)生了一個(gè)虛擬類。對(duì)Jinjia2移植來(lái)說(shuō),這個(gè)解決方案令我非常 的不舒服,我稍稍地對(duì)它進(jìn)行了修改。這樣對(duì)外的API是相同的,只是這種方法使用臨時(shí)類與元類相連接。 好處是你使用它時(shí)不必?fù)?dān)心性能會(huì)受影響并且讓你的繼承樹(shù)保持得很完美。
    這樣的代碼理解起來(lái)有一點(diǎn)難。 基本的理念是利用這種想法:元類可以自定義類的創(chuàng)建并且可由其父類選擇。這個(gè)特殊的解決方法是用元類在創(chuàng)建子類的過(guò)程中從繼承樹(shù)中刪除自己的父類。最終的結(jié)果是這個(gè)函數(shù)創(chuàng)建了帶有虛擬元類的虛擬類。一旦完成創(chuàng)建虛擬子類,就可以使用虛擬元類了,并且這個(gè)虛擬元類必須有從原始父類和真正存在的元類創(chuàng)建新類的構(gòu)造方法。這樣的話,既是虛擬類又是虛擬元類的類從不會(huì)出現(xiàn)。
    這種解決方法看起來(lái)如下:

    def with_metaclass(meta, *bases):
     class metaclass(meta):
     __call__ = type.__call__
     __init__ = type.__init__
     def __new__(cls, name, this_bases, d):
     if this_bases is None:
     return type.__new__(cls, name, (), d)
     return meta(name, bases, d)
     return metaclass('temporary_class', None, {})
    下面是你如何使用它:
     
    class BaseForm(object):
     pass
     
    class FormType(type):
     pass
     
    class Form(with_metaclass(FormType, BaseForm)):
     pass

    字典
    Python 3里更令人懊惱的更改之一就是對(duì)字典迭代協(xié)議的更改。Python2里所有的字典都具有返回列表的keys()、values()和items(),以及返回迭代器的iterkeys(),itervalues()和iteritems()。在Python3里,上面的任何一個(gè)方法都不存在了。相反,這些方法都用返回視圖對(duì)象的新方法取代了。

    keys()返回鍵視圖,它的行為類似于某種只讀集合,values()返回只讀容器并且可迭代(不是一個(gè)迭代器!),而items()返回某種只讀的類集合對(duì)象。然而不像普通的集合,它還可以指向易更改的對(duì)象,這種情況下,某些方法在運(yùn)行時(shí)就會(huì)遇到失敗。

    站在積極的一方面來(lái)看,由于許多人沒(méi)有理解視圖不是迭代器,所以在許多情況下,你只要忽略這些就可以了。
    Werkzeug和Dijango實(shí)現(xiàn)了大量自定義的字典對(duì)象,并且在這兩種情況下,做出的決定僅僅是忽略視圖對(duì)象的存在,然后讓keys()及其友元返回迭代器。

    由于Python解釋器的限制,這就是目前可做的唯一合理的事情了。不過(guò)存在幾個(gè)問(wèn)題:

  • 視圖本身不是迭代器這個(gè)事實(shí)意味著通常狀況下你沒(méi)有充足的理由創(chuàng)建臨時(shí)對(duì)象。

  • 內(nèi)置字典視圖的類集合行為在純Python里由于解釋器的限制不可能得到復(fù)制。

  • 3.x視圖的實(shí)現(xiàn)和2.x迭代器的實(shí)現(xiàn)意味著有大量重復(fù)的代碼。

  • 下面是Jinja2編碼庫(kù)常具有的對(duì)字典進(jìn)行迭代的情形:

    if PY2:
     iterkeys = lambda d: d.iterkeys()
     itervalues = lambda d: d.itervalues()
     iteritems = lambda d: d.iteritems()
    else:
     iterkeys = lambda d: iter(d.keys())
     itervalues = lambda d: iter(d.values())
     iteritems = lambda d: iter(d.items())

    為了實(shí)現(xiàn)類似對(duì)象的字典,類修飾符再次成為可行的方法:

    if PY2:
     def implements_dict_iteration(cls):
     cls.iterkeys = cls.keys
     cls.itervalues = cls.values
     cls.iteritems = cls.items
     cls.keys = lambda x: list(x.iterkeys())
     cls.values = lambda x: list(x.itervalues())
     cls.items = lambda x: list(x.iteritems())
     return cls
    else:
     implements_dict_iteration = lambda x: x

    在這種情況下,你需要做的一切就是把keys()和友元方法實(shí)現(xiàn)為迭代器,然后剩余的會(huì)自動(dòng)進(jìn)行:

    @implements_dict_iteration
    class MyDict(object):
     ...
     
     def keys(self):
     for key, value in iteritems(self):
     yield key
     
     def values(self):
     for key, value in iteritems(self):
     yield value
     
     def items(self):
     ...

    通用迭代器的更改
    由于一般性地更改了迭代器,所以需要一丁點(diǎn)的幫助就可以使這種更改毫無(wú)痛苦可言。真正唯一的更改是從next()到__next__的轉(zhuǎn)換。幸運(yùn)的是這個(gè)更改已經(jīng)經(jīng)過(guò)透明化處理。 你唯一真正需要更改的事情是從x.next()到next(x)的更改,而且剩余的事情由語(yǔ)言來(lái)完成。

    如果你計(jì)劃定義迭代器,那么類修飾符再次成為可行的方法了:

    if PY2:
     def implements_iterator(cls):
     cls.next = cls.__next__
     del cls.__next__
     return cls
    else:
     implements_iterator = lambda x: x
    為了實(shí)現(xiàn)這樣的類,只要在所有的版本里定義迭代步長(zhǎng)方法__next__就可以了:
     
    @implements_iterator
    class UppercasingIterator(object):
     def __init__(self, iterable):
     self._iter = iter(iterable)
     def __iter__(self):
     return self
     def __next__(self):
     return next(self._iter).upper()

    轉(zhuǎn)換編解碼器
    Python 2編碼協(xié)議的優(yōu)良特性之一就是它不依賴于類型。 如果你愿意把csv文件轉(zhuǎn)換為numpy數(shù)組的話,那么你可以注冊(cè)一個(gè)這樣的編碼器。然而自從編碼器的主要公共接口與字符串對(duì)象緊密關(guān)聯(lián)后,這個(gè)特性不再為眾人所知。由于在3.x里轉(zhuǎn)換的編解碼器變得更為嚴(yán)格,所以許多這樣的功能都被刪除了,不過(guò)后來(lái)由于證明轉(zhuǎn)換編解碼有用,在3.3里重新引入了。基本上來(lái)說(shuō),所有Unicode到字節(jié)的轉(zhuǎn)換或者相反的轉(zhuǎn)換的編解碼器在3.3之前都不可用。hex和base64編碼就位列與這些編解碼的之中。

    下面是使用這些編碼器的兩個(gè)例子:一個(gè)是字符串上的操作,一個(gè)是基于流的操作。前者就是2.x里眾所周知的str.encode(),不過(guò),如果你想同時(shí)支持2.x和3.x,那么由于更改了字符串API,現(xiàn)在看起來(lái)就有些不同了:

    >>> import codecs
    >>> codecs.encode(b'Hey!', 'base64_codec')
    'SGV5IQ==
    '

    同樣,你將注意到在3.3里,編碼器不理解別名,要求你書(shū)寫(xiě)編碼別名為"base64_codec"而不是"base64"。

    (我們優(yōu)先選擇這些編解碼器而不是選擇binascii模塊里的函數(shù),因?yàn)橥ㄟ^(guò)對(duì)這些編碼器增加編碼和解碼,就可以支持所增加的編碼基于流的操作。)

    其他注意事項(xiàng)
    仍然有幾個(gè)地方我尚未有良好的解決方案,或者說(shuō)處理這些地方常常令人懊惱,不過(guò)這樣的地方會(huì)越來(lái)越少。不幸是的這些地方的某些現(xiàn)在已經(jīng)是Python 3 API的一部分,并且很難被發(fā)現(xiàn),直到你觸發(fā)一個(gè)邊緣情形的時(shí)候才能發(fā)現(xiàn)它。

    在Linux上處理文件系統(tǒng)和文件IO訪問(wèn)仍然令人懊惱,因?yàn)樗皇腔赨nicode的。Open()函數(shù)和文件系統(tǒng)的層都有危險(xiǎn)的平臺(tái)指定的缺省選項(xiàng)。例如,如果我從一臺(tái)de_AT的機(jī)器SSH到一臺(tái)en_US機(jī)器,那么Python對(duì)文件系統(tǒng)和文件操作就喜歡回退到ASCII編碼上。

    我注意到通常Python3上對(duì)文本操作最可靠的同時(shí)也在2.x正常工作的方法是僅僅以二進(jìn)制模式打開(kāi)文件,然后顯式地進(jìn)行解碼。另外,你也可以使用2.x上的codec.open或者io.open函數(shù),以及Python 3上內(nèi)置的帶有編碼參數(shù)的Open函數(shù)。

    標(biāo)準(zhǔn)庫(kù)里的URL不能用Unicode正確地表示,這使得一些URL在3.x里不能被正確的處理。

    由于更改了語(yǔ)法,所以追溯對(duì)象產(chǎn)生的異常需要輔助函數(shù)。通常來(lái)說(shuō)這非常罕見(jiàn),而且很容易處理。下面是由于更改了語(yǔ)法所遇到的情形之一,在這種情況下,你將不得不把代碼移到exec塊里。

     if PY2:
     exec('def reraise(tp, value, tb):
     raise tp, value, tb')
     else:
     def reraise(tp, value, tb):
     raise value.with_traceback(tb)

    如果你有部分代碼依賴于不同的語(yǔ)法的話,那么通常來(lái)說(shuō)前面的exec技巧是非常有用的。不過(guò)現(xiàn)在由于exec本身就有不同的語(yǔ)法,所以你不能用它來(lái)執(zhí)行任何命名空間上的操作。下面給出的代碼段不會(huì)有大問(wèn)題,因?yàn)榘裞ompile用做嵌入函數(shù)的eval可運(yùn)行在兩個(gè)版本上。另外你可以通過(guò)exec本身啟動(dòng)一個(gè)exec函數(shù)。

    exec_ = lambda s, *a: eval(compile(s, '', 'exec'), *a)

    如果你在Python C API上書(shū)寫(xiě)了C模塊,那么自殺吧。從我知道那刻起到仙子仍然沒(méi)有工具可處理這個(gè)問(wèn)題,而且許多東西都已經(jīng)更改了。借此機(jī)會(huì)放棄你構(gòu)造模塊所使用的這種方法,然后在cffi或者ctypes上重新書(shū)寫(xiě)模塊。如果這種方法還不行的話,因?yàn)槟阌悬c(diǎn)頑固,那么只有接受這樣的痛苦。也許試著在C預(yù)處理器上書(shū)寫(xiě)某些令人討厭的事可以使移植更容易些。

    使用Tox來(lái)進(jìn)行本地測(cè)試。能夠立刻在所有Python版本上運(yùn)行你的測(cè)試是非常有益的,這將為你找到許多問(wèn)題。

    展望

    統(tǒng)一2.x和3.x的基本編碼庫(kù)現(xiàn)在確實(shí)可以開(kāi)始了。移植的大量時(shí)間仍然將花費(fèi)在試圖解決有關(guān)Unicode以及與其他可能已經(jīng)更改了自身API的模塊交互時(shí)API是如何操作上。無(wú)論如何,如果你打算考慮移植庫(kù)的話,那么請(qǐng)不要觸碰2.5以下的版本、3.0-3.2版本,這樣的話將不會(huì)對(duì)版本造成太大的傷害。

    聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    把項(xiàng)目從Python2.x移植到Python3.x的經(jīng)驗(yàn)總結(jié)

    把項(xiàng)目從Python2.x移植到Python3.x的經(jīng)驗(yàn)總結(jié):經(jīng)歷移植jinja2到python3的痛苦之后,我把項(xiàng)目暫時(shí)放一放,因?yàn)槲遗麓蚱苝ython3的兼容。我的做法是只用一個(gè)python2的代碼庫(kù),然后在安裝的時(shí)候用2to3工具翻譯成python3。不幸的是哪怕一點(diǎn)點(diǎn)的改動(dòng)都會(huì)打破迭代開(kāi)發(fā)。如果你選對(duì)了python的版本,你可以專
    推薦度:
    標(biāo)簽: 項(xiàng)目 python 移植
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 久久免费视频网站 | 亚洲另类欧美日韩 | 91情侣在线偷精品国产 | 欧美日韩成人在线视频 | 五月婷婷啪啪 | 欧美日韩成人午夜免费 | 伊人激情网 | 日本成人久久 | 欧美激情影音先锋 | 欧美日韩精品高清一区二区 | 亚洲欧美在线观看视频 | 国产日产精品_国产精品毛片 | 国产精品视频免费观看 | 国产中文字幕视频 | 亚洲精品乱码久久久久 | 日韩高清第一页 | 在线国产一区二区 | 欧美1页| 亚洲欧洲一区 | 91精品国产9l久久久久 | 99久久精品免费看国产 | 日本成人一级 | 国产v精品成人免费视频400条 | 精品国产一区二区三区19 | 欧美在线一区视频 | 亚洲精品福利在线观看 | 亚洲色图欧美激情 | 免费在线国产视频 | 日本不卡一区二区三区四区 | 国产网站免费观看 | 亚洲色图88 | 国产亚洲欧美在线人成aaaa | 欧美国产日韩一区二区三区 | 在线观看色网站 | 久久久久久国产精品视频 | 波多野的店 | 亚洲欧洲精品成人久久曰 | 日本黄 色 成 年 人免费观看 | 毛片1级| 精品国产日韩亚洲一区91 | 在线国产视频观看 |