python拷贝是什么知识点_手把手教你学python第十七讲(模块导入的相关知识和爬虫的准备内含深浅拷贝)...

str和repr

参考了https://blog.csdn.net/sxingming/article/details/52065242

介绍正式内容之前,先来补充一个repr和str的不同点。以前我们用过__str__和__repr__我直接给一个例子复习一下

现在你们应该是可以看懂错误原因了,我不再多解释了。下面是正确的做法

那么我们来先看一下str和repr在python里的帮助怎么说的,str是一个类对象,repr是python的内置函数。

实际用一下

这里我直接复制了,敬请体谅,因为其实之前我已经写过一遍这篇文章了,但是没有保存,然后。。。所以我已经不想打字了。其实下面就是python官方文档的中文翻译。

什么解释器呢?我们官网下的其实自带cpython的解释器,因为是用c语言编写的,还有其它的比如用java编写的jpython,所谓解释器,其实就是运行.py文件的这个一个东西。关于截图里说的一点浮点数,我尝试了下,发现似乎并没有什么不同的地方。并且元组集合的结果也是一样的。

这里就再顺带提一下前面出现过的evalhttps://www.cnblogs.com/liu-shuai/p/6098246.html。你们就到这个网站直接去看看好吧。我是真的有点火气。

str和repr对于字符串结果的差异也体现出来了

简单来说就像是把最外面的引号去掉的功能。下面简单演示一下eval实现了str和list之间的转化,其它的容器类型类似。直接用list是不行的,用eval是可以的。

模块导入相关的知识

先来补充一个变量的搜索顺序,命名空间和locals(),globals()几个知识点。参考了https://blog.csdn.net/scelong/article/details/6977867和

https://www.cnblogs.com/wanxsb/archive/2013/05/07/3064783.html和

https://www.cnblogs.com/shanys/p/5887023.html

下面说的名字空间就是命名空间

看几个尝试

说明locals()只有在函数里面用有意义,在函数外面直接在模块里面用locals()相当于globals(),globals()在一个模块里的的位置不影响结果。而且globals()会屏蔽掉人为的改动,而globals()则不会,因为其实函数的locals()只是一个拷贝而已,并不会影响函数里变量的值。

闭包也不是例外

如果哪个变量是global,那么它将不会出现在函数的locals()里

这个搜索顺序其实很好理解,我们先来看1,2的先后是怎么体现的。

2和3的顺序怎么体现的呢?

我觉得如果你跟着我一直学到这里,通过对比代码,你是可以理解的。

内置名字空间其实是可以看到的

这还并没有截全。

什么是模块,前面其实也说过。

我们去看个模块,还记得以前有个os模块吗?我们来看一下

这只是截取了一段代码。在安装目录的lib里有很多模块的代码

导入模块有三种方法,这三种前面都已经讲过,这里就简单地演示一下

第一种方法我们适合用模块名比较短的时候,因为每次调用模块的属性或者函数的时候都要打一边模块名字。

我们看一下这种方式对于locals()的影响

看到这里你也应该理解为什么前面必须加上模块名了。这种方法不能也没有必要导入单个函数或者变量

至于报错说的os不是一个pakage是什么意思我们下面会说。还有一点,不知道你注意到没有,前面是有写到变量的。

第二种方法还可以用通配符*来导入所有的函数和变量,我们来看一下对globals()的影响

导入某个具体的函数或者变量,这个函数名或者变量会直接出现在globals()里面,而用通配符*导入会把模块里所有的函数和变量加到globals()里面

不推荐使用,因为很可能两个模块的属性或者函数名有重叠的,就会发生取代现象。比如假如我们有下面两个模块a,b都有t函数

用方法二导入后面的就会取代前面的,这就是globals()里的变量名字重合了,而且第二种方法是不可以用第一种模块的调用格式的。

如果有一些隐私变量,你不想被from a import*导入,你可以在变量或者函数前面加一个_,举个例子

可以看出来这种隐藏方法只能应付from my import*这种格式,其它的方式都还是可以调用到的。看一下globals()就能理解为什么了

第二种方法可能会导致循环导入问题,例子

先后执行a.py,b.py

这是为什么呢?

我们先来看一下from a import x到底是什么一个过程

虽然仅仅是导入了x,但是还是运行了整个a.py。然后我们来分析一下,运行b.py的时候,第一行是from a import x,然后就跳到a.py,又遇到第一行from b import y,又跳到b.py又遇到第一行from a import x,就是一个无限循环。但是python开发人员应该是有自己的一套处理这种问题的办法,有内置的异常处理,从而这种无限循环停在和起始相同的地方。开始是from a import x,结束也是在from a import x。

为了这里稍微理解深入一点,我做了以下改动来看看效果。

改动1

b.py没有改变。想一想运行a.py和b.py分别有什么结果呢?

运行a.py为什么会这样呢?前三行是加载了x的,从a.py模块的locals()也能看出来(这里的locals()和globals()没什么区别),第四行from b import y,CPU跳到了b.py,而第二行就是from a import x,我们又跳到了a.py。这里是不是会有小问题?前面不是已经加载了x吗?但是要注意我们执行的脚本是a.py,在a.py的globals()里有,但是在要导入的模块b.py的globals()是没有这个东西的,所以这里仍然会跳到a.py,然后就出现了重复性导入,在黑圈里的语句一样的嘛。

我们稍微来验证一下,修改a.py和b.py如下

这里有一个小细节不知道你们注意到没有,为什么b.py前后是*号?这代表你做了修改但是没有保存,你保存一下就可以了,Ctrl+S或者F5运行一下,运行自动保存嘛,就没有了。

运行一下a,py,结果很长哈,我们用Edit里的Find来找'x',最后结果只找到下面一个红箭头指的地方。

只是为了让你信服b.py的globals()里确实没有'x'这个东西的。下面为了节省空间都把print(globals())去掉了。

那么b.py是个怎么样的过程呢?第二行from a  import x跳到a.py,前三行已经把x导入到了b.py的globals()里了,到第四行from b import y,跳到b.py这时候就不用在第二行跳了,因为已经有了x了,于是就打印了离开b,而我们只从a的第四行跳过来的,又回去打印离开a,a又是从b.py的第二行跳过来的,跳回去执行结束打印离开b。过程就下面这样,红色序号是打印的顺序。

下面这个小改动看着上面这个图应该好分析。

前面也说了这种不建议使用,下面的改动就看看结果,就不展开分析了

改动二

分别运行a.py和b.py

看上去a好像是没有问题的,但是还是有问题,所以不建议使用第二种方式

那么第一种方法表现如何?我认为这里python也是有机制的,如果a.py里出现了import  b,那么后来再遇到import b应该就不会再跳转了,我们先来试验一下这个特性对不对。

果然如此啊,因为进入b和离开b都只打印了一次。

循环嵌套导入的问题是解决了,但是,还是有问题的,

所以还是别随便循环嵌套导入,可能会出现各种问题。当然这些问题不是不能解决的,下面会有解决的办法。

第三种就是用as 后面的新名字代替前面的模块名而已,模块名很长的时候可以考虑,但是新名字别乱取,可能会和别的模块重名的

除了要说三种导入方法之外呢,还有以下三点内容

下面参考了https://www.zhihu.com/question/49136398。和http://blog.konghy.cn/2017/04/24/python-entry-program/。

下面这段话我们看一看就好

如果你学过c语言,应该会理解得更快,因为mian(){}就是一个程序入口。下面这段我们要理解一下

我们先来看一下__name__,我们新启动一次IDLE之后,没有运行任何脚本也就是.py文件时

我们运行下面这样一个脚本文件的时候。

并且是不会显示隐藏的变量_b和_m的。虽然调用是正常的,只是不显示,如果不显示别人也不知道有这些隐藏的东西,就比较隐私嘛

如果不是直接运行a.py文件而是把它作为一个模块导入的时候

打印的就是my了,也就是文件的名字(不包含扩展名)。也就是说

我们来稍微看一下前面的循环嵌套导入会是怎样的一个情况。

运行a.py

用一张简单的图来说就是,红色是前向的顺序,黄色是回去的顺序。可以发现在a.py里运行到import b的时候,就跳到了b.py,然后又跳到a.py里运行,虽然我们运行的是a.py,但是在这个时候,a.py是在b.py里导入的,所以print(__name__)就是a,然后回到b.py里,打印的__name__是b,这很好理解,然后回到a.py里,这是我们运行的那个a.py。所以打印的是__main__。

这有什么用呢?至少我们上面出现的错误,我在a里加这么一句。

就不会报错了,如果你看懂了上面的轨迹,你应该知道为什么不会报错了而且也知道为什么上面会报错。在b.py里加上一个if __name__='__main__'也有一样的效果,原理一样的嘛,就不展示了。__name__='__mian__'通常的用处是拿来做测试,比如说

在运行my.py的时候我们希望这个测试成功打印出来。但是当它作为模块被导入的时候不希望测试的结果打印出来。那么我们就可以用__name__=='__main__'。

当然这个__name__其实是可以改的。可以改为已经有的脚本名字,但是改这个没有太大意义。

你可以这么皮一下,貌似会有用处。

下一个问题搜索路径。什么是搜索路径呢?就类似于上面说过的变量和函数的搜索顺序,如果在路径里,当然路径是有顺序的,都没有找到的话,就会报错。

比如我现在在桌面有一个my.py

我能成功导入吗?

出错了。因为不在sys.path里面,我们可以添加进去

然后我们来看一下搜索顺序是怎么样的。我新创建一个同名的文件,位置如标题栏显示的

注意这里要先Restart一下,因为你新建了一个文件,如果没有运行过它,IDLE

还没有添加它

这个sys.path可以改变,你就可以自己改变搜索顺序了,你可以对sys,path为所欲为

。只是需要RESTART一下哦。但是注意一点,你对sys.path的任何改动都不会影响内置的开发人员编写的内部模块,下面并不影响os的导入,但是影响到了我们自己添加的模块my的导入。

你可能感兴趣的:(python拷贝是什么知识点)