精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入探討 Python 的 import 機制:實現遠程導入模塊

開發 后端
所謂的模塊導入,是指在一個模塊中使用另一個模塊的代碼的操作,它有利于代碼的復用。

 所謂的模塊導入,是指在一個模塊中使用另一個模塊的代碼的操作,它有利于代碼的復用。

也許你看到這個標題,會說我怎么會發這么基礎的文章?

與此相反。恰恰我覺得這篇文章的內容可以算是 Python 的進階技能,會深入地探討并以真實案例講解 Python import Hook 的知識點。

當然為了使文章更系統、全面,前面會有小篇幅講解基礎知識點,但請你有耐心的往后讀下去,因為后面才是本篇文章的精華所在,希望你不要錯過。

1. 導入系統的基礎

1.1 導入單元構成

導入單元有多種,可以是模塊、包及變量等。

對于這些基礎的概念,對于新手還是有必要介紹一下它們的區別。

模塊:類似 *.py,*.pyc, *.pyd ,*.so,*.dll 這樣的文件,是 Python 代碼載體的最小單元。

包 還可以細分為兩種:

  •  Regular packages:是一個帶有 __init__.py  文件的文件夾,此文件夾下可包含其他子包,或者模塊
  •  Namespace packages

關于 Namespace packages,有的人會比較陌生,我這里摘抄官方文檔的一段說明來解釋一下。

Namespace packages 是由多個 部分 構成的,每個部分為父包增加一個子包。各個部分可能處于文件系統的不同位置。部分也可能處于 zip 文件中、網絡上,或者 Python 在導入期間可以搜索的其他地方。命名空間包并不一定會直接對應到文件系統中的對象;它們有可能是無實體表示的虛擬模塊。

命名空間包的 __path__ 屬性不使用普通的列表。而是使用定制的可迭代類型,如果其父包的路徑 (或者最高層級包的 sys.path) 發生改變,這種對象會在該包內的下一次導入嘗試時自動執行新的對包部分的搜索。

命名空間包沒有 parent/__init__.py 文件。實際上,在導入搜索期間可能找到多個 parent 目錄,每個都由不同的部分所提供。因此 parent/one 的物理位置不一定與 parent/two 相鄰。在這種情況下,Python 將為頂級的 parent 包創建一個命名空間包,無論是它本身還是它的某個子包被導入。

1.2 相對/絕對對導入

當我們 import 導入模塊或包時,Python 提供兩種導入方式:

  •  相對導入(relative import ):import foo.bar 或者 form foo import bar
  •  絕對導入(absolute import):from . import B 或 from ..A import B,其中.表示當前模塊,..表示上層模塊

你可以根據實際需要進行選擇,但有必要說明的是,在早期的版本( Python2.6 之前),Python 默認使用的相對導入。而后來的版本中( Python2.6 之后),都以絕對導入為默認使用的導入方式。

使用絕對路徑和相對路徑各有利弊:

  •  當你在開發維護自己的項目時,應當使用相對路徑導入,這樣可以避免硬編碼帶來的麻煩。
  •  而使用絕對路徑,會讓你模塊導入結構更加清晰,而且也避免了重名的包沖突而導入錯誤。

1.3 導入的標準寫法

在 PEP8 中有一條,對模塊的導入順序提出了要求,不同來源模塊導入,應該有清晰的界限,使用一空行來分開。

  •  import 語句應當分行書寫 
  1. # bad  
  2. import os,sys  
  3. # good  
  4. import os  
  5. import sys 
  •  import語句應當使用absolute import 
  1. # bad  
  2. from ..bar import  Bar  
  3. # good  
  4. from foo.bar import test 
  •  import語句應當放在文件頭部,置于模塊說明及docstring之后,全局變量之前
  •  import語句應該按照順序排列,每組之間用一個空格分隔,按照內置模塊,第三方模塊,自己所寫的模塊調用順序,同時每組內部按照字母表順序排列 
  1. # 內置模塊  
  2. import os  
  3. import sys  
  4. # 第三方模塊  
  5. import flask  
  6. # 本地模塊  
  7. from foo import bar 

2. __import__ 的妙用

在 Python 中使用 import 關鍵字來實現模塊/包的導入,可以說是基礎中的基礎。

但這不是唯一的方法,還有 importlib.import_module() 和 __import__() 等。

對于 __import__ ,普通的開發者,可能就會比較陌生。

和 import 不同的是,__import__ 是一個函數,也正是因為這個原因,使得 __import__ 的使用會更加靈活,常常用于框架中,對于插件的動態加載。

實際上,當我們調用 import 導入模塊時,其內部也是調用了 __import__ ,請看如下兩種導入方法,他們是等價的。 

  1. # 使用 import  
  2. import os  
  3. # 使用 __import__  
  4. os = __import__( os ) 

通過舉一反三,下面兩種方法同樣也是等價的。 

  1. # 使用 import .. as ..  
  2. import pandas as pd  
  3. # 使用 __import__  
  4. pd = __import__( pandas ) 

上面我說 __import__ 常常用于插件的動態,事實上也只有它能做到(相對于 import 來說)。

插件通常會位于某一特定的文件夾下,在使用過程中,可能你并不會用到全部的插件,也可能你會新增插件。

如果使用 import 關鍵字這種硬編碼的方式,顯然太不優雅了,當你要新增/修改插件的時候,都需要你修改代碼。更合適的做法是,將這些插件以配置的方式,寫在配置文件中,然后由代碼去讀取你的配置,動態導入你要使用的插件,即靈活又方便,也不容易出錯。

假如我的一個項目中,有 plugin01 、plugin02、plugin03 、plugin04  四個插件,這些插件下都會實現一個核心方法 run()  。但有時候我不想使用全部的插件,只想使用 plugin02、plugin04 ,那我就在配置文件中寫我要使用的兩個插件。 

  1. # my.conf  
  2. custom_plugins=[ plugin02 ,  plugin04 ] 

那我如何使用動態加載,并運行他們呢? 

  1. # main.py  
  2. for plugin in conf.custom_plugins:  
  3.     __import__(plugin)  
  4.     sys.modules[plugin].run() 

3. 理解模塊的緩存

在一個模塊內部重復引用另一個相同模塊,實際并不會導入兩次,原因是在使用關鍵字 import 導入模塊時,它會先檢索 sys.modules 里是否已經載入這個模塊了,如果已經載入,則不會再次導入,如果不存在,才會去檢索導入這個模塊。

來實驗一下,在 my_mod02 這個模塊里,我 import 兩次 my_mod01 這個模塊,按邏輯每一次 import 會一次 my_mod01 里的代碼(即打印 in mod01),但是驗證結果是,只打印了一次。 

  1. $ cat my_mod01.py              
  2. print( in mod01 )                  
  3. $ cat my_mod02.py                  
  4. import my_mod01                                         
  5. import my_mod01 
  6. $ python my_mod02.py             
  7. in mod01            

 該現象的解釋是:因為有 sys.modules 的存在。

sys.modules 是一個字典(key:模塊名,value:模塊對象),它存放著在當前 namespace 所有已經導入的模塊對象。 

  1. # test_module.py  
  2. import sys  
  3. print(sys.modules.get( json ,  NotFound ))  
  4. import json  
  5. print(sys.modules.get( json ,  NotFound )) 

運行結果如下,可見在 導入后 json 模塊后,sys.modules 才有了 json 模塊的對象。 

  1. $ python test_module.py  
  2. NotFound  
  3. <module  json  from  C:Python27libjson__init__.pyc > 

由于有緩存的存在,使得我們無法重新載入一個模塊。

但若你想反其道行之,可以借助 importlib 這個神奇的庫來實現。事實也確實有此場景,比如在代碼調試中,在發現代碼有異常并修改后,我們通常要重啟服務再次載入程序。這時候,若有了模塊重載,就無比方便了,修改完代碼后也無需服務的重啟,就能繼續調試。

還是以上面的例子來理解,my_mod02.py 改寫成如下 

  1. # my_mod02.py  
  2. import importlib  
  3. import my_mod01  
  4. importlib.reload(my_mod01) 

使用 python3 來執行這個模塊,與上面不同的是,這邊執行了兩次 my_mod01.py 

  1. $ python3 my_mod02.py  
  2. in mod01  
  3. in mod01 

4. 查找器與加載器

如果指定名稱的模塊在 sys.modules 找不到,則將發起調用 Python 的導入協議以查找和加載該模塊。

此協議由兩個概念性模塊構成,即 查找器 和 加載器。

一個 Python 的模塊的導入,其實可以再細分為兩個過程:

  •  由查找器實現的模塊查找
  •  由加載器實現的模塊加載

4.1 查找器是什么?

查找器(finder),簡單點說,查找器定義了一個模塊查找機制,讓程序知道該如何找到對應的模塊。

其實 Python 內置了多個默認查找器,其存在于 sys.meta_path 中。

但這些查找器對應使用者來說,并不是那么重要,因此在 Python 3.3 之前, Python 解釋將其隱藏了,我們稱之為隱式查找器。 

  1. # Python 2.7  
  2. >>> import sys  
  3. >>> sys.meta_path  
  4. []  
  5. >>>  

由于這點不利于開發者深入理解 import 機制,在 Python 3.3 后,所有的模塊導入機制都會通過 sys.meta_path 暴露,不會在有任何隱式導入機制。 

  1. # Python 3.7  
  2. >>> import sys  
  3. >>> sys.meta_path  
  4. [<class  _frozen_importlib.BuiltinImporter > 
  5.  <class  _frozen_importlib.FrozenImporter >,   
  6.  <class  _frozen_importlib_external.PathFinder >,   
  7.  <class  _frozen_importlib_external.PathFinder > 
  8. >>> 

觀察一下 Python 默認的這幾種查找器 (finder),可以分為三種:

  •  一種知道如何導入內置模塊
  •  一種知道如何導入凍結模塊
  •  一種知道如何導入來自 import path 的模塊 (即 path based finder)。

那我們能不能自已定義一個查找器呢?當然可以,你只要:

    1. 定義一個實現了 find_module 方法的類(py2和py3均可),或者實現 find_loader 類方法(僅 py3 有效),如果找到模塊需要返回一個 loader 對象或者 ModuleSpec 對象(后面會講),沒找到需 要返回 None

    2.定義完后,要使用這個查找器,必須注冊它,將其插入在 sys.meta_path 的首位,這樣就能優先使用。 

  1. import sys  
  2. class MyFinder(object):  
  3.     @classmethod  
  4.     def find_module(cls, name, path, target=None):  
  5.         print("Importing", name, path, target)  
  6.         # 將在后面定義  
  7.         return MyLoader()  
  8. # 由于 finder 是按順序讀取的,所以必須插入在首位  
  9. sys.meta_path.insert(0, MyFinder) 

查找器可以分為兩種: 

  1. object  
  2.  +-- Finder (deprecated)  
  3.       +-- MetaPathFinder  
  4.       +-- PathEntryFinder 

這里需要注意的是,在 3.4 版前,查找器會直接返回 加載器(Loader)對象,而在 3.4 版后,查找器則會返回模塊規格說明(ModuleSpec),其中 包含加載器。

而關于什么是 加載器 和 模塊規格說明, 請繼續往后看。

4.2 加載器是什么?

查找器只負責查找定位找模,而真正負責加載模塊的,是加載器(loader)。

一般的 loader 必須定義名為 load_module() 的方法。

為什么這里說一般,因為 loader 還分多種: 

  1. object  
  2.  +-- Finder (deprecated)  
  3.  |    +-- MetaPathFinder  
  4.  |    +-- PathEntryFinder  
  5.  +-- Loader  
  6.       +-- ResourceLoader --------+  
  7.       +-- InspectLoader          |  
  8.            +-- ExecutionLoader --+  
  9.                                  +-- FileLoader  
  10.                                  +-- SourceLoader 

通過查看源碼可知,不同的加載器的抽象方法各有不同。

加載器通常由一個 查找器 返回。詳情參見 PEP 302。

那如何自定義我們自己的加載器呢?

你只要:

  1.  定義一個實現了 load_module 方法的類
  2.  對與導入有關的屬性(點擊查看詳情)進行校驗
  3.  創建模塊對象并綁定所有與導入相關的屬性變量到該模塊上
  4.  將此模塊保存到 sys.modules 中(順序很重要,避免遞歸導入)
  5.  然后加載模塊(這是核心)
  6.  若加載出錯,需要能夠處理拋出異常( ImportError),若加載成功,則返回 module 對象

若你想看具體的例子,可以接著往后看。

4.3 模塊的規格說明

導入機制在導入期間會使用有關每個模塊的多種信息,特別是加載之前。大多數信息都是所有模塊通用的。模塊規格說明的目的是基于每個模塊來封裝這些導入相關信息。

模塊的規格說明會作為模塊對象的 __spec__ 屬性對外公開。有關模塊規格的詳細內容請參閱 ModuleSpec。

在 Python 3.4 后,查找器不再返回加載器,而是返回 ModuleSpec 對象,它儲存著更多的信息

  •  模塊名
  •  加載器
  •  模塊絕對路徑

那如何查看一個模塊的 ModuleSpec ?

這邊舉個例子 

  1. $ cat my_mod02.py  
  2. import my_mod01  
  3. print(my_mod01.__spec__)  
  4. $ python3 my_mod02.py  
  5. in mod01  
  6. ModuleSpec(namemy_mod01 , loader=<_frozen_importlib_external.SourceFileLoader object at 0x000000000392DBE0>origin= /home/MING/my_mod01.py ) 

從 ModuleSpec 中可以看到,加載器是包含在內的,那我們如果要重新加載一個模塊,是不是又有了另一種思路了?

來一起驗證一下。

現在有兩個文件:

一個是 my_info.py 

  1. # my_info.py  
  2. namepython 

另一個是:main.py 

  1. # main.py  
  2. import my_info  
  3. print(my_info.name)  
  4. # 加一個斷點  
  5. import pdb;pdb.set_trace()  
  6. # 再加載一次  
  7. my_info.__spec__.loader.load_module()  
  8. print(my_info.name) 

在 main.py 處,我加了一個斷點,目的是當運行到斷點處時,我修改 my_info.py 里的 name 為 ming ,以便驗證重載是否有效? 

  1. $ python3 main.py  
  2. python  
  3. > /home/MING/main.py(9)<module>()  
  4. -> my_info.__spec__.loader.load_module()  
  5. (Pdb) c  
  6. ming 

從結果來看,重載是有效的。

4.4 導入器是什么?

導入器(importer),也許你在其他文章里會見到它,但其實它并不是個新鮮的東西。

它只是同時實現了查找器和加載器兩種接口的對象,所以你可以說導入器(importer)是查找器(finder),也可以說它是加載器(loader)。

5. 遠程導入模塊

由于 Python 默認的 查找器和加載器 僅支持本地的模塊的導入,并不支持實現遠程模塊的導入。

為了讓你更好的理解 Python Import Hook 機制,我下面會通過實例演示,如何自己實現遠程導入模塊的導入器。

5.1 動手實現導入器

當導入一個包的時候,Python 解釋器首先會從 sys.meta_path 中拿到查找器列表。

默認順序是:內建模塊查找器 -> 凍結模塊查找器 -> 第三方模塊路徑(本地的 sys.path)查找器

若經過這三個查找器,仍然無法查找到所需的模塊,則會拋出ImportError異常。

因此要實現遠程導入模塊,有兩種思路。

  •  一種是實現自己的元路徑導入器;
  •  另一種是編寫一個鉤子,添加到sys.path_hooks里,識別特定的目錄命名模式。

我這里選擇第一種方法來做為示例。

實現導入器,我們需要分別查找器和加載器。

首先是查找器

由源碼得知,路徑查找器分為兩種

  •  MetaPathFinder
  •  PathEntryFinder

這里使用 MetaPathFinder 來進行查找器的編寫。

在 Python 3.4 版本之前,查找器必須實現 find_module() 方法,而  Python 3.4+ 版,則推薦使用 find_spec()  方法,但這并不意味著你不能使用 find_module(),但是在沒有 find_spec() 方法時,導入協議還是會嘗試 find_module() 方法。

我先舉例下使用 find_module() 該如何寫。 

  1. from importlib import abc  
  2. class UrlMetaFinder(abc.MetaPathFinder):  
  3.     def __init__(self, baseurl):  
  4.         self._baseurl = baseurl  
  5.     def find_module(self, fullname, path=None):  
  6.         if path is None:  
  7.             baseurl = self._baseurl  
  8.         else:  
  9.             # 不是原定義的url就直接返回不存在  
  10.             if not path.startswith(self._baseurl):  
  11.                 return None  
  12.             baseurl = path  
  13.         try:  
  14.             loader = UrlMetaLoader(baseurl)  
  15.             # loader.load_module(fullname)  
  16.         except Exception:  
  17.             return None 

若使用 find_spec() ,要注意此方法的調用需要帶有兩到三個參數。

第一個是被導入模塊的完整限定名稱,例如 foo.bar.baz。第二個參數是供模塊搜索使用的路徑條目。對于最高層級模塊,第二個參數為 None,但對于子模塊或子包,第二個參數為父包 __path__ 屬性的值。如果相應的 __path__ 屬性無法訪問,將引發 ModuleNotFoundError。第三個參數是一個將被作為稍后加載目標的現有模塊對象。導入系統僅會在重加載期間傳入一個目標模塊。 

  1. from importlib import abc  
  2. from importlib.machinery import ModuleSpec  
  3. class UrlMetaFinder(abc.MetaPathFinder):  
  4.     def __init__(self, baseurl):  
  5.         self._baseurl = baseurl  
  6.     def find_spec(self, fullname, path=Nonetarget=None):  
  7.         if path is None:  
  8.             baseurl = self._baseurl  
  9.         else:  
  10.             # 不是原定義的url就直接返回不存在  
  11.             if not path.startswith(self._baseurl):  
  12.                 return None  
  13.             baseurl = path  
  14.         try:  
  15.             loader = UrlMetaLoader(baseurl)  
  16.             return ModuleSpec(fullname, loader, is_package=loader.is_package(fullname))  
  17.         except Exception:  
  18.             return None 

接下來是加載器

由源碼得知,路徑查找器分為兩種

  •  FileLoader
  •  SourceLoader

按理說,兩種加載器都可以實現我們想要的功能,我這里選用 SourceLoader 來示范。

在 SourceLoader 這個抽象類里,有幾個很重要的方法,在你寫實現加載器的時候需要注意

  •  get_code:獲取源代碼,可以根據自己場景實現實現。
  •  exec_module:執行源代碼,并將變量賦值給 module.dict
  •  get_data:抽象方法,必須實現,返回指定路徑的字節碼。
  •  get_filename:抽象方法,必須實現,返回文件名

在一些老的博客文章中,你會經常看到 加載器 要實現 load_module() ,而這個方法早已在 Python 3.4 的時候就被廢棄了,當然為了兼容考慮,你若使用 load_module() 也是可以的。 

  1. from importlib import abc  
  2. class UrlMetaLoader(abc.SourceLoader):  
  3.     def __init__(self, baseurl): 
  4.         self.baseurl = baseurl  
  5.     def get_code(self, fullname):  
  6.         f = urllib2.urlopen(self.get_filename(fullname))  
  7.         return f.read() 
  8.      def load_module(self, fullname):  
  9.         code = self.get_code(fullname)  
  10.         mod = sys.modules.setdefault(fullname, imp.new_module(fullname))  
  11.         mod.__file__ = self.get_filename(fullname)  
  12.         mod.__loader__ = self  
  13.         mod.__package__ = fullname 
  14.         exec(code, mod.__dict__)  
  15.         return None  
  16.     def get_data(self):  
  17.         pass  
  18.     def execute_module(self, module):  
  19.         pass  
  20.     def get_filename(self, fullname):  
  21.         return self.baseurl + fullname +  .py 

當你使用這種舊模式實現自己的加載時,你需要注意兩點,很重要:

  •  execute_module 必須重載,而且不應該有任何邏輯,即使它并不是抽象方法。
  •  load_module,需要你在查找器里手動執行,才能實現模塊的加載。。

做為替換,你應該使用 execute_module() 和 create_module() 。由于基類里已經實現了 execute_module 和 create_module(),并且滿足我們的使用場景。我這邊可以不用重復實現。和舊模式相比,這里也不需要在設查找器里手動執行 execute_module()。 

  1. import urllib.request as urllib2  
  2. class UrlMetaLoader(importlib.abc.SourceLoader):  
  3.     def __init__(self, baseurl):  
  4.         self.baseurl = baseurl  
  5.     def get_code(self, fullname):  
  6.         f = urllib2.urlopen(self.get_filename(fullname))  
  7.         return f.read()  
  8.     def get_data(self):  
  9.         pass  
  10.     def get_filename(self, fullname):  
  11.         return self.baseurl + fullname +  .py 

查找器和加載器都有了,別忘了往sys.meta_path 注冊我們自定義的查找器(UrlMetaFinder)。 

  1. def install_meta(address):  
  2.     finder = UrlMetaFinder(address)  
  3.     sys.meta_path.append(finder) 

所有的代碼都解析完畢后,我們將其整理在一個模塊(my_importer.py)中 

  1. # my_importer.py  
  2. import sys  
  3. import importlib  
  4. import urllib.request as urllib2  
  5. class UrlMetaFinder(importlib.abc.MetaPathFinder):  
  6.     def __init__(self, baseurl):  
  7.         self._baseurl = baseurl  
  8.     def find_module(self, fullname, path=None):  
  9.         if path is None:  
  10.             baseurl = self._baseurl  
  11.         else:  
  12.             # 不是原定義的url就直接返回不存在  
  13.             if not path.startswith(self._baseurl):  
  14.                 return None  
  15.             baseurl = path  
  16.         try:  
  17.             loader = UrlMetaLoader(baseurl)  
  18.         except Exception:  
  19.             return None  
  20. class UrlMetaLoader(importlib.abc.SourceLoader):  
  21.     def __init__(self, baseurl):  
  22.         self.baseurl = baseurl  
  23.     def get_code(self, fullname):  
  24.         f = urllib2.urlopen(self.get_filename(fullname))  
  25.         return f.read()  
  26.     def get_data(self):  
  27.         pass  
  28.     def get_filename(self, fullname):  
  29.         return self.baseurl + fullname +  .py   
  30. def install_meta(address):  
  31.     finder = UrlMetaFinder(address)  
  32.     sys.meta_path.append(finder) 

5.2 搭建遠程服務端

最開始我說了,要實現一個遠程導入模塊的方法。

我還缺一個在遠端的服務器,來存放我的模塊,為了方便,我使用python自帶的 http.server 模塊用一條命令即可實現。 

  1. $ mkdir httpserver && cd httpserver  
  2. $ cat>my_info.py<EOF  
  3. namePython編程時光   
  4. print( ok )  
  5. EOF  
  6. $ cat my_info.py  
  7. namePython編程時光   
  8. print( ok )  
  9. $   
  10. $ python3 -m http.server 12800  
  11. Serving HTTP on 0.0.0.0 port 12800 (http://0.0.0.0:12800/) ...  
  12. ... 

一切準備好,我們就可以驗證了。 

  1. >>> from my_importer import install_meta  
  2. >>> install_meta( http://localhost:12800/ ) # 往 sys.meta_path 注冊 finder   
  3. >>> import my_info  # 打印ok,說明導入成功  
  4. ok  
  5. >>> my_info.name  # 驗證可以取得到變量  
  6.  Python編程時光 

至此,我實現了一個簡易的可以導入遠程服務器上的模塊的導入器。 

 

責任編輯:龐桂玉 來源: 機器學習算法與Python學習
相關推薦

2010-11-22 14:18:32

MySQL鎖機制

2009-12-10 15:02:07

OSPF動態路由協議

2010-03-04 14:51:21

Python Conf

2009-12-01 16:34:21

PHP表單

2010-03-15 16:31:34

Java多線程

2010-03-01 17:57:11

WCF緩存機制

2010-03-05 13:44:00

Python序列

2009-12-23 16:13:00

WPF Attache

2010-03-31 14:58:03

云計算

2009-12-07 16:07:03

PHP類的繼承

2009-12-14 13:33:49

Ruby與Python

2010-07-21 09:38:15

PHP緩存技術

2009-11-20 17:17:08

Oracle函數索引

2021-05-17 05:36:02

CSS 文字動畫技巧

2023-10-23 12:35:36

Golang追加操作

2009-10-16 18:20:07

綜合布線系統

2009-12-07 11:21:59

PHP生成縮略圖

2009-12-10 13:14:26

PHP下拉框

2009-12-25 10:20:28

WPF窗口

2011-02-25 09:23:00

Java類加載器
點贊
收藏

51CTO技術棧公眾號

最近中文字幕免费视频| 国产精品国产三级国产专区53 | 日本在线一级片| 日本在线一区二区三区| 天天综合天天做天天综合| 日韩一本精品| 国产精品果冻传媒潘| 亚洲黄色小说在线观看| 无遮挡爽大片在线观看视频 | 欧美激情一区二区三区在线视频| 国产成人精品一区二区色戒| 欧美激情四色| 影音先锋欧美精品| 玖玖爱在线精品视频| 麻豆久久久久| 狠狠做深爱婷婷久久综合一区 | 国产一区二区无遮挡| 日韩女同强女同hd| 亚洲成人精品| 一区二区三区无码高清视频| 国产a级黄色片| 在线观看日韩羞羞视频| 欧美一区二区黄片| 国精产品一区一区三区mba桃花| 91精品国产777在线观看| 国产精品1区2区3区4区| 欧美男男freegayvideosroom| 欧美日韩国产123区| 日本精品免费在线观看| 日韩激情美女| 中文字幕在线视频一区| 欧美18视频| 婷婷五月综合激情| 国产大陆精品国产| 国产欧美日韩视频| 337p粉嫩色噜噜噜大肥臀| 青青草手机视频在线观看| 成人性教育av免费网址| 午夜日韩在线电影| 日韩视频 中文字幕| 自拍视频在线播放| 久久综合九色欧美综合狠狠| 国产精选一区二区| 99久久久久久久| 蜜桃视频第一区免费观看| 欧美成人激情在线| 国产精品国产三级国产传播| 国产麻豆精品久久| 国产视频亚洲精品| 日本aaa视频| 欧美大片网址| 日韩麻豆第一页| 色婷婷精品久久二区二区密| 51亚洲精品| 精品国产乱码久久久久久老虎 | 一区二区三区精品国产| 第九色区av在线| 国产人伦精品一区二区| 日韩精品伦理第一区| 国产香蕉视频在线看| 中文不卡1区2区3区| 91色视频在线| 日本午夜一区二区三区| 国产资源在线播放| 日本一区二区三级电影在线观看| 涩涩涩999| 国产无限制自拍| 免费的av网站| 国产精品白丝av嫩草影院| 亚洲精品一区二区三区香蕉 | 日日夜夜一区| 欧美一级日韩一级| 正在播放一区| 国产亚洲精久久久久久无码77777| 亚洲国产精品综合久久久 | 视频一区二区三区在线| 国产精品久久久久久网站| 欧美高清69hd| 国产一区二区在线影院| 国产精品国产亚洲精品看不卡15 | 欧美国产精品v| 三年中文高清在线观看第6集| 深夜国产在线播放| 欧美日韩裸体免费视频| 亚欧在线免费观看| 久久丁香四色| 日韩精品视频三区| 亚洲天堂精品一区| 亚洲日本欧美| 国产精品久久久久久久久久免费| 午夜精品一二三区| 国产欧美一区二区三区沐欲| 国产手机视频在线观看| 中文字幕在线中文字幕在线中三区| 欧美系列一区二区| 一级黄色电影片| 国产欧美日韩精品高清二区综合区| 久久精品视频va| 黄色在线观看国产| 国产资源精品在线观看| 久久精品国产精品青草色艺| 麻豆网站视频在线观看| 日韩欧美在线网址| caopor在线视频| 在线观看 亚洲| 日韩中文字幕亚洲一区二区va在线| 91牛牛免费视频| 一区二区不卡在线视频 午夜欧美不卡'| a级在线免费观看| 91精品蜜臀一区二区三区在线| 97超级碰碰碰久久久| 91免费视频播放| 久久久精品免费网站| 日韩精品一区二区三区四| h1515四虎成人| 日韩精品免费在线| 久一视频在线观看| 国产一区二三区| 亚洲精品国产一区| gay欧美网站| 亚洲第一精品福利| 精品国产乱码久久久久久鸭王1| 日韩极品在线观看| 欧美成人免费在线| 成人免费观看在线观看| 这里是久久伊人| 亚洲精品一区二区三区影院忠贞| 亚洲看片免费| 国产精品久久久久久久免费大片| gogo在线观看| 7777精品伊人久久久大香线蕉完整版 | 毛片大全在线观看| 8x8x8国产精品| 中国女人特级毛片| 久久青草久久| 欧美日韩精品久久| xxxx国产视频| 国产夫妻在线| 精品999在线播放| 免费在线观看日韩| 国产福利电影一区二区三区| 欧美爱爱视频网站| 91麻豆精品| 日韩亚洲在线观看| 一级特黄特色的免费大片视频| 国产日韩影视精品| 中文字幕国内自拍| 全球成人免费直播| 国产精品一区二区3区| 在线毛片网站| 欧美日本韩国一区二区三区视频| 国产aaaaaaaaa| 麻豆专区一区二区三区四区五区| 深夜福利成人| 亚洲精品aaa| 久久久999精品| 国产成人av免费看| 亚洲综合一区在线| 亚洲图片综合网| 免费亚洲一区| 亚洲三区在线| 国产电影一区| 国内外成人免费激情在线视频网站| 亚洲av无码专区在线| 亚洲网友自拍偷拍| 亚洲中文字幕无码av| 新67194成人永久网站| 日本在线免费观看一区| 日韩成人在线电影| 欧美激情精品久久久久久变态| 高清毛片aaaaaaaaa片| 欧美日韩精品在线| 日本精品久久久久中文| 国产一区二区免费看| 免费视频爱爱太爽了| 丝袜久久网站| 国产精品久久久久久久久久东京| 黄色在线播放网站| 久久激五月天综合精品| 91传媒视频免费| a√中文在线观看| 精品视频久久久久久久| 亚洲国产精品人久久电影| 我要看一级黄色录像| 国产成人av电影在线| 无码人妻精品一区二区三区在线 | 国产精品538一区二区在线| 一本久道高清无码视频| 国产精品欧美日韩一区| 亚洲一区亚洲二区| 最近高清中文在线字幕在线观看1| 亚洲色图综合久久| www.国产麻豆| 欧美在线啊v一区| 激情小说中文字幕| 国产午夜精品福利| 中文字幕无码毛片免费看| 亚洲免费中文| 欧美做受777cos| 欧美精品第一区| 国产富婆一区二区三区| 97欧美成人| 91av免费观看91av精品在线| 色老头视频在线观看| 日韩精品在线免费观看视频| 国产孕妇孕交大片孕| 色综合视频一区二区三区高清| 欧美国产日韩综合| 国产精品亲子伦对白| 国产成人精品无码片区在线| 国产精品一区二区三区99| 黄色av免费在线播放| 亚洲人人精品| 国产激情片在线观看| 日韩精品欧美激情一区二区| 精品综合在线| eeuss鲁片一区二区三区| 国产综合福利在线| 国产在线|日韩| 88国产精品欧美一区二区三区| 最爽无遮挡行房视频在线| 中文字幕不卡在线视频极品| 日韩精品视频无播放器在线看| 日韩三级视频在线看| 一级α片免费看刺激高潮视频| 色综合亚洲欧洲| 国产精品老女人| 亚洲国产一区二区在线播放| 黄视频网站免费看| 中文字幕一区二区三区蜜月| 一色道久久88加勒比一| 2019国产精品| 亚洲天堂网一区二区| 播五月开心婷婷综合| 成年人性生活视频| 国产又粗又猛又爽又黄91精品| 五月婷婷丁香综合网| 日韩影院精彩在线| 无码人妻精品一区二区三区66| 久久福利影视| 日韩视频第二页| 久久精品30| 成人久久久久久久久| 美女久久网站| 虎白女粉嫩尤物福利视频| 免费在线日韩av| 成人羞羞国产免费网站| 日韩高清欧美激情| 天堂网在线免费观看| 免费观看在线色综合| 国产原创精品在线| 久久99蜜桃精品| 欧美一级免费在线| 国产福利一区二区| 国模私拍在线观看| 91美女片黄在线观看91美女| 精品欧美一区二区久久久| 国产亚洲综合av| 刘亦菲国产毛片bd| 亚洲欧美日韩中文字幕一区二区三区| 老湿机69福利| 亚洲一区二区三区四区的| 奇米影视第四色777| 色综合天天综合网天天狠天天| 中文精品久久久久人妻不卡| 欧美日本高清视频在线观看| 国产又黄又粗又硬| 欧美mv日韩mv国产网站app| 香港三日本三级少妇66| 国产亚洲精品久久久久久777| 日韩子在线观看| 欧美黄色片在线观看| 不卡av影片| 国产日韩精品在线观看| 91免费精品国偷自产在线在线| 国产一区二区中文字幕免费看| 欧美热在线视频精品999| 性欧美大战久久久久久久免费观看| 91精品精品| 老太脱裤让老头玩ⅹxxxx| 日韩 欧美一区二区三区| 国产精品久久久久野外| 91麻豆福利精品推荐| 国产又粗又猛又爽又黄的视频小说| 亚洲精品视频在线| 国产精品人人人人| 69堂成人精品免费视频| 黄色片一区二区三区| 中文字幕亚洲欧美日韩2019| 色黄网站在线观看| 国产成一区二区| 亚洲一区网址| 日本精品一区二区| 欧美精品综合| 美女网站免费观看视频| 国产成人亚洲综合色影视| 法国空姐电影在线观看| 亚洲精品国久久99热| 少妇高潮av久久久久久| 日韩手机在线导航| www免费网站在线观看| 久久免费视频在线| 国产欧美自拍| 乱色588欧美| 欧美在线高清| 欧美特级aaa| 91片在线免费观看| 五月婷婷一区二区| 欧美区视频在线观看| 图片区 小说区 区 亚洲五月| 久久精品国产亚洲一区二区| 这里有精品可以观看| 亚洲综合在线播放| 久久激情电影| 成人在线激情网| www.成人网.com| 欧美卡一卡二卡三| 欧美嫩在线观看| 男男电影完整版在线观看| 欧美国产日韩一区二区在线观看| 成人av集中营| 日本不卡一区| 亚洲一卡久久| 国产精品久久久久久亚洲色| 亚洲天堂成人在线观看| 欧美激情一区二区三区免费观看 | 亚洲专区一区二区三区| 男人添女人荫蒂国产| 中文字幕一区视频| 中文字幕日韩国产| 国产亚洲精品美女久久久| 波多野结衣亚洲一二三| 欧美不卡在线一区二区三区| 国产精品久久久久久模特| 亚洲高清无码久久| 亚洲一卡二卡三卡四卡五卡| 国产伦理一区二区| 久久综合免费视频| 国产精品欧美一区二区三区不卡 | 777亚洲妇女| 免费在线看黄| 国产欧美精品一区二区| 日韩欧美中文| 成人不卡免费视频| 最新国产成人在线观看| 国产乱淫a∨片免费观看| 色妞久久福利网| 日本久久二区| 亚洲天堂第一区| 国产成人激情av| 国产无套在线观看| 亚洲高清福利视频| 亚洲涩涩在线| 欧美系列一区| 欧美96一区二区免费视频| 国产一二三四视频| 欧美精品久久天天躁| caopen在线视频| 鬼打鬼之黄金道士1992林正英| 亚洲午夜久久久久久尤物| 成人免费看片载| 日韩欧美在线中文字幕| 国产裸舞福利在线视频合集| 国产精品久久久久国产a级| 日韩欧美电影| 中文字幕av一区二区三区人妻少妇 | 久久精品女人天堂av免费观看| 日韩精品大片| 精品一区二区在线播放| 久操免费在线视频| 日韩国产一区三区| 色成人免费网站| 久久天天东北熟女毛茸茸| 成人99免费视频| av首页在线观看| 欧美成人精品在线播放| 久久激情av| 一区二区三区入口| 一区二区三区不卡在线观看| 特级丰满少妇一级aaaa爱毛片| 国产精品久久久久av| 欧美日韩一卡| 国产美女永久免费无遮挡| 欧美一区二区三区在| 日本在线高清| 91手机视频在线| 99久久久国产精品免费蜜臀| 中文字幕av影视| 久久久久久中文字幕| 欧美日韩有码| 美女露出粉嫩尿囗让男人桶| 色综合久久中文字幕综合网| 老司机午夜在线视频| 久久精品国产精品国产精品污 | 色偷偷88欧美精品久久久| 国产在线观看av| 97久久精品人搡人人玩| 国产精品69久久久久孕妇欧美| 色呦呦日韩精品| 亚洲性图自拍|