欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

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

系統(tǒng) 1621 0

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

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

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

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

放棄python 2.5 3.1和3.2

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

  • ??? 字符串兼容。2.6和3.3支持相同的字符串語法。你可以用 "foo" 表示原生字符串(2.x表示byte,3.x表示unicode),u"foo" 表示unicode字符串,b"foo" 表示原生字符串或字節(jié)數(shù)組。
  • ??? print函數(shù)兼容,如果你的print語句比較少,那你可以加上"from __future__ import print_function",然后開始使用print函數(shù),而不是把它綁定到別的變量上,進(jìn)而避免詭異的麻煩。
  • ??? 兼容的異常語法。Python 2.6引入的 "except Exception as e" 語法也是3.x的異常捕捉語法。
  • ??? 類修飾器都有效。這個(gè)可以用在修改接口而不在類結(jié)構(gòu)定義中留下痕跡。例如可以修改迭代方法名字,也就是把 next 改成 __next__ 或者把 __str__ 改成 __unicode__ 來兼容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沒有 3.3的byteobject類型,雖然有一個(gè)內(nèi)建的名字但那僅僅只是str的別名,并且使用習(xí)慣也有很大差異。
  • ??? Python 3.3又加入了byte到byte和string到string的編碼與解碼,這已經(jīng)在3.1和3.2中去掉了,很不幸,他們的接口很復(fù)雜了,別名也沒了,但至少更比以前的2.x版本更接近了。

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


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

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

跳過six

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

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

開始使用Modernize

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

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

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

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

總體上來說你現(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的最大變化毫無疑問是對(duì)Unicode接口的更改。不幸的是,這些更改在某些地方非常的痛苦,而且在整個(gè)標(biāo)準(zhǔn)庫中還得到了不一致地處理。大多數(shù)與字符串處理相關(guān)的時(shí)間函數(shù)的移植將完全被廢止。字符串處理這個(gè)主題本身就可以寫成完整的文檔,不過這兒有移植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的某些接口,不過反過來卻從不是這樣的。由于這種字符串常量“升級(jí)”為Unicode,而2.x仍然在某種程度上支持Unicode,因此這種字符串常量怎么用都行。
??? 例如 datetime.strftime函數(shù)在Python2里嚴(yán)格不支持Unicode,并且只在3.x里支持Unicode。不過因?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的許多庫都已經(jīng)有非常好的支持Unicode,因此這樣的字符串常量對(duì)許多人來說都不應(yīng)該感到奇怪。

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


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

  • ??? 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 裝飾類,來幫助實(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里看起來有點(diǎn)奇怪),裝飾類在2.x里會(huì)自動(dòng)把它重命名為 __unicode__,然后添加新的 __str__ 來調(diào)用 __unicode__ 并把其返回值用 UTF-8 編碼再返回。在過去,這種模式在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

          

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

            
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ì)遇到失敗。

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

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

  • ??? 視圖本身不是迭代器這個(gè)事實(shí)意味著通常狀況下你沒有充足的理由創(chuàng)建臨時(shí)對(duì)象。
  • ??? 內(nèi)置字典視圖的類集合行為在純Python里由于解釋器的限制不可能得到復(fù)制。
  • ??? 3.x視圖的實(shí)現(xiàn)和2.x迭代器的實(shí)現(xiàn)意味著有大量重復(fù)的代碼。

下面是Jinja2編碼庫常具有的對(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)的幫助就可以使這種更改毫無痛苦可言。真正唯一的更改是從next()到__next__的轉(zhuǎn)換。幸運(yùn)的是這個(gè)更改已經(jīng)經(jīng)過透明化處理。 你唯一真正需要更改的事情是從x.next()到next(x)的更改,而且剩余的事情由語言來完成。

如果你計(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)格,所以許多這樣的功能都被刪除了,不過后來由于證明轉(zhuǎn)換編解碼有用,在3.3里重新引入了。基本上來說,所有Unicode到字節(jié)的轉(zhuǎn)換或者相反的轉(zhuǎn)換的編解碼器在3.3之前都不可用。hex和base64編碼就位列與這些編解碼的之中。

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

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

          

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

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

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

??? 在Linux上處理文件系統(tǒng)和文件IO訪問仍然令人懊惱,因?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)制模式打開文件,然后顯式地進(jìn)行解碼。另外,你也可以使用2.x上的codec.open或者io.open函數(shù),以及Python 3上內(nèi)置的帶有編碼參數(shù)的Open函數(shù)。

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

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

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

          

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

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

            
          

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

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

展望

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


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 亚洲欧美在线观看一区二区 | 三上悠亚2022年最新番号 | 欧美精品99毛片免费高清观看 | 老牛影视av一区二区在线观看 | 性做久久久久免费看 | 日本黄色大片免费 | 亚洲精品久久久久一区二区三 | 亚洲国产精品一区二区久久 | 亚洲精品在| 99re热精品视频 | 色洛色中文综合网站 | 黄色免费在线观看网址 | 久久精品网 | 国内精品久久久久影院老司 | 午夜影院18 | 国产精品不卡一区 | 免费国产成人α片 | 污污成人一区二区三区四区 | 一区二区视频在线 | 国产欧美一区二区视频 | 日本成人中文字幕 | 午夜神器18以下不能进免费观看 | 午夜视频免费国产在线 | 一97日本道伊人久久综合影院 | 一级视频在线播放 | 久草亚洲视频 | 欧美女人天堂 | 欧美一级特黄毛片免费 | 午夜精品久久久久久久男人的天堂 | 精品亚洲欧美高清不卡高清 | 成人永久福利在线观看不卡 | 亚洲国产成人精品女人久久久 | 色婷婷久久综合中文久久一本 | 国产97人妻人人做人碰人人爽 | 日韩av免费在线观看 | 成人亚洲欧美日韩在线 | 成年人色网站 | 国产精品亚洲视频 | 色午夜影院 | 三级在线网站 | 亚洲国产99在线精品一区二区 |