从其他py⽂件中导⼊类报错_彻底搞懂Python中的import与
fromimport
对不少 Python 初学者来说,Python 导⼊其他模块的⽅式让他们很难理解。什么时候⽤import xxx?什么时候⽤from xxx import yyy?什么时候⽤ import zzz?什么时候⽤from xxx import *?
这篇⽂章,我们来彻底搞懂这个问题。
系统⾃带的模块
以正则表达式模块为例,我们经常这样写代码:
1 2 3 4import re
target = 'abc1234xyz' re.search('(d+)', target)
但有时候,你可能会看到某些⼈这样写代码:
1 2 3from re import search target = 'abc1234xyz' search('(d+)', target)
那么这两种导⼊⽅式有什么区别呢?
我们分别使⽤type函数来看看他们的类型:
1 2 3 4 5 6>>> import re
>>> type(re)
<class 'module'>
>>> from re import search >>> type(search)
<class 'function'>
python怎么读取py文件如下图所⽰:
可以看到,直接使⽤import re导⼊的re它是⼀个module类,也就是模块。我们把它成为正则表达式模块。⽽当我们from re import search时,这个search是⼀个function类,我们称呼它为search 函数。
⼀个模块⾥⾯可以包含多个函数。
如果在你的代码⾥⾯,你已经确定只使⽤search函数,不会再使⽤正则表达式⾥⾯的其他函数了,那么你使⽤两种⽅法都可以,没什么区别。
但是,如果你要使⽤正则表达式下⾯的多个函数,或者是⼀些常量,那么⽤第⼀种⽅案会更加简洁清晰。
例如:
1 2 3import re
re.search('c(.*?)x', flags=re.S)
re.sub('[a-zA-Z0-9]', '***', target, flags=re.I)
4
在这个例⼦中,你分别使⽤了re.search ,re.sub ,re.S 和re.I 。后两者是常量,⽤于忽略换⾏符和⼤⼩写。
但是,如果你使⽤from re import search, sub, S, I 来写代码,那么代码就会变成这样:
1
2
3
4import re search('c(.*?)x', flags=S)sub('[a-zA-Z0-9]', '***', target, flags=I)
看起来虽然简洁了,但是,⼀旦你的代码⾏数多了以后,你很容易忘记S 和I 这两个变量是什么东西。⽽且我们⾃⼰定义的函数,也很有可能取名为sub 或者search ,从⽽覆盖正则表达式模块下⾯的这两个同名函数。这就会导致很多难以觉察的潜在 bug。
再举⼀个例⼦。Python 的 datetime 模块,我们可以直接import datetime ,此时我们导⼊的是⼀个datetime
模块,如下图所⽰:
但是如果你写为from datetime import datetime ,那么你导⼊的datetime 是⼀个type
类:
因为这种⽅式导⼊的datetime ,它就是Python 中的⼀种类型,⽤于表⽰包含⽇期和时间的数据。
这两种导⼊⽅式导⼊的datetime ,虽然名字⼀样,但是他们的意义完全不⼀样,请⼤家观察下⾯两种写法:
1
2
3
4import datetime now = w()one_hour_ago = now - datetime.timedelta(hours=1)
1
2
3from datetime import datetime, timedelta now = w()one_hour_ago = now - timedelta(hours=1)
第⼆种写法看似简单,但实则改动起来却更为⿇烦。例如我还需要增加⼀个变量today ⽤于记录今⽇的⽇期。
对于第⼀段代码,我们只需要增加⼀⾏即可:
1today = day()
但对于第⼆⾏来说,我们需要⾸先修改导⼊部分的代码:
1from datetime import datetime, timedelta, date
然后才能改代码:today = day()
这样⼀来你就要修改两个地⽅,反倒增加了负担。
第三⽅库
在使⽤某些第三⽅库的代码⾥⾯,我们会看到类似这样的写法:
1
2
3from lxml.html import fromstring selector = fromstring(HTML)
但是我们还可以写为:
1
2
3from lxml import html selector = html.fromstring(HTML)
但是,下⾯这种写法会导致报错:
1
2import lxml selector = lxml.html.fromstring(HTML)
那么这⾥的lxml.html ⼜是什么东西呢?
这种情况多常见于⼀些特别⼤型的第三⽅库中,这种库能处理多种类型的数据。例如lxml 它既能处理xml 的数据,⼜能处理html 的数据,于是这种库会划分⼦模块,lxml.html 模块专门负责html 相关的数据。
⾃⼰来实现多种导⼊⽅法
我们现在⾃⼰来写代码,实现这多种导⼊⽅法。
我们创建⼀个⽂件夹DocParser ,在⾥⾯分别创建两个⽂件main.py 和util.py ,他们的内容如下:
util.py ⽂件:
1
2def write():print('write 函数被调⽤!')
main.py ⽂件:
1
2
3import util util.write()运⾏效果如下图所⽰:
现在我们把main.py 的导⼊⽅式修改⼀下:
1
2
3from util import write write()
依然正常运⾏,如下图所⽰
当两个⽂件在同⼀个⽂件夹下⾯,并且该⽂件夹⾥⾯没有 init init.py ⽂件时,两种导⼊⽅式等价。现在,我们来创建⼀个⽂件夹microsoft ,⾥⾯再添加⼀个⽂件parse.py :
1
2def read():print('我是 microsoft ⽂件夹下⾯的 parse.py 中的 read函数')如下图所⽰:
此时我们在 main.py 中对它进⾏调⽤:
1
2
3from microsoft import ad()
运⾏效果如下图所⽰:
我们也可以⽤另⼀种⽅法:
1
2
3from microsoft.parse import read read()运⾏效果如下图所⽰:
但是,你不能直接导⼊microsoft ,如下图所⽰:
你只能导⼊⼀个模块或者导⼊⼀个函数或者类,你不能导⼊⼀个⽂件夹
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论