作者:下家山(qq:1209050967,微信:xiajiashan)
二十九 函数
29.1 什么是函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。
Python提供的内建函数,比如print(),比较函数cmp(obj1,obj2),求最大值max(obj)和最小值函数min(obj)。但你也可以自己创建函数,这被叫做用户自定义函数。
29.2 自定义函数的特征
1:以def关键字开头;
2:def后面紧跟一个空格,然后是函数名(函数名不能以数字开头);
3:函数名后面紧跟一个圆括号,中间可以有0~多个空格,一般是0个;
4:原括号里面可以有零个(0个参数时,括号不能省略),或多个参数,多个参数之间以逗号分开。
5:原括号后面是冒号
6:函数体以return结束
7:函数体要有缩进
29.3 自定义的使用
注意:return 不要也可以
29.4 函数中的值传递
变量a的值,并没有通过modify函数修改为100.
我们在第7行定义了一个变量a=200
在第八行,调用了modify函数,并把a传进去,此时,a=200是实际参数,在第2行中的a是形式参数(大家不要误以为这两个a是一回事,这就像一个班有两个人的名字都叫王兴一个道理,你喜欢的是他的身体和个性,而不是那个名字),所以当把a=200传给形参a的时候,a=200还在,在第8行只不过是把把变量a的值(200)传给了形参。所以,变量a的值没有发生变化,在第9行打印出来还是200。
29.5 函数中的地址传递
上述情况就是传的地址
过程及原理如图所示
注意以下情况:
29.6 关于深拷贝(deepcopy)和浅拷贝(copy)
浅拷贝,即拷贝地址
深拷贝,即拷贝地址里面的内容
但是要注意,深拷贝只有在嵌套的列表中才有意义,单层列表不取作用
Win7中python3.6.1的shell运行结果
Win7中pycharm运行结果
29.7 函数参数列表
如果某个函数有形参,当我们调用的时候必须传一个实际参数进去。
如果不传呢?
怎么解决这个问题?
当我们定义函数的时候,给他默认参数值,则在调用的过程中,如果不给实际参数,那么系统将采用默认函数参数值。这样可以避免用户漏给参数。
多个参数的情况
多个参数,默认参数情况
29.8 可变长参数
如果去掉第一个形参arg1可以吗?
去掉可变长参数中的第一个形参也是可以的。
29.9 python 3.0+版本中如何去掉换行?
29.10 可变长参数是列表,元组,字典的情况
可变长参数接受元组的情况
系统默认会以元组来缓冲冗余的参数
可变参数是字典的情况
当我们实参传一个字典给可变参数,那么系统还是把它当成一个元组
29.11 双星**的情况
注意:函数调用的时候,必须一对一,也就是,第三个参数必须是一个字典
比如这样是错误的
29.12 匿名函数
python 使用 lambda来创建匿名函数。
Lambda语法:
Lambda [arg1 [,arg2,arg3,…,argn]]:expression
案例:
Lambda的规则
· lambda只是一个表达式,函数体比def简单很多。
· lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
· lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
· 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
Lambda的作用
以下引用于知乎上的路人甲
我特别喜欢吃核桃,以前我吃核桃的时候我都是这样吃的:一个一个用手剥了吃。
29.13 return语句
Return语句是否是必须的?
下面这种情况是必须的
下面这种情况是可有可无的
去掉return
29.14 变量的作用域
注意:局部变量与全局变量同名,在函数体内,使用的是局部变量,其他作用域则使用的是全局变量。
三十 模块
http://blog.csdn.net/love_is_all_in_life/article/details/49967427
Python中的模块(Module)是一个以.py为后缀的文件(python程序代码)。
模块里面包含变量,函数,以及可执行代码。
模块的作用:作为一个独立单元,方便其他程序反复调用。
30.1 自定义一个实现加减乘除的模块
注意:#-*-coding:utf8-*-是为了支持中文
From __future__ import divison是为了实现默认精确除法(关于精确除法见6.6节)
30.2 如何使用自定义模块
30.3 关于from … import语句
我在arithmetic模块中写了4个函数,当我用import导入arithmetic的时候,实际上导入了这个模块中的所有内容,如果我只需要其中的某一部分功能,则并不需要这样。此时from…import就有用了。
From…import 格式
From modulename importfunctionname
From和import是关键字
Modulename是你要导入的模块名
Functionname是你要从模块modulename中导入的哪个函数
具体实例如下:
注意:from arithmeticimport func_mutli不要写成
From func_mutli import arithmetic
30.4 关于from…import *语句
From … import是导入模块中的某一个函数;
而from…import *是导入模块中的所有函数;
30.5 import,from … import,from … import *三者的区别
Import是导入整个模块,from…import*是导入模块中所有的内容
那么他们两者有什么区别呢?
我们先来看看他们的实例截图:
区别在于:import artithmetic这种方式,在使用模块中的函数的时候,需要通过模块名.的形式,如:
而from arithmetic import *则可以直接使用模块中的函数,无需在函数前给模块名(当然,你给模块名也可以)
30.6 python是如何找到你所导入的模块的
当我们使用Pycharm这种IDE工具来写python代码的时候,我们导入一个模块,系统马上可以帮我们检索模块中的变量或者函数,那么python是怎么搜索到的呢?
当你导入一个模块,Python 解析器对模块位置的搜索顺序是:
· 1、当前目录
· 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
· 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/lib/python2.7/。
模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。
我们来看看sys.path
上面是Ubuntu中python的环境变量路径
这是windows上sys.path的路径
30.7 如何设置python的环境变量
作为环境变量,PYTHONPATH由装在一个列表里的许多目录组成。PYTHONPATH的语法和 shell 变量 PATH 的一样。
在 Windows 系统,典型的 PYTHONPATH 如下:
set PYTHONPATH=c:\python27\lib;
在 UNIX 系统,典型的 PYTHONPATH 如下:
set PYTHONPATH=/usr/local/lib/python
30. xx 命名空间到讲类的时候再
30.8 import xxx as xx
三十一:系统模块sys和os
os与sys模块的官方解释如下:
os:This module provides a portable way of using operating system dependentfunctionality.
这个模块提供了一种方便的使用操作系统函数的方法。
sys:This module provides access to some variables used or maintained by theinterpreter and to functions that interact strongly with the interpreter.
这个模块可供访问由解释器使用或维护的变量和与解释器进行交互的函数。
总结就是,os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;sys模块负责程序与Python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
os常用方法
os.remove(‘path/filename’)删除文件
os.rename(oldname,newname) 重命名文件
os.walk()生成目录树下的所有文件名
os.chdir('dirname')改变目录
os.mkdir/makedirs('dirname')创建目录/多层目录
os.rmdir/removedirs('dirname')删除目录/多层目录
os.listdir('dirname')列出指定目录的文件
os.getcwd()取得当前工作目录
os.chmod()改变目录权限
os.path.basename(‘path/filename’)去掉目录路径,返回文件名
os.path.dirname(‘path/filename’)去掉文件名,返回目录路径
os.path.join(path1[,path2[,...]])将分离的各部分组合成一个路径名
os.path.split('path')返回(dirname(), basename())元组
os.path.splitext()返回 (filename,extension) 元组
os.path.getatime\ctime\mtime分别返回最近访问、创建、修改时间
os.path.getsize()返回文件大小
os.path.exists()是否存在
os.path.isabs()是否为绝对路径
os.path.isdir()是否为目录
os.path.isfile()是否为文件
sys常用方法
sys.argv命令行参数List,第一个元素是程序本身路径
sys.modules.keys()返回所有已经导入的模块列表
sys.exc_info()获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
sys.exit(n)退出程序,正常退出时exit(0)
sys.hexversion获取Python解释程序的版本值,16进制格式如:0x020403F0
sys.version获取Python解释程序的版本信息
sys.maxint最大的Int值
sys.maxunicode最大的Unicode值
sys.modules返回系统导入的模块字段,key是模块名,value是模块
sys.path返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform返回操作系统平台名称
sys.stdout标准输出
sys.stdin标准输入
sys.stderr错误输出
sys.exc_clear()用来清除当前线程所出现的当前的或最近的错误信息
sys.exec_prefix返回平台独立的python文件安装的位置
sys.byteorder本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little'
sys.copyright记录python版权相关的东西
sys.api_version解释器的C的API版本
sys.stdin,sys.stdout,sys.stderr
stdin , stdout , 以及stderr 变量包含与标准I/O流对应的流对象. 如果需要更好地控制输出,而print 不能满足你的要求, 它们就是你所需要的. 你也可以替换它们, 这时候你就可以重定向输出和输入到其它设备( device ), 或者以非标准的方式处理它们
我们常用print和raw_input来进行输入和打印,那么
print和 raw_input是如何与标准输入/输出流建立关系的呢?
其实Python程序的标准输入/输出/出错流定义在sys模块中,分别为:sys.stdin,sys.stdout, sys.stderr
下列的程序也可以用来输入和输出是一样的:import sys
sys.stdout.write('HelloWorld!')
print'Please enter yourname:',
name=sys.stdin.readline()[:-1]
print 'Hi,%s!' % name
那么sys.stdin, sys.stdout, stderr到底是什么呢?我们在Python运行环境中输入以下代码:import sys
for f in(sys.stdin,sys.stdout, sys.stderr): print f
输出为:
<openfile'<stdin>', mode 'r' at 892210>
<openfile'<stdout>', mode 'w' at 892270>
<openfile'<stderr>', mode 'w at 8922d0>
由此可以看出stdin, stdout, stderr在Python中无非都是文件属性的对象,他们在Python启动时自动与Shell 环境中的标准输入,输出,出错关联。
而Python程序的在Shell中的I/O重定向与本文开始时举的DOS命令的重定向完全相同,其实这种重定向是由Shell来提供的,与Python 本身并无关系。那么我们是否可以在Python程序内部将stdin,stdout,stderr读写操作重定向到一个内部对象呢?答案是肯定的。
Python提供了一个StringIO模块来完成这个设想,比如:
from StringIO import StringIO
import sys
buff =StringIO()
temp=sys.stdout #保存标准I/O流
sys.stdout=buff #将标准I/O流重定向到buff对象
print 42, 'hello', 0.001
sys.stdout=temp #恢复标准I/O流
print buff.getvalue()
三十二:内置函数
Python内置(built-in)函数随着python解释器的运行而创建。在Python的程序中,你可以随时调用这些函数,不需要定义。最常见的内置函数是:
print("Hello World!")
常见的python内置函数如下:
|
| 内置函数 |
|
|
unicode() | ||||
| ||||
| ||||
object() |
| |||
32.1 dir()函数
Dir()函数返回一个模块中定义过的名字,这些名字以字符串的形式返回,而且是排过序的一个字符串列表。
比如,我们要看看math这个模块内容,可以这样:
那么这里的'__doc__','__name__', '__package__’是什么呢?
那么__doc__到底有什么用呢?
这里,我们可以看到__doc__可以输出math中sin函数的用法。
我们来看看我们自己定义的模块
那么这里’__builtins__', '__cached__', '__doc__', '__file__', '__loader__','__name__', '__package__', '__spec__'是什么意思呢?
以上是在python3.6.1中执行结果
以上是在pycharm上执行结果
32.1.1 dir()函数的作用
Dir函数的作用在于,当你不知道math这个模块中有哪些函数的时候,你可以通过dir(math)返回,正如上所述。
比如,你不知道我们所定义的模块arithmetic中的函数,那么通过dir(arithemtic)就可以知道了。
32.2 globals()函数和locals()函数
Globals()函数
Globals()函数返回当前命名空间中所有的全局变量
注意,from moduleimport 和 import module之间的不同。使用 import module,模块自身被导入,
但是它保持着自已的名字空间,这就是为什么你需要使用模块名来访问它的函数或属性(module.function)
的原因。但是使用 from module import,实际上是从另一个模块中将指定的函数和属性导入到你自己的名字
空间,这就是为什么你可以直接访问它们却不需要引用它们所来源的模块的原因。
Locals()函数
Locals()函数以字典的形式返回当前函数的局部变量,包括参数!
全局变量返回值,局部变量返回值,为什么一样呢?
如果在当前命名空间的范围内打印locals()返回值,是什么情况呢?
从以上现象,我们知道,当我们把locals函数放在函数内部,那么他的可视范围为当前函数,所以他只会打印当前函数add里面的局部变量包括参数部分,如果把他放在当前程序(实际上是当前命名空间),那么locals返回的是当前命名空间的局部变量,也就等于当前命名空间的全局变量。
32.3 reload()函数
Reload()函数表示重新装载某一个模块
当使用该模块的时候
注意,在原模块中和,新模块的var1的地址是一样的。
第二次导入同一个模块,不会再执行原模块中语句。
很失败,在python2.7之后,已经没有reload函数了!
三十三:python中的包
模块,库,包的区别
https://www.zhihu.com/question/30082392?sort=created
http://www.jb51.net/article/63943.html
http://blog.csdn.net/offbye/article/details/39029051(后续研究一下sys.path)
33.1 不用包会这么样
很多初学者,学习一个知识点,首先想到的是我学这个有什么用,当他知道了学这个东西的重要性,甚至必学不可的时候,他才会用心去学。为了打消各位这种顾虑,我先讲python中为什么要有包这个感念,设计包的目的是什么?
假设我们有个package1的总目录,在这个总目录下又有subpack1,subpack2两个子目录;在subpack1子目录下有module11.py,module12.py,module13.py这三个文件;在subpack2的子目录下有module21.py,module22.py,module23.py这三个文件。
在于总目录package1平级的位置有一个package_test.py文件。
结构如下所示:
package1
subpack1
module11.py
module12.py
module13.py
subpack2
module21.py
module22.py
module23.py
package_test.py
其中,module11.py中的代码如下:
#----python包研究------ #-*-coding:utf8-*- def fun_11(): print("我在module11中...") return
类似的,在module12.py中的代码如下:
#----python包研究------ #-*-coding:utf8-*- def fun_12(): print("我在module12中...") return
在module13.py中的代码如下:
#----python包研究------ #-*-coding:utf8-*- def fun_13(): print("我在module13中...") return
其中,module21.py中的代码如下:
#----python包研究------ #-*-coding:utf8-*- def fun_21(): print("我在module21中...") return
Module22.py中的代码如下:
#----python包研究------ #-*-coding:utf8-*- def fun_22(): print("我在module22中...") return
Module23.py中的代码如下:
#----python包研究------ #-*-coding:utf8-*- def fun_23(): print("我在module23中...") return
现在我们要在pacage_test.py中调用module11.py中函数fun_11,代码如何实现呢?
假设我们这样写:
#----python包研究------ #-*-coding:utf8-*- import module11 module11.fun_11()
运行结果如下:
我们该怎么办呢?
采用from吗?
行不通!python系统怎么解决这个问题呢?
Sys和os模块参考第三十一章:《系统模块sys和Os》
sys.path.append(os.getcwd()+'\\package1\\subpack1\\')
这一句是吧module11模块所在路径添加到python的系统路径中。
这样地6句就能找到module11.py模块了,第7句调用fun_11函数的时候就会执行成功。
那么python中的系统路径是个什么样子呢?
我们来做一个实验。
33.2 python是如何去搜索一个模块的
python在执行import语句时,到底进行了什么操作,按照python的文档,它执行了如下操作:
- 第1步,创建一个新的,空的module对象(它可能包含多个module);
- 第2步,把这个module对象插入sys.module中
- 第3步,装载module的代码(如果需要,首先必须编译)
- 第4步,执行新的module中对应的代码。
在执行第3步时,首先要找到module程序所在的位置,其原理为:
如果需要导入的module的名字是m1,则解释器必须找到m1.py,它首先在当前目录查找,然后是在环境变量PYTHONPATH中查找。 PYTHONPATH可以视为系统的PATH变量一类的东西,其中包含若干个目录。如果PYTHONPATH没有设定,或者找不到m1.py,则继续搜索与python的安装设置相关的默认路径,在Unix下,通常是/usr/local/lib/python。
事实上,搜索的顺序是:当前路径(以及从当前目录指定的sys.path),然后是PYTHONPATH,然后是python的安装设置相关的默认路径。正因为存在这样的顺序,如果当前路径或PYTHONPATH中存在与标准module同样的module,则会覆盖标准module。也就是说,如果当前目录下存在xml.py,那么执行import xml时,导入的是当前目录下的module,而不是系统标准的xml。
注意:本节参考下列博文
http://blog.csdn.net/offbye/article/details/39029051
知道了python寻找导入模块的规则,我们就好理解上面代码中,第6行为什么加入了
sys.path.append(os.getcwd()+'\\package1\\subpack1\\')
系统就可以找到导入的模块了。
33.3 用了包后
我们通过
sys.path.append(os.getcwd()+'\\package1\\subpack1\\')
可以解决上诉python导入模块的问题,但是如果把所有的模块路径都导入到系统环境变量中,不但代码复制混乱,而且让环境变量很复杂。为了解决这个问题,python引入了包的概念。
我们来看引入包后的代码
__init__.py的作用,在于给python提供一个层级关系链,方便python系统快速索引。
__init__.py文件中的内容可以为空。
33.4 __init__.py可以干点什么吗?
我们在package1的包文件__init__.py中加入下面代码:
在subpack1的包文件__init__.py中加入如下代码:
再次运行包测试程序package_test.py
系统根据from package1.subpack1.module11 import fun_11这条语句的顺序,先找到package1的包文件,并且执行里面的代码,然后找到子包subpack1中的包文件并执行里面的代码。
所以说,__init__.py文件不仅可以管理python中的目录及文件,方便python导入模块的时候快速索引,而且可以本身携带代码执行。
33.5 关于from 包 import *
我们经常在导入一个模块的时候使用下列语句
From module import *
这样我们在接下来的代码中就可以很方便的,直接使用模块中的函数。
那我们是否可以导入一个包中的所有变量和函数呢?
答案是可以的。
我们先来看代码结构
Package_test.py的代码如下:
#----python包研究------ #-*-coding:utf8-*- from package1.subpack1 import * module11.fun_11() module12.fun_12() module13.fun_13()
Package1目录下的__init__.py代码没有改变,具体内容如下:
#----python包研究------ #-*-coding:utf8-*- print("我是package1包...")
subpack1目录下的__init__.py代码如下:
#----python包研究------ #-*-coding:utf8-*- __all__=['module11','module12','module13'] print("我是子包subpack1包...")
Subpack1目录下的三个模块文件没有做改动。
Package_test.py运行结果如下:
我们试着改一下subpack1目录下的包文件,改为如下内容:
#----python包研究------ #-*-coding:utf8-*- __all__=['module11','module12'] print("我是子包subpack1包...")
然后运行package_test.py代码,结果如下
因为我们在subpack1的包文件中,没有包含module3。
__all__=['module11','module12']
所以,import *(注意,*号实际上是找__all__)不会导入module3