python import from class_Python: import vs from (module) import function(class) 的理解
Python: Import vs From (module) import function(class)
本文涉及的 Python 基本概念:
Module
Class
import
from ... import
最近在學習Paython, 遇到一個問題,涉及到import 和 from ... import,module 和 class 的理解,解決方式是將import 替換成 from import, 但其實并非一個好的解決方法, 后來還是改回import。在這里稍微總結一下,以免再犯。
為方便解釋,先簡化一下問題,后面我會列出我遇到問題時用的代碼,以供參考。
問題 1 重現
假設我們有兩個 module,文件名分別是:module.py, animal.py。對于不太熟悉 python module 的同學,我在后面稍微解釋了下。
module.py: 希望調用animal中 Animal類的方法
animal.py: 包含一個名為 Animal 的類
module.py
import animal
class Module(object):
def test(self):
animal.run()
if __name__=="__main__":
Module().test()
animal.py
class Animal(object):
def run(self):
print "animal is running"
運行" python module.py"的時候出現錯誤:
Traceback (most recent call last):
File "module.py", line 8, in
Module().test()
File "module.py", line 5, in test
animal.run()
AttributeError: 'module' object has no attribute 'run'
這是因為,在import animal 的時候,python 會創建一個對 模塊名 animal 的引用,如果要訪問該模塊內其他方法或類時,需要寫全,如 animal.attribute。
Imports the module X, and creates a reference to that module in the current namespace. Then you need to define completed module path to access a particular attribute or method from inside the module (e.g.: X.name or X.attribute)
在我上面的例子中,我需要訪問的是 animal 中 的 Animal 類中定義的方法 run。因為這個 run 方法是 Animal 類的實例方法,所以我還需要創建一個Animal實例才可以訪問。
所以,將 module.py 中 第五行代碼 "animal.run()" 改為:
animal.Animal().run()
再運行即可成功。
module.py 修改后的代碼:
import animal
class Module(object):
def test(self):
animal.Animal().run()
if __name__=="__main__":
Module().test()
對于剛接觸 Python 的同學,有必要先了解一下 python 中 **module **的定義:
A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended
module 就是一個 后綴是 .py 的Python文件,文件名就是 module的名字,文件中可以定義一些函數方法或者class類,這個module可以通過 import 指令導入其他module,以便重用(reuse)。
比如我這里的例子中 animal.py,其中animal就是一個python module,里面定義了一個Animal類。module.py 文件中通過 import animal,導入animal,這樣我便可以調用animal中Animal 類的方法。
問題 2 重現
現在我們再創建一個cat.py: 包含一個名為 cat 的類,是 Animal的子類
cat.py:
import animal
class Cat(animal):
def run(self):
print "cat is running"
我們修改一下 module.py, 讓它調用 cat module 中的方法:
import cat
class Module(object):
def test(self):
cat.run()
if __name__=="__main__":
Module().test()
現在我們運行 module.py 的話,有沒有看出會出現什么問題?
Traceback (most recent call last):
File "module.py", line 1, in
import cat
File "C:\projects\Python\500lines\simple-web-server\simple-web-server\cat.py", line 3, in
class Cat(animal):
TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given)
是不是有點糊涂,我就被這個錯誤卡住了 "module.__init__() takes at most 2 arguments (3 given)"。毫無頭緒,網上搜索了下,原因是 Class Cat(animal),這里python 認為是要繼承module animal
, 而不是class Animal,所以報錯。
在cat.py中,import animal 語句告訴python,我們導入的是 animal module.
那為什么繼承module的話會出現這種模糊不清的錯誤提示呢:module.__init__() takes at most 2 arguments (3 given)?
簡單的解釋就是:
python在遇到繼承的時候,會內部調用__init__方法,如果是繼承class的話,就會調用type.__init__() 方法,該方法有三個參數;而如果是繼承module的話,就會調用module.__init__()
方法,該方法只接受兩個參數。所以就會出現上面那個錯誤:module.__init__() takes at most 2 arguments (3 given)
type(BaseClass).__init__(cls, name_of_subclass, (BaseClass,), dict_of_subclass)
# or simpler
type(BaseClass)(name_of_subclass, (BaseClass,), dict_of_subclass)
那為什么繼承class 是調用type.__init__, 而module則是 module.__init__呢? 這就涉及到 python module 和 class 的區別了。我們可以使用 type() 方法在python shell中快速察看一下:
>>> import animal
>>> type(animal)
>>> from animal import Animal
>>> type(Animal)
當我們導入 module animal的時候,animal 的類型是module;
當我們從animal 導入 Animal的時候,Animal的類型是 type,也就是類;
現在我們的問題 2 知道原因何在了吧,我們需要Cat類繼承Animal Class, 而不是 animal module。
從上面 "from animal import Animal" 語句我們可以看出,這樣導入后我們可以直接調用Animal,而不需要animal.Animal。
現在修改一下cat.py:
from animal import Animal
class Cat(animal):
def run(self):
print "cat is running"
以及 module.py:
from cat import Cat
class Module(object):
def test(self):
Cat().run()
if __name__=="__main__":
Module().test()
運行 python module.py,終于得到我們要的結果了
PS C:\projects\Python\500lines\simple-web-server\simple-web-server> python module.py
cat is running
大家可以看到,現在我們用的是 from...import...語句:
from X import *
Imports the module X, and creates references to all public objects defined by that module in the current namespace (that is, everything that doesn’t have a name starting with _) or whatever name you mentioned.
*號表示 X 中的所有非私有對象,除了__開頭的。
如果用特定的對象取代 * ,比如from cat import Cat, 便是從module cat 導入 class Cat, 而非所有的module cat中的對象。
在使用這種導入的時候,module X 本身并沒有設置,所以我們不能用 X.name 或 X.其他對象 來引用 module中的對象。我們直接使用那些對象即可。
至于 import module 和 from module import FC 哪種更好,則見仁見智,但普遍傾向于前者,畢竟一勞永逸,導入后用modulename.blahblah 可訪問module中的任意可訪問的對象,也符合python的namespace hirearchy理念。
所以,您試著再改回import X唄。這里就不貼代碼了。
我的實際問題
server.py 是主入口程序,其中有一個 Cases 列表,其中羅列的是多個class的實例(instance), 如 case_no_file() 是 class case_no_file的實例。
cases.py中定義了這些列表 item class 如 case_no_file,其父類是 base_case
base_case.py 中定義了父類 base_case
部分代碼如下:
Server.py:
import BaseHTTPServer
import cases
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
Cases = [case_no_file(),
case_cgi_file(),
case_existing_file(),
case_directory_index_file(),
case_directory_no_index_file(),
case_always_fail()]
base_case.py:
class base_case(object):
'''Parent for case handlers.'''
def handle_file(self, handler, full_path):
try:
with open(full_path, 'rb') as reader:
content = reader.read()
handler.send_content(content)
except IOError as msg:
msg = "'{0}' cannot be read: {1}".format(full_path, msg)
handler.handle_error(msg)
cases.py:
import base_case
class case_existing_file(base_case):
'''File exists.'''
def test(self, handler):
return os.path.isfile(handler.full_path)
def act(self, handler):
self.handle_file(handler, handler.full_path)
運行 "python server.py"的時候,報錯了:
Traceback (most recent call last):
File "server.py", line 2, in
import cases
File "c:\projects\python\500lines\simple-web-server\simple-web-server\cases.py", line 4, in
class case_existing_file(base_case):
TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given)
根據前面的分析,修改 server.py 和 cases.py如下后,運行正常:這里仍然用的是 import module。
server.py:
import cases
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
Cases = [cases.case_no_file(),
cases.case_cgi_file(),
cases.case_existing_file(),
cases.case_directory_index_file(),
cases.case_directory_no_index_file(),
cases.case_always_fail()
]
cases.py:
import base_case
class case_existing_file(base_case.base_case):
'''File exists.'''
def test(self, handler):
return os.path.isfile(handler.full_path)
def act(self, handler):
self.handle_file(handler, handler.full_path)
總結:
1 module 是什么
A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended
2 module 和 class 的區別:
module 包含 class
module 只是一個實例,不能繼承。 class可以有多個實例,可以單繼承,多繼承
module 名一般小寫,class名一般大寫
繼承時如果傳入的是module, 提示的錯誤是module.__init__方法調用參數有誤,比較模糊,具體分析見上文。
3 import 和 from ... import的區別:
import 導入的是 module
from a import b, 是從 module a 中導入 b, b可以是 module, class, function, variable
一般建議用import module;
參考資料
歡迎一起討論學習!
總結
以上是生活随笔為你收集整理的python import from class_Python: import vs from (module) import function(class) 的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java表单提交包含文件_如何同时提交表
- 下一篇: python3.7怎么安装dlib_py