99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁大數(shù)據(jù)時代搞懂Python包之后,感覺學Python輕松多了
搞懂Python包之后,感覺學Python輕松多了
2021-02-07
收藏

來源:麥叔編程

作者:麥叔

1.前言

學習方法不對,事倍功半!學習方法對了,事半功倍。

學編程,要先扎實的學好基礎(chǔ)語法和結(jié)構(gòu),剩下的就是不斷的實戰(zhàn)應用,同時按需加強相關(guān)知識。

Python的包就是這里說的基礎(chǔ)語法結(jié)構(gòu)之一。

把手放在胸口上,問問自己,你對Python包的了解有多少?然后認真看完本文。你的今天一定是有進步的。

包是基于模塊的,是對模塊的組織,建議和另一篇模塊文章一起看,融會貫通起來。模塊文章鏈接見文末往期推薦第1篇。

2.Python包

假設(shè)你已經(jīng)開發(fā)了一個包含許多模塊的非常大的應用程序。隨著模塊數(shù)量的增長,如果將它們都放到一個位置,則很難跟蹤所有模塊。如果它們有相似的名稱或功能,情況會更糟。你可能希望把他們放在不同的文件夾中,這就是Python中的包。

包(package)允許使用點表示法對模塊名稱空間進行分層結(jié)構(gòu)。就像模塊可以避免全局變量名之間的沖突一樣,包也可以避免模塊名之間的沖突。

創(chuàng)建包非常簡單,因為它利用了操作系統(tǒng)固有的分層文件結(jié)構(gòu)。參考下面的目錄結(jié)構(gòu):

pkg ├── mod1.py └── mod2.py 

這里有一個名為pkg的目錄,其中包含兩個模塊,mod1.py和mod2.py。模塊的內(nèi)容有:

mod1.py

def foo(): print('[mod1] foo()') class Foo: pass 

mod2.py

def bar(): print('[mod2] bar()') class Bar: pass 

根據(jù)這個結(jié)構(gòu),如果pkg目錄位于一個可以找到它的位置(在sys.path中包含的一個目錄中),你可以用點符號引用這兩個模塊(pkg.mod1, pkg.mod2),然后用你已經(jīng)熟悉的語法導入它們:

import <module_name>[, <module_name> ...]
>>> import pkg.mod1, pkg.mod2 >>> pkg.mod1.foo()
[mod1] foo() >>> x = pkg.mod2.Bar() >>> x
0x033F7290>
from  import 
>>> from pkg.mod1 import foo >>> foo()
[mod1] foo()
from  import  as 
>>> from pkg.mod2 import Bar as Qux >>> x = Qux() >>> x
0x036DFFD0>

你也可以用這些語句來導入模塊:

from <package_name> import <modules_name>[, <module_name> ...]
from <package_name> import <module_name> as <alt_name> 
>>> from pkg import mod1 >>> mod1.foo()
[mod1] foo() >>> from pkg import mod2 as quux >>> quux.bar()
[mod2] bar()

從技術(shù)上講,你也可以直接導入這個包:

>>> import pkg >>> pkg
<module 'pkg' (namespace)> 

但這沒什么用。盡管嚴格地說,這是一個語法正確的Python語句,但它并沒有把pkg中的任何模塊放到本地命名空間中:

>>> pkg.mod1
Traceback (most recent call last):
  File "", line 1in <module>     pkg.mod1 AttributeError: module 'pkg
has no attribute 'mod1' >>> pkg.mod1.foo()
Traceback (most recent call last):
  File "", line 1in <module>     pkg.mod1.foo() AttributeError: module '
pkghas no attribute 'mod1' >>> pkg.mod2.Bar()
Traceback (most recent call last):
  File "", line 1in <module>     pkg.mod2.Bar() AttributeError: module '
pkghas no attribute 'mod2' 

要實際導入模塊或其內(nèi)容,需要使用上面展示的import例子。

3.包初始化

如果一個名為__init__.py的文件存在于包目錄中,它會在導入包或包中的模塊時被調(diào)用。這可以用于執(zhí)行包初始化代碼,比如包級數(shù)據(jù)的初始化。

例如以下__init__.py文件:

__init__.py

print(f'Invoking __init__.py for {__name__}')
A = ['quux''corge''grault']

讓我們把上面例子中的這個文件添加到pkg目錄中:

pkg ├── __init__.py ├── mod1.py └── mod2.py 

現(xiàn)在,當包被導入時,A就會被初始化:

>>> import pkg
Invoking __init__.py for pkg >>> pkg.A
['quux''corge''grault']

包中的模塊可以訪問包里的全局變量:

mod1.py

def foo():     from pkg import A
    print('[mod1] foo() / A = ', A) class Foo:     pass 
>>> from pkg import mod1
Invoking __init__.py for pkg >>> mod1.foo()
[mod1] foo() / A =  ['quux''corge''grault']

__init__.py也可以用來實現(xiàn)從包中自動導入模塊。例如,前面你看到import pkg語句只將名稱pkg放在調(diào)用者的局部符號表中,而不導入任何模塊。但是如果pkg目錄中的__init__.py包含以下內(nèi)容:

__init__.py

print(f'Invoking __init__.py for {__name__}') import pkg.mod1, pkg.mod2

然后當你執(zhí)行import pkg,模塊mod1和mod2自動導入:

>>> import pkg Invoking __init__.py for pkg >>> pkg.mod1.foo() [mod1] foo()
>>> pkg.mod2.bar() [mod2] bar()

注意:大部分Python文檔都聲明在創(chuàng)建包時必須在包目錄中存在__init__.py文件。這曾經(jīng)是必須的。過去,__init__.py的存在對Python來說意味著正在定義一個包。該文件可以包含初始化代碼,甚至可以為空,但它必須存在。從Python 3.3開始,引入了隱式命名空間包。這些允許創(chuàng)建一個沒有任何__init__.py文件的包。當然,如果需要包初始化,它仍然可以存在。但現(xiàn)在不再是必須的了。

4.Importing * From a Package

為了以下討論的目的,先前定義的包被擴展以包含一些額外的模塊:

pkg ├── mod1.py ├── mod2.py ├── mod3.py └── mod4.py 

pkg目錄中現(xiàn)在定義了四個模塊。其內(nèi)容如下:

mod1.py

def foo():     print('[mod1] foo()') class Foo:     pass 

mod2.py

def bar():     print('[mod2] bar()') class Bar:     pass 

mod3.py

def baz():     print('[mod3] baz()') class Baz:     pass 

mod4.py

def qux():     print('[mod4] qux()') class Qux:     pass 

正如你所看到,當import *用于一個模塊時,該模塊中的所有對象都被導入到本地符號表中,除了那些名稱以下劃線開頭的對象:

>>> dir()
['__annotations__''__builtins__''__doc__''__loader__''__name__',
 '__package__''__spec__'] >>> from pkg.mod3 import *

>>> dir()
['Baz''__annotations__''__builtins__''__doc__''__loader__'
'__name__', '__package__''__spec__''baz'] >>> baz()
[mod3] baz() >>> Baz
 <class 'pkg.mod3.Baz'> 

一個包的類似聲明是這樣的:

from  import *

這行代碼做了什么呢?

>>> dir()
['__annotations__''__builtins__''__doc__''__loader__''__name__', 
'__package__''__spec__'] >>> from pkg import *
>>> dir()
['__annotations__''__builtins__''__doc__''__loader__'
'__name__', '__package__''__spec__']

嗯。好像什么也沒做。你可能期望Python會深入到包目錄中,找到它所能找到的所有模塊,并將它們?nèi)繉搿5缒闼吹降?,默認情況下并不是這樣的。

相反,Python遵循以下約定:如果包目錄中的__init__.py文件包含名為__all__的列表,當遇到import *語句時,它將被視為應該導入的模塊列表。

對于現(xiàn)在的例子,假設(shè)你像這樣在pkg目錄中創(chuàng)建一個__init__.py:

pkg/__init__.py

__all__ = [
        'mod1',
        'mod2',
        'mod3',
        'mod4'         ]

現(xiàn)在用import *導入所有四個模塊:

>>> dir()
['__annotations__''__builtins__''__doc__''__loader__''__name__', 
'__package__''__spec__'] >>> from pkg import *
>>> dir()
['__annotations__''__builtins__''__doc__''__loader__''__name__', 
'__package__''__spec__''mod1''mod2''mod3''mod4'] >>> mod2.bar()
[mod2] bar() >>> mod4.Qux
<class 'pkg.mod4.Qux'> 

使用import *仍然不被認為是很好的形式,無論是對包還是模塊來說都是如此。但是這個功能至少讓包的創(chuàng)建者對指定import *時發(fā)生的事情有一定的控制。(事實上,它提供了完全禁止它的能力,只要拒絕定義__all__就行了。如你所見,包的默認行為是不導入任何內(nèi)容。)

順便說一下,__all__也可以在模塊中定義,并達到同樣的目的:控制import *導入的內(nèi)容。例如,修改mod1.py如下: pkg/mod1.py

__all__ = ['foo'] def foo():     print('[mod1] foo()') class Foo:     pass 

現(xiàn)在,pkg.mod1中的import *語句只會導入包含在__all__中的內(nèi)容:

>>> dir()
['__annotations__''__builtins__''__doc__''__loader__''__name__',
 '__package__''__spec__'] >>> from pkg.mod1 import *
>>> dir()
['__annotations__''__builtins__''__doc__''__loader__'
'__name__', '__package__''__spec__''foo'] >>> foo()
[mod1] foo() >>> Foo
Traceback (most recent call last):
  File "", line 1in <module>     Foo NameError: name 'Foo' is not defined 

foo()(函數(shù))現(xiàn)在定義在本地命名空間中,但foo(類)沒有定義,因為后者不在__all__中。

總之,當import *被指定時,__all__會被包和模塊用來控制導入的內(nèi)容。但是默認行為是不同的:

對于一個包:當__all__沒有定義,import *不導入任何東西。對于一個模塊:當__all__沒有定義,import *導入所有內(nèi)容(除了以下劃線開頭的名稱)。

5.子包

包可以包含任意深度的嵌套子包。例如,讓我們對示例包目錄再做一個修改,如下所示:

pkg ├── sub_pkg1 │   ├── mod1.py │   └── mod2.py └── sub_pkg2   
  ├── mod3.py     └── mod4.py 

四個模塊(mod1.py, mod2.py, mod3.py和mod4.py)的定義如前所述。但是現(xiàn)在,它們不是被集中到pkg目錄中,而是被分成兩個子目錄,sub_pkg1和sub_pkg2。

導入仍然和前面顯示的一樣工作。語法類似,但是額外的點符號用于分隔包名和子包名:

>>> import pkg.sub_pkg1.mod1 >>> pkg.sub_pkg1.mod1.foo()
[mod1] foo() >>> from pkg.sub_pkg1 import mod2 >>> mod2.bar()
[mod2] bar() >>> from pkg.sub_pkg2.mod3 import baz >>> baz()
[mod3] baz() >>> from pkg.sub_pkg2.mod4 import qux as grault >>> grault()
[mod4] qux()

此外,一個子包中的模塊可以引用同級子包中的對象(如果同級子包包含你需要的某些功能)。例如,假設(shè)你想從mod3模塊中導入并執(zhí)行mod1中的函數(shù)foo()。你可以使用絕對導入:

pkg/sub_pkg2/mod3.py

def baz():     print('[mod3] baz()') class Baz:     pass 
from pkg.sub_pkg1.mod1 import foo foo()
 
>>> from pkg.sub_pkg2 import mod3 [mod1] foo()
>>> mod3.foo() [mod1] foo()

或者你可以使用相對導入,其中..指的是上一級的包。從mod3.py中引用的話也就是sub_pkg2這一層。

..結(jié)果為父包(pkg),../sub_pkg1結(jié)果為子包sub_pkg1。

pkg/sub_pkg2/mod3.py

def baz():     print('[mod3] baz()') class Baz:     pass from .. import sub_pkg1
print(sub_pkg1) from ..sub_pkg1.mod1 import foo
foo()
>>> from pkg.sub_pkg2 import mod3
<module 'pkg.sub_pkg1' (namespace)>
[mod1] foo()

數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }