第七章 异常和模块、包

35 篇文章 3 订阅
25 篇文章 0 订阅

目录

一、异常

1.1 概念

1.2 定义

1.3 异常的工作原理

1.4 异常的嵌套

1.5 except后的参数

1.5.1 except后面不带任何参数

1.5.2 except后面带多种异常类型

1.6 异常参数

1.7 try-finally/else语句

1.8 raise触发异常

1.9 自定义异常

1.10 异常抛出机制

1.11 标准异常

1.12 with上下文管理

1.12.1 语法及工作原理

1.12.2 自定义with异常

1.13 断言

二、模块

2.1 定义

2.2 导入模块

2.2.1 import

2.2.2 from...import...

2.2.3 reload()

2.2.4 import和from...import的区别

2.3 定位模块

2.4 命名空间和作用域

2.5 globals()和locals()函数

三、包

3.1 包的使用

3.2 包的创建

3.2.1 包的创建1

3.2.2 包的创建2

3.2.3 包的创建3

3.2.4 包的创建4

3.3 包的相对路径

3.4 包的总结

四、课堂练习

1、将两个list,连接成[(1,4),(2,5),(3,6)], l= [1,2,3],l2=[4,5,6]

2、生成二维数组[[0,1,2],[3,4,5],[6,7,8]]

3、L中分别按照学生姓名和学生成绩排序,L=[("Bob",75),("Adam",92),("Bart",66),("Lisa",88)]

4、生成["z1","y2","x3","w4","v5"]


一、异常

1.1 概念

异常是指程序在运行过程中出现了意外,导致程序不能正常执行。

异常处理机制是指当程序出现错误后程序的处理方法,如果程序出错后进行异常处理,程序会继续执行下面的代码。

1.2 定义

try:
	<语句>#可能发生异常的代码
except<名字>: 
	<语句>#如果在try部份引发了'name'异常
except<名字> as <异常参数>:
	<语句>#如果引发了‘name’异常,获得附加的异常对象
else:
	<语句>#如果没有异常发生

注意:

1. 异常最多被同级的except拦截一次
2. 排在前面的except异常优先被触发
3. 捕获异常中可以再嵌套捕获异常,直到不会有新的异常发生为止

print(1)
try:
	int("abc") 
	print(1/0) # 异常最多被同级的except拦截一次
except ZeroDivisionError:
	print("除数不能为0")
except ValueError:
	print("值的异常出现了")
except: # 如果异常没有被之前的拦截,这个是兜底的
	print("某个异常发生了")
print(2)

"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
1
值的异常出现了
2
"""

1.3 异常的工作原理

try的工作原理是:当开始一个try语句后,python就在当前程序的上下文中作标记,当异常出现并捕获后继续执行后续的代码,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。

  • 如果在try包围的语句执行时发生异常,python就跳出try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就跳过整个try语句(除非在处理异常时又引发新的异常)。
  • 如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印缺省的出错信息)。
  • 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。
  • 不管执行try语句是否发生异常,都将会执行finally语句块的语句(如果有的话)。

1.4 异常的嵌套

print(1)
try:
	int("abc")
except ZeroDivisionError:
	print("除数不能为0")
except ValueError:
	print("值的异常出现了")
	try:
		int("abc") 
	except ValueError:
		print("嵌套异常出现了ValueError!")
except: 
	print("某个异常发生了")
print(2)
try:
	try:
		1/0
	except IOError:
		print ("IOError occur")
except Exception as e:
	print (e)

1.5 except后的参数

➢ except可以不带参数,表示捕获所有的异常;如果加了特定的参数,表示捕获特定的异常。
➢ except参数可以有多个,每个参数间用逗号分隔。

1.5.1 except后面不带任何参数

print(1)
try:
	print(1/0)
	print("除数不能为0")
except ValueError:
	print("值的异常出现了!", e)
except: 
	print("某个异常发生了")
print(2)
"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
1
某个异常发生了
2
"""

但这不是一个很好的方式,我们不能通过该程序识别出具体的异常信息,因为它捕获了所有的异常

1.5.2 except后面带多种异常类型

try:
#可能发生异常的代码
	except(Exception1[,Exception2[,...ExceptionN]]]):#如果发生了任何异常列表中发生的异常,将会执行这里的代码
else:
	#如果没有发生异常将会执行这里的代码
print(1)
try:
	int("abc")
except (ValueError,TypeError:
	print("值的异常出现了!")
except: 
	print("某个异常发生了")
print(2)

1.6 异常参数

  ➢ 一个异常可以带上参数,可作为输出的异常信息参数。通过except语句来捕获异常的参数
➢ 异常参数接收的异常值通常包含在异常的语句中。在元组的 表单中变量可以接收一个或者多个值。元组通常包含错误字符串,错误数字,错误位置 
语法格式:
try:
    #可能发生异常的代码
except ExceptionType, Argument:
    #打印异常Argument的值

print(1)
try:
	int("abc")
except ZeroDivisionError:
	print("除数不能为0")
except (ValueError,TypeError) as e:
	print("值的异常出现了!", e)
	try:
		int("abc") 
	except ValueError:
		print("嵌套异常出现了ValueError!")
except: 
	print("某个异常发生了")
print(2)

"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
1
值的异常出现了! invalid literal for int() with base 10: 'abc'
嵌套异常出现了ValueError!
2
"""

1.7 try-finally/else语句

➢ 在try块中抛出一个异常,程序会立即执行finally块代码(如果有的话)。当finally块中的所有代码被执行结束后,异常才会被再次提出,并执行except块代码。
➢ finally和else语句块可以同时存在。如果发生异常只执行finally语句块,否则两语句块都会执行。
注意:
finally要放到else的后面,否则报语法错误
try:
	try:
		1/0
	except IOError:
		print ("IOError occur")
except Exception as e:
	print (e)
else: # 这里的else会执行,是因为第一层try中无异常,而第二层try中抛出的异常,第一层对应的else检测不到
	print("else")
finally:
	print("Done!")

"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
division by zero
Done!
"""

1.8 raise触发异常

Python中使用关键字raise来自己触发异常。
语法格式如下:
raise[SomeExcpetion[, args [, traceback]]]
语句中的SomeExcpetion是一个异常的类型,如NameError,可选;
参数args是一个异常参数值,通常为元组,可选,如果不提供为“None”。
参数traceback也是可选的,实际很少用,如果存在,是跟踪异常对象。
如果有其他参数(args 或traceback),就必须提供SomeExcpetion
def exceptionTest(num):
	if num < 0:
		raise Exception("Invalid num")
	else:
		print (num)
	if num == 0:
		raise ZeroDivisionError("integer division or modulo by zero")

#调用函数,触发异常
exceptionTest(-12)

"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
Traceback (most recent call last):
  File "F:\LiFuChe\光荣之路\课堂编码练习\python_day9\a.py", line 10, in <module>
    exceptionTest(-12)
  File "F:\LiFuChe\光荣之路\课堂编码练习\python_day9\a.py", line 3, in exceptionTest
    raise Exception("Invalid num")
Exception: Invalid num
"""

def exceptionTest(num):
	if num < 0:
		raise Exception("Invalid num")
	else:
		print (num)
	if num == 0:
		raise ZeroDivisionError("integer division or modulo by zero")

#调用函数,触发异常
try:
	exceptionTest(-12)
except:
	print("error")
print("*"*10)
"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
error
**********
"""
def exceptionTest(num):
	if num < 0:
		raise Exception("Invalid num")
	else:
		print (num)
	if num == 0:
		raise
#调用函数,触发异常
exceptionTest(0)

"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
0
Traceback (most recent call last):
  File "F:\LiFuChe\光荣之路\课堂编码练习\python_day9\a.py", line 9, in <module>
    exceptionTest(0)
  File "F:\LiFuChe\光荣之路\课堂编码练习\python_day9\a.py", line 7, in exceptionTest
    raise
RuntimeError: No active exception to reraise
"""

def exceptionTest(num):
	if num < 0:
		raise Exception("Invalid num")
	else:
		print (num)
	if num == 0:
		raise
#调用函数,触发异常
try:
	exceptionTest(0)
except:
	print("error出现了")
"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
0
error出现了
RuntimeError: No active exception to reraise
"""

def exceptionTest(num):
	if num < 0:
		raise Exception("Invalid num")
	else:
		print (num)
	if num == 0:
		raise
#调用函数,触发异常
try:
	exceptionTest(0)
except Exception as e:
	print("error出现了",e)

"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
0
error出现了 No active exception to reraise
"""

1.9 自定义异常

通过创建一个新的异常类,程序可以创建它们自己特定的异常。自定义异常都需要继承异常基类(Exception类),当然也可以继承具体的异常类(比如RuntimeError),通过直接或间接的方式。
# coding=utf-8
class Networkerror(RuntimeError): # 自定义一个异常类
	# 重写默认的__init__()方法,
	# 抛出特定的异常信息
	def __init__(self, value):
		self.value = value

# 触发自定义的异常
try:
	raise Networkerror("Bad hostname") #生成了一个自定义异常类的实例
except Networkerror as e:
	print ("My exception occurred, value:", e.value)


"""运行结果:
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 a.py
My exception occurred, value: Bad hostname
"""

# 自定义异常继承Exception
class ShortInputException(Exception):
  '''A user-defined exception class.'''
  def __init__(self, length, atleast):
    Exception.__init__(self)
    self.length = length
    self.atleast = atleast
try:
  s = input('Enter something --> ')
  if len(s) < 3:
    #如果输入的内容长度小于3,触发异常
    raise ShortInputException(len(s), 3)
except EOFError:
  print ('\nWhy did you do an EOF on me?')
except ShortInputException as x:
  print ('ShortInputException: The input was of length %d,\
  was expecting at least %d' % (x.length, x.atleast))
else:
  print ('No exception was raised.')

1.10 异常抛出机制

异常抛出机制:

  1. 如果在运行时发生异常,解释器会查找相应的处理语句(称为handler);
  2. 要是在当前函数里没有找到,它会将异常传递给上层的调用函数,看那里能不能处理;
  3. 如果在最外层(全局“main”)还是没有找到的话,解释器就会退出,同时打印出traceback以便让用户找到错误产生的原因。

注意:

虽然大多数错误会导致异常,但一个异常不一定代表错误,有时候它们只是一个警告,有时候它们可能是一个终止信号,比如退出循环等。

1.11 标准异常

所有的标准异常类都是内建的,在脚本启动前或者交互命令提示前就可以使用了,查看方法:

dir(__builtins__)

所有的标准/内建异常都是从根异常派生的。目前,有3 个直接 从BaseException 派生的异常子类:SystemExit, KeyboardInterrupt 和Exception其他的所有的内建异常都是Exception 的子类。
Python2.5开始,所有的异常的都是BaseException 的子类
异常名称描述
BaseException所有异常的基类
SystemExit解释器请求退出
KeyboardInterrupt用户中断执行(通常是输入^C)
Exception常规错误的基类
StopIteration迭代器没有更多的值
GeneratorExit生成器(generator)发生异常来通知退出
StandardError所有的内建标准异常的基类
ArithmeticError所有数值计算错误的基类
FloatingPointError浮点计算错误
OverflowError数值运算超出最大限制
ZeroDivisionError除(或取模)零 (所有数据类型)
AssertionError断言语句失败
AttributeError对象没有这个属性
EOFError没有内建输入,到达EOF 标记
EnvironmentError操作系统错误的基类
IOError输入/输出操作失败
OSError操作系统错误
WindowsError系统调用失败
ImportError导入模块/对象失败
LookupError无效数据查询的基类
IndexError序列中没有此索引(index)
KeyError映射中没有这个键
MemoryError内存溢出错误(对于Python 解释器不是致命的)
NameError未声明/初始化对象 (没有属性)
UnboundLocalError访问未初始化的本地变量
ReferenceError弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError一般的运行时错误
NotImplementedError尚未实现的方法
SyntaxErrorPython 语法错误
IndentationError缩进错误
TabErrorTab 和空格混用
SystemError一般的解释器系统错误
TypeError对类型无效的操作
ValueError传入无效的参数
UnicodeErrorUnicode 相关的错误
UnicodeDecodeErrorUnicode 解码时的错误
UnicodeEncodeErrorUnicode 编码时错误
UnicodeTranslateErrorUnicode 转换时错误
Warning警告的基类
DeprecationWarning关于被弃用的特征的警告
FutureWarning关于构造将来语义会有改变的警告
OverflowWarning旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning关于特性将会被废弃的警告
RuntimeWarning可疑的运行时行为(runtime behavior)的警告
SyntaxWarning可疑的语法的警告
UserWarning用户代码生成的警告

1.12 with上下文管理

with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码统统去掉,简化try….except….finlally的处理流程。

with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。所以使用with处理的对象必须有__enter__()和__exit__()这两个方法。其中__enter__()方法在语句体(with语句包裹起来的代码块)执行之前进入运行,__exit__()方法在语句体执行完毕退出后运行。

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放

1.12.1 语法及工作原理

with expression [as target]:
        with_body
参数说明:
expression:是一个需要执行的表达式;
target:是一个变量或者元组,存储的是expression表达式执行返回的结果, 可选参数。
工作原理

with后面的语句被求值后,该语句返回的对象的__enter__()方法被调用,这个方法将返回的值赋给as后面的变量,当with包围的语句块全部执行完毕后,自动调用对象的__exit__()方法。

1.12.2 自定义with异常

with处理异常会更方便,省去try...else...finally复杂的流程,这个用到的就是对象的__exit__()方法:__exit__( exc_type, exc_value, exc_trackback)

后面三个参数是固定的,用来接收with执行过程中异常类型,异常名称和异常的堆栈信息

#encoding=utf-8
class opened(object):
	def __init__(self, filename):
		self.handle = open(filename)
		print ('Resource: %s'% filename)
	
	def __enter__(self):
		print ('[Enter %s]: Allocate resource.' % self.handle)
		return self.handle # 可以返回不同的对象
	# exc_type异常类型,exc_value异常值,exc_trackback异常的堆栈信息
	# 如果with代码块里面出现了异常,上面3个参数都有对应的值保存
	# 如果没有异常,上面3个参数都是None
	def __exit__(self, exc_type, exc_value, exc_trackback):
		print ('[Exit %s]: Free resource.' % self.handle)
		if exc_trackback is None:
			print ('[Exit %s]: Exited without exception.,' % self.handle)
			self.handle.close()
		else:
			print ("error occur!") #句柄泄漏
		#return True
		return False #会抛出异常,中断程序的执行

try:
	with opened(r'F:\LiFuChe\光荣之路\课堂编码练习\python_day9\p2.py') as fp:
		for line in fp.readlines():
			print(line)
		raise TypeError
except:
	print("TypeError occur!")

1.13 断言

 python中用assert进行断言,使用断言是一个非常好的习惯。当程序没有完成时,不知道程序在什么地方出错,就可以使用断言让其出错的时候就崩溃,这样就能方便的定位问题。

assert 的语法:

assert expression[, arguments]

>>> assert 1+1 == 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>> try:
...     assert 1 + 1 == 3
... except AssertionError:
...     print("断言失败")
...
断言失败

二、模块

2.1 定义

模块是Python中最高级别的程序组织单元,它将程序代码和数据封装起来以便重用,而模块就对应Python中的程序文件(.py文件),一旦在一个.py文件中导入了其他模块之后就可以在这个文件中使用导入模块中的变量、函数或类等。模块可以由两个语句和一个内置的函数reload()导入。
import:导入一个整体的模块
from:从一个模块中获取一些特定的内容
➢ reload:在不中止Python程序的情况下,重新导入模块文件内容的方法。
# a.py
x=100
def add(a,b):
	return a+b

class Person():
	pass

# c.py
import a # 模块的名字
print(a.x)
print(a.add(1,2))
print(a.Person())

# a.py和c.py必须在同一个目录下,否则可能找不到

2.2 导入模块

2.2.1 import

import导入的是整个模块的内容。

语法格式:

import module1[, module2[,... moduleN]

说明: 可以在一行中导入多个模块,每个模块之间用逗号隔开

注意

  1. 导入模块时所有的代码都会被执行。如果当做模块导入时有些代码不想被执行时就将其放到if __name__ == "__main__":下。因为当文件本身被执行时__name__ = "__main__",如果是当做模块导入时__name__ =文件名
  2. 一个模块只会被导入一次,不管执行多少次import;
  3. 使用import导入的模块是存放在模块的命名空间中,所以想使用模块中的方法和属性时,必须用以下格式:模块名.方法()/属性

if __name__ == "__main__": 只有文件本身当做程序执行时,才会被执行;被当成模块导入时,if下的代码块不会被执行。if下的代码块通常写一些测试用例来测试此文件的函数、类等内容

2.2.2 from...import...

  from语句可以从模块中导入指定的部分到当前的命名空间中,也就是当前要执行的python文件。

语法一:

from modname import name1[, name2[,... nameN]]

如:from math import sqrt

作用:这样声明只会把math模块中的sqrt函数导入到执行这个声明的模块的全局符号表中,而不是将整个math模块导入。

语法二:

from modname import  *

作用:将模块中的所有内容全部导入到当前的命名空间中,相当于命名空间的合并,这样就可以直接使用模块中的方法或者属性,不用再加上模块名,使用起来更简单一些。

缺点:但是这种方法不推荐,因为如果后引入的模块和之前的模块中有同名的方法或者属性时,会覆盖之前同名的内容,这很可能不是我们想要的。

# a.py
x=100
def add(a,b):
	return a+b

class Person():
	pass

# print("a模块被执行了")
if __name__ == "__main__": # 只有文件本身被当做程序执行时,才会被执行;此if代码块下的代码,通常写一些测试用例来测试文件的函数、类等内容
	print("a模块被执行了")
	assert add(1,2) == 3

# b.py
# import a
from a import * # 把a模块中的所有变量、函数、类,引入到当前命名空间

def add(a,b): #会覆盖a.add()方法
	print("*****")

x=1 #会覆盖a.x的值
print(x)
print(add(1,2))
print(Person())

2.2.3 reload()

reload()需要从imp中引入,表示重新导入已导入过的模块。

语法如下:

from imp import reload

reload(module_name)

比如:reload(math)

说明:使用reload的时候是有一些要求的:

  1. 模块必须是使用import导入的;
  2. 模块必须被成功导入;
  3. reload()参数必须是模块名自身,而不是模块名的字符串
  4. reload()再次导入的模块,会再次被执行,跟import不同。

2.2.4 import和from...import的区别

  • import是将模块中所有的内容导入,而from...import只是导入指定的内容;
  • import导入的属性或方法使用时前面必须加上模块名,而from...import导入的不需要,直接用即可
  • import导入的内容仍然在模块的命名空间中,而from...import导入的内容是在当前文件的命名空间中,这样的话如果有同名的函数或者属性,后导入的内容会将之前的覆盖,引起不必要的麻烦。

说明:导入模块语句一般放在文件的顶端,也可以在需要的时候导入,比如说在函数中,但是出了函数的作用域导入的模块也就不能使用了。

2.3 定位模块

当导入一个模块时,python解析器会去搜索该模块存在的位置,其搜索顺序为:

 如果找不到时,可以通过以下4种方式处理:

1 检查当前目录
2 sys.path.append来添加

import sys
sys.path.append(dir) # dir为被导入模块a的路径
import a

3 环境变量的pythonpath指定路径,必须重启cmd
4 如果都找不到,在python安装路径lib下的site-packages的目录下添加

2.4 命名空间和作用域

命名空间是一个包含了变量名称(键)和它们各自相应的对象( 值)的字典
一个Python表达式可以访问局部命名空间和全局命名空间里的变量。如果一个局部变量和一个全局变量重名,则局部变量会覆盖全局变量。
每个函数都有自己的命名空间。类的方法的作用域规则和通常函数的一样
Python会智能地猜测一个变量是局部的还是全局的,它假设任何在函数内赋值的变量都是局部的。因此,如果要给全局变量在一个函数里赋值,必须使用global关键字,声明该变量为全局变量,否则就会认为是局部变量而重新开辟一段空间。Global VarName的表达式会告诉Python,VarName是一个全局变量,这样Python就不会再局部命名空间里去寻找这个变量了。函数外的list变量在函数内使用无需声明为global。

2.5 globals()和locals()函数

根据调用地方的不同,globals()和locals()函数可被用来返回全局和局部命名空间里的名字
如果在函数内部调用locals(),返回的是所有能在该函数里访问的命名。
如果在函数内部调用globals(),返回的是所有在该函数里能访问的全局名字。
两个函数的返回类型都是字典。所以名字们能用keys()函数摘取。
>>> a=100
>>> b=[1,2,3]
>>> def c():
...     x=1
...     y=1.1
...     print(locals())
...     print(globals())
...
>>> c()
{'x': 1, 'y': 1.1}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 100, 'b': [1, 2, 3], 'c': <function c at 0x00000283299E3E20>}

三、包

包就是相当于文件夹,是一个分层的目录结构,定义了一些由模块及其子包等组成的python应用环境。可以更有逻辑的组织自己的代码。

使用包的方式跟模块也类似,唯一的区别就是文件夹中需要包含__init__.py文件,目的是为了避免将文件夹名当作普通的字符串。

__init__.py的内容可以为空,用来进行包的某些初始化工作或设置__all__值,__all__是在from package-name import *这语句使用时,表示全部导出定义过的模块,如果在__all__中未定义的值时,不能被使用,但是用import package-name导入不受影响。

# package_a.py
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'


# b.py
from package_a import *
print(bar)
print(baz)
# The following will trigger an exception, as "waz" is not exported by the module
print(waz)

"""
F:\LiFuChe\光荣之路\课堂编码练习\python_day9>py -3 package_b.py
10
<function baz at 0x000001EF26996200>
Traceback (most recent call last):
  File "F:\LiFuChe\光荣之路\课堂编码练习\python_day9\package_b.py", line 5, in <module>
    print(waz)
NameError: name 'waz' is not defined. Did you mean: 'baz'?
"""

>>> import os
>>> os.getcwd()
'F:\\LiFuChe\\光荣之路\\课堂编码练习\\python_day10'
>>> os.chdir(r"F:\LiFuChe\光荣之路\课堂编码练习\python_day9")
>>> import letter.letters
>>> letters.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'letters' is not defined. Did you mean: 'letter'?
>>> letter.letters.x
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> from letter import letters
>>> letters.x
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

 

3.1 包的使用

在包文件中的__init__文件中的__all__表示 允许其他程序使用from testmodule import *时可以导入testmodule中的哪些 模块,防止一次导入太多模块导致名称冲突
建立一个testmodule的目录,目录中有3个文件:
a.py、x.py、__init__.py
# a.py
waz = 5
bar = 10
def baz(): return 'baz'

# x.py
name='gloryroad'
def sub(a,b):
    return a-b

# __init__.py
__all__ = ['x']
在testmodule目录的同级目录下,新建一个b.py文件
from testmodule import * 
print (a.bar)
print (a.baz)
print (a.waz)

执行结果:

 将 __init__.py中的__all__ = ['x']改为__all__ = ['a'], 执行b.py,执行结果:

 

3.2 包的创建

目录结构:

gloryroad
│  │  a.py
│  │  __init__.py
│  │
│  ├─submodule
│  │  │  b.py
│  │  │  __init__.py
gloryroad_b.py

gloryroad_b2.py

gloryroad_b3.py

# a.py
def add(a,b):
	return a+b

# b.py
def multiple(a,b):
	return a*b

 

3.2.1 包的创建1

# gloryroad_b.py
#encoding=utf-8
import gloryroad.a
import gloryroad.submodule.b
print(gloryroad.a.add(10,20))
print(gloryroad.submodule.b.multiple(10,20))


# 改短点
from gloryroad.a import add
from gloryroad.submodule.b import multiple
print(add(10,20))
print(multiple(10,20))

 

 

3.2.2 包的创建2

gloryroad目录下的__init__.py文件中,加入如下代码:

import sys
sys.path.append(r"F:\LiFuChe\光荣之路\课堂编码练习\python_day9\gloryroad")
import a

在gloryroad目录的submodule下的__init__.py 文件中,加入如下代码:

import sys
sys.path.append(r"F:\LiFuChe\光荣之路\课堂编码练习\python_day9\gloryroad\submodule")
import b
# gloryroad_b2.py
#encoding=utf-8
import gloryroad
import gloryroad.submodule
print(gloryroad.a.add(10,20))
print(gloryroad.submodule.b.multiple(10,20))

 

3.2.3 包的创建3

目录结构:

test
│      a.py
│      b.py
│      __init__.py

# a.py
def add(a,b):
	return a+b

# b.py
def sub(a,b):
	return a-b

#__init__.py
from .a import *
from .b import *

 执行test.py

# 与test目录同级的test.py文件
import test
print(test.add(1,2))
print(test.sub(2,1))

 

修改__init__.py文件为:

from . import a
from . import b

执行test2.py 

# 与test目录同级的test2.py
from test import *
print(a.add(1,2))
print(b.sub(2,1))

 

3.2.4 包的创建4

跨子包使用

目录结构:

demo
│  │  __init__.py
│  │
│  ├─test1
│  │      a.py
│  │      __init__.py
│  │
│  └─test2
│          b.py
│          __init__.py

# a.py
x=1

# b.py
import sys,os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # 把demo模块的绝对路径添加到pythonpath中
from test1 import a
print(a.x)

 

3.3 包的相对路径

包的引用也是可是使用相对路径的,在flask框架中就有类似写法。

包的结构:

 testt
 │  __init__.py
 │
 ├─test1
 │  │  a.py
 │  │  b.py
 │  │  __init__.py

 │
 ├─test2
 │  │  b.py
 │  │  c.py
 │  │  d.py
 │  │  __init__.py

子包内路径的引用,可以按相对位置引入子模块,有以下三种形式:

1 from . import a                # 同级目录 导入 a

2 from .. import test2            # 上级目录 导入 test2

3 from ..test2 import d          # 上级目录的test2模块下 导入 d

..\\test1\\b.py想引用同级的a模块中的变量以及test2包中模块c中的变量,代码如下:

# testt\test1\b.py
from . import a
print (a.x)

from ..test2 import c
print(c.y)

相对路径的执行:py -3 -m test.test1.b,-m参数的作用是将test.test1.b当作模块来启动。注意:不能直接执行py -3 b.py,会报import错误

 

3.4 包的总结

➢ 第一次导入一个模块,会执行这个模块
➢ 可以通过修改模块module的__all__列表,来改变from module import * 时的效果
➢ 导入一个包,其实就是导入包的__init__.py模块
➢如果包的__init__.py模块为空,使用import package这样的语句是不能使用包当中的任何模块,只能使用import package.module(在使用时必须也带上包名.模块名.xx)或者from package import module(在使用时可不写包名,只写模块名.xx)这样的导入方式
➢ __init__.py也是个模块,也可以在__init__.py中直接定义函数fun,那样import package就可以直接用package.fun这个函数。但是一般不推荐这么做,这样会使__init__.py文件太乱
➢ __init__.py也是个模块,那也可以在这个模块中导入其他模块,这样import package时,就能直接使用一些符号了。
➢ __init__.py也是个模块,也可以定义__all__列表变量,控制from package import * 的作用。

四、课堂练习

1、将两个list,连接成[(1,4),(2,5),(3,6)], l= [1,2,3],l2=[4,5,6]

l= [1,2,3]
l2=[4,5,6]
# 方法1
result=list(zip(l,l2))

# 方法2
result=[]
for i in range(len(l)):
	result.append((l[i],l2[i]))
print(result)

# 方法3
result=[]
for i in l:
	for j in l2:
		result.append((i,j))
print(result)


2、生成二维数组[[0,1,2],[3,4,5],[6,7,8]]

result=[]
times=0
tmp=[]
for i in range(9):
	times += 1
	tmp.append(i)
	if times % 3 == 0: # 用if (i+1) % 3 == 0也可以
		result.append(tmp)
		arr = []

print(result)


3、L中分别按照学生姓名和学生成绩排序,L=[("Bob",75),("Adam",92),("Bart",66),("Lisa",88)]

L=[("Bob",75),("Adam",92),("Bart",66),("Lisa",88)]
def func(l):
	return l[0]

def func2(l):
	return l[1]

print("按学生姓名排序:",sorted(L,key=func))
print("按学生成绩排序:",sorted(L,key=func2))

# 用匿名函数
print("按学生姓名排序:",sorted(L,key=lambda x:x[0]))
print("按学生成绩排序:",sorted(L,key=lambda x:x[1]))

# 方法2
d={}
for i in L:
	d[i[0]]= i[1]

sorted_value = sorted(d.values())
result = []
for i in sorted_value:
	for key,value in d.items():
		if value==i:
			t=(key,value)
			result.append(t)

print(result)


4、生成["z1","y2","x3","w4","v5"]

result=[]
for i in range(5):
	t = chr(ord("z")-i) + str(i+1)
	result.append(t)

print(result)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值