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>
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 <module>
import cat
File "C:\projects\Python\500lines\simple-web-server\simple-web-server\cat.py", line 3, in <module>
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)

其实不是模糊不清,背后的逻辑请参考What happens when you inherent from a module instead of a class in Python? - Stack Overflow,解释的很清楚,下次遇到这种问题的时候就不会没有头绪了。

简单的解释就是:

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)
<type 'module'>
>>> from animal import Animal
>>> type(Animal)
<type 'type'>

当我们导入 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呗。这里就不贴代码了。

我的实际问题

我是跟着这个500 Lines or Less | A Simple Web Server在学,简化一下项目的结构如下:

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 <module>
import cases
File "c:\projects\python\500lines\simple-web-server\simple-web-server\cases.py", line 4, in <module>
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 - from ... import vs import . - Stack Overflow

What happens when you inherent from a module instead of a class in Python? - Stack Overflow

欢迎一起讨论学习!

Python: import vs from (module) import function(class) 的理解的更多相关文章

  1. 关于Python Package下的Module import方式[转]

    2012年有一个目标我没有达成,那就是深入学习和使用Python语言.这个目标被其他学习任务和工作无情的抢占了,当然最主要的原因还是我重视不够^_^. 近期恰逢有一些Python工程的开发工作要做,就 ...

  2. python中from module import * 的一个陷阱

    from module import *把module中的成员全部导到了当前的global namespace,访问起来就比较方便了.当然,python style一般不建议这么做,因为可能引起nam ...

  3. python import 错误 TypeError: 'module' object is not callable

    python import 错误 TypeError: 'module' object is not callable 在这里,有 Person.py test.py; 在 test.py 里面 im ...

  4. Python中from module import *语法

    from module import *的语法在Python 3.X和Python 2.X中的使用稍有区别: 在Python 3.X中,from module import *无法在函数里面使用,而在 ...

  5. python 动态加载module、class、function

    python作为一种动态解释型语言,在实现各种框架方面具有很大的灵活性. 最近在研究python web框架,发现各种框架中需要显示的定义各种路由和Handler的映射,如果想要实现并维护复杂的web ...

  6. 编译caffe的Python借口,提示:ImportError: dynamic module does not define module export function (PyInit__caffe)

    >>> import caffeTraceback (most recent call last): File "<stdin>", line 1, ...

  7. Python 中包/模块的 `import` 操作

    版权声明:博客为作者原创,允许转载,但必须注明原文地址: https://www.cnblogs.com/byronxie/p/10745292.html 用实例来说明 import 的作用吧. 创建 ...

  8. [zz] Python 3.7 anaconda environment - import _ssl DLL load fail error

    https://stackoverflow.com/questions/54175042/python-3-7-anaconda-environment-import-ssl-dll-load-fai ...

  9. phoenix客户端连接hbase数据库报错:Traceback (most recent call last): File "bin/sqlline.py", line 27, in <module> import argparse ImportError: No module named argparse

    环境描述: 操作系统版本:CentOS release 6.5 (Final) phoenix版本:phoenix-4.10.0 hbase版本:hbase-1.2.6 现象描述: 通过phoenix ...

随机推荐

  1. 关于js参数传递矛盾新理解

    之前看了很多人的解释,说js中,函数的参数传递都是值传递中不理解. 他们无非举了两个例子 在这两个例子中,第二个例子可以看出参数是由值传递的.因为函数内对象的变化没有影响到函数外对象的变化.但是在第一 ...

  2. 谈谈一些有趣的CSS题目(十四)-- 纯 CSS 方式实现 CSS 动画的暂停与播放!

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  3. PRINCE2学习

    今天对PRINCE2中提及的7大主题进行学习,主要的内容是通过概述和PMBOK之间的对比做一些总结,每个主题所包含的过程和方法并没有太多涉及,没有对整个体系有全面深入的学习,有些断章取义的地方也请博友 ...

  4. freemarker导出word文档——WordXML格式解析

    前不久,公司一个项目需要实现导出文档的功能,之前是一个同事在做,做了3个星期,终于完成了,但是在项目上线之后却发现导出的文档有问题,此时,这个同事已经离职,我自然成为接班者,要把导出功能实现,但是我看 ...

  5. Android -- onMeasure()源码分析

    1,作为自定义控件最重要的三个方法之一,onMeasure()可以说是我们研究的重点,今天我们更详细的来研究一下View的onMeasure()方法和ViewGroup的onMeasure()方法 2 ...

  6. 老李分享:Android性能优化之内存泄漏3

    线程造成的内存泄漏 对于线程造成的内存泄漏,也是平时比较常见的,如下这两个示例可能每个人都这样写过: //——————test1 new AsyncTask<Void, Void, Void&g ...

  7. Uva 679 Dropping Balls (模拟/二叉树的编号)

    题意:有一颗二叉树,深度为D,所有节点从上到下从左到右编号为1,2,3.....在结点一处放一个小球,每个节点是一个开关,初始全是关闭的,小球从顶点落下,小球每次经过开关就会把它的状态置反,现在问第k ...

  8. 设置ARC有效或者无效

    在编译单位上,可以设置ARC有效或者无效.比如对每个文件可以选择使用或者不使用ARC,一个应用程序中可以混合ARC有效或者无效的二进制形式. 设置ARC有效的编译方法如下所示:(Xcode4.2开始默 ...

  9. linux mail命令详解

    用程序发送邮件有3种方式,分别是: 1.模拟http请求邮件服务商网页实现邮件的发送 2.如果邮件服务商开通了smtp服务,那么可以通过smtp协议通过邮件代理服务商发送邮件 3.自己部署邮件服务器, ...

  10. Python标准模块--importlib

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 模块简介 Python提供了importlib包作为标准库的一 ...