上传文件至 /

This commit is contained in:
zwb 2024-12-26 09:59:55 +08:00
parent e3a10fe2ba
commit 2bacd3eaea
5 changed files with 4954 additions and 0 deletions

451
06-Python流程控制.md Normal file
View File

@ -0,0 +1,451 @@
# 06-Python流程控制
**内置函数range()**
内置函数 [`range()`](https://docs.python.org/zh-cn/3.12/library/stdtypes.html#range) 用于生成等差数列:
```python
>>> for i in range(5):
... print(i)
0
1
2
3
4
```
生成的序列绝不会包括给定的终止值;`range(10)` 生成 10 个值——长度为 10 的序列的所有合法索引。range 可以不从 0 开始,且可以按给定的步长递增(即使是负数步长):
```python
>>> list(range(5, 10))
[5, 6, 7, 8, 9]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(-10, -100, -30))
[-10, -40, -70]
```
如果直接打印一个 range 会发生意想不到的事情:
```
>>> range(10)
range(0, 10)
```
[`range()`](https://docs.python.org/zh-cn/3.12/library/stdtypes.html#range) 返回的对象在很多方面和列表的行为一样,但其实它和列表不一样。该对象只有在被迭代时才一个一个地返回所期望的列表项,并没有真正生成过一个含有全部项的列表,从而节省了空间。
这种对象称为可迭代对象 [iterable](https://docs.python.org/zh-cn/3.12/glossary.html#term-iterable),适合作为需要获取一系列值的函数或程序构件的参数。[`for`](https://docs.python.org/zh-cn/3.12/reference/compound_stmts.html#for) 语句就是这样的程序构件;以可迭代对象作为参数的函数例如 [`sum()`](https://docs.python.org/zh-cn/3.12/library/functions.html#sum)
```python
>>> sum(range(4)) # 0 + 1 + 2 + 3
6
# 注意虽然可迭代对象有很多但sum只适用于list和tuple,不支持str和字典
```
## 一、Python 条件判断
Python条件语句是通过一条或多条语句的执行结果True或者False来决定执行的代码块。
Python程序语言指定任何非0和非空null值为true0 或者 null为false。
**基本形式**
```python
if 判断条件:
执行语句……
else
执行语句……
```
其中"判断条件"成立时(非零),则执行后面的语句,而执行内容可以多行,以缩进来区分表示同一范围。
else 为可选语句,当需要在条件不成立时执行内容则可以执行相关语句
**判断条件**
可以用>、<、==、>=、<=来表示其关系。
**多条件判断**
```python
if 判断条件1:
执行语句1……
elif 判断条件2:
执行语句2……
elif 判断条件3:
执行语句3……
else:
执行语句4……
```
Python 并不支持 switch 语句,所以多个条件判断,只能用 elif 来实现,如果判断需要多个条件需同时判断时,可以使用 or (或),表示两个条件有一个成立时判断条件成功;使用 and (与)时,表示只有两个条件同时成立的情况下,判断条件才成功。
```python
#!/usr/bin/python3.8
num = 9
if num >= 0 and num <= 10:
print('hello')
num = 10
if num < 0 or num > 10:
print('hello')
else:
print('undefine')
num = 8
if (num >= 0 and num <= 5) or (num >= 10 and num <= 15):
print('hello')
else:
print('undefine')
```
**简单语句组**
可以在同一行的位置上使用if条件判断语句
```python
var = 100
if ( var == 100 ) : print("变量 var 的值为100")
```
**match语句**
在Python 3.10中,引入了一种新的结构,即“结构化匹配”,通过`match`语句实现。`match`语句类似于`switch`语句,可以用来匹配一些特定的模式。就像是`if-elif-else`语句的升级版,提供了更多的功能和灵活性。
`match`语句常用于处理这样一些情况:当你有一个变量,你想在这个变量满足不同的条件时做不同的事情。例如,你可能想将一个变量与几个不同的常数比较,或者你可能想检查一个变量是否具有特定的结构,比如它是一个列表并且具有特定的长度。
以下是使用`match`的基本语法:
```python
match expression:
case pattern1:
# 做一些事
case pattern2:
# 做其他事
```
`expression` 是你想匹配的表达式,`pattern1`和`pattern2`等是你定义的模式。各种不同的模式可以用来匹配值的类型,列表的长度,或者字典是否有某个键,等等。
例如
```python
def http_response_status(code):
match code:
case 200:
return "Success"
case 404:
return "Not Found"
# 当没有匹配的值时,使用`_`作为默认模式
case _:
return "Unknown status"
print(http_response_status(200)) # 输出Success
print(http_response_status(500)) # 输出Unknown status
```
在这个例子中,`match`语句将`code`和变量后面的每一种可能进行比较,然后执行第一个匹配的`case`语句的代码块。如果没有匹配的`case`语句,那么就执行默认的`_`模式的代码块。
## 二、Python迭代
迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次"迭代",而每一次迭代得到的结果会被用来作为下一次迭代的初始值。
迭代是程序中对一组指令(或一定步骤)的重复。它既可以被用作通用的术语(与"重复"同义),也可以用来描述一种特定形式的具有可变状态的重复。
比如for循环就是一种编程语言的迭代陈述能够让代码反复的执行。
## 三、Python 循环语句
循环语句允许我们执行一个语句或语句组多次
**循环类型**
Python提供了for和while循环Python中没do..while:
| 循环类型 | 描述 |
| ---------- | ------------------------------------------------------ |
| while 循环 | 在给定的判断条件为 true 时执行循环体,否则退出循环体。 |
| for 循环 | 重复执行语句 |
| 嵌套循环 | 可以在while循环体中嵌套for循环反之亦可 |
**循环控制**
循环控制语句可以更改语句执行的顺序。Python支持以下循环控制语句
| 控制语句 | 描述 |
| ------------- | ------------------------------------------------------------ |
| break 语句 | 在语句块执行过程中终止循环,并且跳出整个循环 |
| continue 语句 | 在语句块执行过程中终止当前循环,跳出该次循环,执行下一次循环。 |
| pass 语句 | pass是空语句是为了保持程序结构的完整性。 |
**while循环**
语法:
```python
while 判断条件:
执行语句……
```
执行语句
可以是单个语句或语句块。
判断条件
可以是任何表达式任何非零、或非空null的值均为true。
当判断条件假false时循环结束。
例:
```python
#!/usr/bin/python3.8
count = 0
while (count < 9):
print('The count is:', count)
count = count + 1
print("Good bye!")
```
continue 用于跳过该次循环break 则是用于退出循环,此外"判断条件"还可以是个常值,表示循环必定成立,具体用法如下:
```python
#!/usr/bin/python3.8
i = 1
while i < 10:
i += 1
if i%2 > 0: # 非双数时跳过输出
continue
print(i) # 输出双数2、4、6、8、10
i = 1
while 1: # 循环条件为1必定成立
print(i) # 输出1~10
i += 1
if i > 10: # 当i大于10时跳出循环
break
```
**无限循环**
如果条件判断语句永远为 true循环将会无限的执行下去如下实例
```python
#!/usr/bin/python3.8
var = 1
while var == 1 : # 该条件永远为true循环将无限执行下去
num = input("Enter a number :")
print("You entered: ", num)
print("Good bye!" )
```
**循环使用 else 语句**
在 python 循环里else 中的语句会在循环正常执行完,即循环不是通过 break 跳出而中断的情况下执行
```python
#!/usr/bin/python3.8
count = 0
while count < 5:
print(count, " is less than 5")
count = count + 1
else:
print(count, " is not less than 5")
```
**简单语句组**
类似if语句的语法如果你的while循环体中只有一条语句你可以将该语句与while写在同一行中 如下所示:
```python
flag = 1
while (flag): print("Given flag is really true!")
```
**for循环**
for循环可以遍历任何序列的项目如一个列表或者一个字符串。
语法:
for iterating_var in sequence:
statements(s)
实例:
```python
#!/usr/bin/python3.8
for letter in 'Python':
print('当前字母 :', letter)
fruits = ['banana', 'apple', 'mango']
for fruit in fruits:
print('当前字母 :', fruit)
```
以上实例输出结果:
当前字母 : P
当前字母 : y
当前字母 : t
当前字母 : h
当前字母 : o
当前字母 : n
当前字母 : banana
当前字母 : apple
当前字母 : mango
**通过序列索引迭代**
另外一种执行循环的遍历方式是通过索引,如下实例:
```python
#!/usr/bin/python3.8
fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
print('当前水果 :', fruits[index])
```
以上实例输出结果:
当前水果 : banana
当前水果 : apple
当前水果 : mango
注:内置函数 len() 和 range()
len() 返回列表的长度,即元素的个数。
range() 返回一个序列的数。
**循环使用 else 语句**
实例:
```python
#!/usr/bin/python3.8
for num in range(10,20): # 迭代 10 到 20 之间的数字
for i in range(2,num): # 根据因子迭代
if num%i == 0: # 确定第一个因子
j=num/i # 计算第二个因子
print ('%d 等于 %d * %d' % (num,i,j))
break # 跳出当前循环
else: # 循环的 else 部分
print (num, '是一个质数')
输出结果:
10 等于 2 * 5
11 是一个质数
12 等于 2 * 6
13 是一个质数
14 等于 2 * 7
15 等于 3 * 5
16 等于 2 * 8
17 是一个质数
18 等于 2 * 9
19 是一个质数
```
**循环嵌套**
Python 语言允许在一个循环体里面嵌入另一个循环。
```python
for 循环嵌套语法:
for iterating_var in sequence:
for iterating_var in sequence:
statements(s)
statements(s)
while 循环嵌套语法:
while expression:
while expression:
statement(s)
statement(s)
```
**continue和break语句**
continue 语句跳出本次循环而break跳出整个循环。
continue 语句用来告诉Python跳过当前循环的剩余语句然后继续进行下一轮循环。
**pass语句**
pass是空语句不做任何事情一般用做占位语句,为了保持程序结构的完整性。
```python
语法:
pass
```
**itertools模块**
包含特殊用途的迭代器函数
**1、 chain() 用于同时迭代不同类型的数据,比如列表和元组,可同时传入多个迭代类型数据参数**
```python
import itertools
for item in itertools.chain([1,2],('a','b'),[3,4]):
print(item)
1
2
a
b
3
4
```
**2、cycle() 用于迭代且循环访问一个可迭代数据,只能传一个迭代类型的数据参数**
```python
import itertools
for item in itertools.cycle([1,2]):
print(item)
1
2
1
2
...
```
******
```
******
******
******
*
**
***
****
*****
*
***
*****
*******
*********
*
***
*****
*******
*********
*****
*******
*********
***
***
***
------------------
*
* *
* *
* *
*********
```

1980
07-Python数据类型.md Normal file

File diff suppressed because it is too large Load Diff

735
08-Python文件处理.md Normal file
View File

@ -0,0 +1,735 @@
# 08-Python文件处理
## 一、打开关闭文件
可以用 file 对象做大部分的文件操作。 file()在python3中已经被废除使用open()打开文件
**open 函数**
先用open()打开一个文件创建一个file
对象,再用相关方法才可以调用它进行读写。
**语法**
```python
file object = open(file_name [, access_mode][, buffering])
```
**参数说明**
file_name
file_name变量是一个包含了你要访问的文件名称的字符串值。
access_mode
决定打开文件的模式:只读'r',写入'w',追加'a'等,所有可取值见后面的完全列表,这个参数是非强制的,默认文件访问模式为只读(r)。
buffering:
如果buffering值被设为0python3已经不能使用0了就不会有寄存数据会立即写入文件。
如果buffering值取1默认值访问文件时会寄存行直到文件关闭才会把数据同步到文件。一般缓冲使用系统默认值即可.
如果将buffering的值设为大于1的整数表明这就是的寄存区的缓冲大小。缓冲内容超过这个大小之后就会同步硬盘
如果取负值,寄存区的缓冲大小则为系统默认。
例1.
\>>> f = open('c.txt','w',0) #没有缓冲
\>>> f.write('hello world') #close之前打开另一终端观察文件发现已经写入进去,说明关闭文件之前就已经写到硬盘
\>>> f.close()
例2.
\>>> f = open('d.txt','w',1) #有缓冲
\>>> f.write('hello world') #close之前打开另一终端观察文件发现没有写入进去,说明关闭文件之前没有写到硬盘
\>>> f.close()
**不同模式打开文件的完全列表**
| 模式 | 描述 |
| ---- | ------------------------------------------------------------ |
| r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。以这种模式打开的文件必须是已经存在的(U模式也是) |
| rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
| r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。注意这个模式默认是带缓冲的 |
| rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
| w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
| wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
| w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
| wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
| a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后即使你 seek 到了其它的地方。如果该文件不存在,创建新文件进行写入。 |
| ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
| a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
| ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
通用换行符支持(UNS)
还有一个特殊的模式U,不同平台用来表示行结束的符号是不同的, 例如 \n, \r, 或者 \r\n.当你使用 'U' 标志打开文件的时候, 所有的行分割符(或行结束符, 无论它原来是什么)通过 Python 的输入方法(例如 read*() )返回时都会被替换为换行符 NEWLINE(\n).注意 UNS 只用于读取文本文件. 没有对应的处理文件输出的方法.
可以使用U,rU或Ua模式打开文件
**关于 'b' 的说明**
对于所有 POSIX 兼容的 Unix 系统(包括Linux)来说, 'b'是可有可无的, 因为它们把所有的文件当作二进制文件, 包括文本文件.
下面是从 Linux 手册的 fopen() 函数使用中摘录的一段, Python 语言中的 open() 函数就是从它衍生出的:
指示文件打开模式的字符串中也可以包含字符 "b" , 但它不能做为第一个字符出现.
这样做的目的是为了严格地满足 ANSI C3.159-1989 (即 ANSI C)中的规定。
事实上它没有任何效果, 所有POSIX 兼容系统, 包括 Linux , 都会忽略 "b" ,其它系统可能会区分文本文件和二进制文件, 如果你要处理一个二进制文件, 并希望你的程序可以移植到其它非 Unix 的环境中, 加上"b" 会是不错的主意
扩展阅读:
```
计算机在物理内存上面存放的都是二进制所以文本文件和二进制文件的主要区别是在逻辑上的而不是物理上的。而从文件的编码方式来看文件可以分为文本文件和二进制文件。文本文件是基于字符编码的文件常见的有ASCII、Unicode等二进制文件是基于值编码的文件可以看成是变长编码你可以根据自己的需要决定多少个比特代表一个值。
从文件编码的方式来看文件可分为ASCII码文件和二进制码文件两种。
(1)ASCII文件也称为文本文件这种文件在磁盘中存放时每个字符对应一个字节用于存放对应的ASCII码。例如数5678的存储形式为
    
    ASC码 00110101 00110110 00110111 00111000
          ↓     ↓    
    十进制码: 5      6     7     8 共占用4个字节。ASCII码文件可在屏幕上按字符显示 例如源程序文件就是ASCII文件用DOS命令TYPE可显示文件的内容。 由于是按字符显示,因此能读懂文件内容。
(2)二进制文件是按二进制的编码方式来存放文件的。 例如, 数5678的存储形式为 00010110 00101110只占二个字节。二进制文件虽然也可在屏幕上显示但其内容无法读懂。C系统在处理这些文件时并不区分类型都看成是字符流按字节进行处理。 输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 因此也把这种文件称作“流式文件”。
存储的方式不同
二进制文件就是把内存中的数据按其在内存中存储的形式原样输出到磁盘中存放,即存放的是数据的原形式。
文本文件是把数据的终端形式的二进制数据输出到磁盘上存放,即存放的是数据的终端形式
在实际存储中最好是将数据分成字符数据和非字符数据两类:
(1)如果存储的是字符数据,无论采用文本文件还是二进制文件都是没有任何区别的,所以讨论使用文本文件还是二进制文件是没有意义的。
(2)如果存储的是非字符数据,又要看我们使用的情况来决定:
a:如果是需要频繁的保存和访问数据,那么应该采取二进制文件进行存放,这样可以节省存储空间和转换时间。
b:如果需要频繁的向终端显示数据或从终端读入数据,那么应该采用文本文件进行存放,这样可以节省转换时间。
文本文件的打开方式和二进制文件打开方式的区别
(1)文本模式中回车被当成一个字符'\n'在文件中如果读到0x1B,文本模式会认为这是文件结束符,会按照一定方式对数据做相应的转换。
(2)二进制模式中'\n'会被认为是两个字符0x0D0x0A;在读到0x1B时二进制模式不会对文件进行处理。
只读/写模式的r/w和rb/wb
(1)r:读取到的是文本数据(字符的编码),使用 open() 打开文件时,默认采用 GBK 编码。但当要打开的文件不是 GBK 编码格式时,可以在使用 open() 函数时手动指定打开文件的编码格式例如file = open("a.txt",encoding="utf-8")
(2)rb: 读取到的是二进制数据(字符在硬盘中存储的二进制),不需要指定编码.
```
**file对象的属性**
一个文件被打开后你就会拥有一个file对象你可以得到有关该文件的各种信息。
file对象属性列表
| 属性 | 描述 |
| ----------- | ----------------------------------------- |
| file.closed | 如果文件已被关闭返回true否则返回false。 |
| file.mode | 返回被打开文件的访问模式。 |
| file.name | 返回文件的名称。 |
例:
```python
#!/usr/bin/python3.8
# 打开一个文件
fo = open("foo.txt", "w")
print("文件名: ", fo.name)
print("是否已关闭 : ", fo.closed)
print("访问模式 : ", fo.mode)
输出结果:
文件名: foo.txt
是否已关闭 : False
访问模式 : w
```
**close()方法**
File 对象的 close方法刷新缓冲区里任何还没写入的信息并关闭该文件这之后便不能再进行写入。
语法:
fileObject.close()
例:
```python
#!/usr/bin/python3.8
fo = open("foo.txt", "w")
print("文件名: ", fo.name)
fo.close() # 关闭打开的文件
输出结果:
文件名: foo.txt
```
**with**
用with可以不用关闭文件
with open('/proc/meminfo') as fd: 和 fd=open('/proc/meminfo') 执行的结果一样,都是遍历文件;
**后者当打开的文件达到几个G的时候很消耗内存**,而前者没有这个问题
```python
#!/usr/bin/env python3.8
with open('a.txt','w') as f:
f.write('hello world')
with open('a.txt','r') as f:
print(f.read())
```
## 二、读文件
使用方法read() readline() readlines()
read():返回字符串
从一个打开的文件中读取一个字符串。
fileObject.read([count])
被传递的参数count是要从已打开文件中读取的字节计数。
该方法从文件的开头开始读入如果没有传入count参数(默认值为 -1)或者值为负, 文件将被读取到末尾.
```python
#!/usr/bin/python3.8
fo = open("foo.txt", "r+")
str = fo.read(10);
print("读取的字符串是 : ", str)
fo.close()
输出结果:
读取的字符串是 : www.fklinu
```
**Windows下字符编码报错**
```python
报错如下:
Traceback (most recent call last):
File "c:/Users/86186/Desktop/python-exc/hello.py", line 3, in <module>
str = fo.read(10);
UnicodeDecodeError: 'gbk' codec can't decode byte 0xff in position 0: illegal multibyte sequence
解决方案:
#!/usr/bin/python3.8
fo = open("foo.txt", "r+",encoding="utf-8",errors="ignore") # 如果在windows下读文件报错就加上编码和错误忽略,这里用的utf-8也不合适最后的结果会有问题每个字符之间都有个空格
str = fo.read(10);
print("读取的字符串是 : ", str)
fo.close()
#!/usr/bin/python3.8
fo = open("foo.txt", "r+",encoding="utf-16",errors="ignore") # 查看记事本用的字符编码是utf-16,这样才能可以读到正确的内容
str = fo.read(10);
print("读取的字符串是 : ", str)
fo.close()
```
![image-20200923114720328](assets/image-20200923114720328.png)
readline():返回字符串
读取下个行结束符之前的所有字节. 作为字符串返回整行,包括行结束符。
和 read() 相同, 它也有一个可选的 size 参数, 默认为 -1, 代表读至行结束符, 如果提供了该参数, 那么在超过 size 个字节后会返回不完整的行.
readlines():返回字符串列表
读取所有剩余的行,返回一个字符串列表。
## 三、写文件
使用方法write() writelines()
write()
可将任何`字符串`(包括二进制数据)写入一个打开的文件Linux下不会在字符串的结尾添加换行符('\n')windows是有换行符的不支持数字
writelines()
是针对列表的操作, 它接受一个`字符串`序列(**字符串,字符串列表,字符串元组**)作为参数, 将它们写入文件. 行结束符并不会被自动加入, 所以如果需要的话, 你必须在调用writelines()前给每行结尾加上行结束符.
语法:
fileObject.write(string)
string参数是要写入到已打开文件的内容。
```python
#!/usr/bin/python3.8
fo = open("foo.txt", "w")
fo.write("www.fklinux.com!\nVery good site!\n");
fo.close() # 关闭打开的文件
被创建的foo.txt文件内容:
# cat foo.txt
www.fklinux.com!
Very good site!
```
## 四、文件指针
**tell()**
这个方法告诉我们文件内的当前位置,换句话说,下一次的读写会发生在文件开头这么多字节之后。
**seek()**
可以在文件中移动文件指针到不同的位置.
语法:
```python
seek(offset [,from])
```
offset
表示要移动的字节数
from
指定开始移动字节的参考位置。
如果from被设为0这意味着将文件的开头作为移动字节的参考位置0 -- start of stream (the default); offset should be zero or positive
如果设为1则使用当前的位置作为参考位置python2可以python3必须带b读文件--rb
如果设为2那么该文件的末尾将作为参考位置 (**其实唯一的作用是将指针移动到最后seek(0,2)**)
seek配置r+模式可以实现从指定位置修改文件
例: 就用上面创建的文件foo.txt
```python
#!/usr/bin/python3.8
# python2没有任何问题python3 在seek的时候如果相对位置是1需要打开文件的是时候带'b'
fo = open("foo.txt", "r+")
str = fo.read(10);
print ("读取的字符串是 : ", str)
# 查找当前位置
position = fo.tell();
print ("当前文件位置 : ", position)
# 把指针再次重新定位到文件开头
position = fo.seek(0, 0);
str = fo.read(10);
print ("重新读取字符串 : ", str)
# 关闭打开的文件
fo.close()
输出结果:
读取的字符串是 : www.fklinu
当前文件位置 : 10
重新读取字符串 : www.fklinu
In [77]: with open('a.txt','rb') as f:
...: print(f.read(2))
...: f.seek(2,1)
...: print(f.read(2))
...:
b'he'
b'o '
```
## 五、文件迭代
一行一行访问文件很简单:
```python
for eachLine in f:
:
```
eachLine 代表文本文件的一行,包括末尾的行结束符
Python 2.2 中, 引进了迭代器和文件迭代, 文件对象成为了它们自己的迭代器用户不必调用 read() 方法就可以在 for 循环中迭代文件的每一行.
```python
迭代器之前的老方法
for eachLine in f.readline():
:
```
```python
In [35]: for i in f:
...: print(i,end="") # end的作用是取消print默认的换行
...:
1111
2222
3333
4444
```
**print函数取消默认换行符**
print 语句默认在输出内容末尾后加一个换行符, 而在语句后加一个逗号就可以避免这个行为. readline() 和 readlines() 函数不对行里的空白字符做任何处理,所以你有必要加上逗号. 如果你省略逗号, 那么显示出的文本每行后会有两个换行符, 其中一个是输入是附带的, 另个是 print 语句自动添加的.
打印输出的时候取消默认换行python2只需要在后面加一个逗号','
```python
#!/usr/bin/env python
print "hello", # 在这里加逗号可以取消换行
print "hi"
#!/usr/bin/env python3.8
print("hello",end="") # 这是python3里的方法
print "hi"
```
另外也可使用迭代器的 next 方法, file.next() 可以用来读取文件的下一行.
注意python3已经不支持file.next()方法python3使用系统内置函数next()
和其它迭代器一样Python 也会在所有行迭代完成后引发 StopIteration 异常.
```python
In [269]: f=open("a.txt","r+")
In [270]: next(f)
Out[270]: 'hello world\n'
In [271]: next(f)
Out[271]: 'nice to meet you\n'
In [272]: next(f)
Out[272]: 'I love you\n'
```
## 六、文件重命名和删除
创建普通文件
```python
>> os.mknod("/a.txt")
```
Python的os模块提供了帮你执行文件处理操作的方法比如重命名和删除文件。
**rename()方法**
语法:
os.rename(current_file_name, new_file_name)
例子: 下例将重命名一个已经存在的文件test1.txt。
```python
#!/usr/bin/env python3.8
import os
os.rename("foo.txt","foo1.txt") # 重命名文件foo.txt到foo1.txt
```
**remove()方法**
删除文件
语法:
os.remove(file_name)
例子: 下例将删除一个已经存在的文件test2.txt。
```python
#!/usr/bin/python3.8
import os
os.remove("test2.txt") # 删除一个已经存在的文件test2.txt
```
## 七、Python目录操作
os模块有许多方法能帮你创建删除和更改目录。
**mkdir()方法**
语法:
os.mkdir("newdir")
例子:
```python
#!/usr/bin/python3.8
import os
os.mkdir("test") # 创建目录test
```
**chdir()方法**
改变当前工作目录
语法:
os.chdir("newdir")
例子: 下例将进入"/home/newdir"目录。
```python
#!/usr/bin/python3.8
import os
os.chdir("/home/newdir") # 将当前目录改为"/home/newdir"
```
**getcwd()方法**
显示当前工作目录
语法:
os.getcwd()
例子:
```python
#!/usr/bin/python
import os
os.getcwd() # 给出当前的目录
```
**rmdir()方法**
删除目录,只能删除空目录
语法:
os.rmdir('dirname')
例子:
```python
#!/usr/bin/python3.8
import os
os.rmdir( "/tmp/test" ) # 删除”"tmp/test"目录
```
## 八、Python File方法列表
file 对象使用 open 函数来创建,下表列出了 file 对象常用的方法
| 方法 | 描述 |
| -------------------------- | ------------------------------------------------------------ |
| file.close() | 关闭文件。关闭后文件不能再进行读写操作。 |
| file.flush() | 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。 |
| file.fileno() | 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。 |
| file.isatty() | 如果文件连接到一个终端设备返回 True否则返回 False。 |
| | |
| file.read([size]) | 从文件读取指定的字节数,如果未给定或为负则读取所有。 |
| file.readline([size]) | 读取整行,包括 "\n" 字符。 |
| file.readlines([sizehint]) | 读取所有行并返回列表若给定sizeint>0返回总和大约为sizeint字节的行, 实际读取值可能比sizhint较大, 因为需要填充缓冲区。 |
| file.seek(offset[,whence]) | 设置文件当前位置 |
| file.tell() | 返回文件当前位置。 |
| file.truncate([size]) | 截取文件截取的字节通过size指定默认为当前文件位置。 |
| file.write(str) | 将字符串写入文件,没有返回值。 |
| file.writelines(sequence) | 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。 |
truncate() 方法
将文件截取到当前文件指针位置或者到给定 size , 以字节为单位.
它接受一个可选的 size 作为参数. 如果给定, 那么文件将被截取到最多 size 字节处. 如果没有传递 size 参数, 那么默认将截取到文件的当前位置.例如, 你刚打开了一个文件, 然后立即调用 truncate() 方法, 那么你的文件(内容)实际上被删除,这时候你是其实是从 0 字节开始截取的
```python
In [19]: cat foo.txt
aaaaa
bbbbb
In [20]: f = open('foo.txt','r+') #注意权限必须带+号
In [21]: f.truncate(2)
Out[21]: 2
In [22]: cat foo.txt
aa
```
## 八、Python序列化数据存储
序列化 (Serialization)是指将对象、数据结构的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
我们编写的程序,会涉及到各种各样的对象、数据结构,它们通常是以变量的形式在内存中存在着。当程序运行结束后,这些变量也就会被清理。但我们有时希望能够在下一次编写程序时恢复上一次的某个对象(如机器学习中的到结果,需要程序运行较长时间,多次运行时间成本太大),这就需要我们将变量进行持久化的存储。
一种方式是利用文件读写的方式将变量转化为某种形式的字符串写入文件内,但需要自己控制存储格式显得十分笨拙。更好的方式是通过序列化的方式将变量持久化至本地。
json是一种所有的语言都可以识别的数据结构。
如果我们将一个字典或者序列化成了一个json存在文件里那么java代码或者js代码也可以拿来用。
但是如果我们用pickle进行序列化其他语言就不能读懂这是什么了
所以如果你序列化的内容是列表或者字典非常推荐你使用json模块
但如果出于某种原因你不得不序列化其他的数据类型而未来你还会用python对这个数据进行反序列化的话那么就可以使用pickle
**json序列化**
json模块提供了四个功能
dumps 序列化对象至字符串,存储到内存
loads 对应的反序列化方法
dump 序列化对象至本地文件
load 对应的反序列化方法
**pickle序列化**
pickle模块提供了四个功能
dumps 序列化对象至字符串,存储到内存
loads 对应的反序列化方法
dump 序列化对象至本地文件
load 对应的反序列化方法
**pickle可以存储什么类型的数据**
1. 所有python支持的原生类型布尔值整数浮点数复数字符串字节None。
2. 由任何原生类型组成的列表,元组,字典和集合。
3. 函数,类,类的实例
例子:
**pickle模块**
```python
>>> import pickle
>>> data = ['aa', 'bb', 'cc']
```
**dumps 存储数据将数据通过特殊的形式转换为只有python语言认识的字符串**
```python
>>> p_str = pickle.dumps(data)
>>> print(p_str) b'\x80\x03]q\x00(X\x02\x00\x00\x00aaq\x01X\x02\x00\x00\x00bbq\x02X\x02\x00\x00\x00ccq\x03e.
```
**loads 读取数据将pickle数据转换为python的数据结构**
```python
>>> mes = pickle.loads(p_str)
>>> print(mes)
['aa', 'bb', 'cc']
```
**dump 存储数据将数据通过特殊的形式转换为只有python语言认识的字符串并写入文件**
```python
with open('/tmp/aa.txt', 'wb') as f:
pickle.dump(data, f)
```
注意以上代码中的w必须带b
**load 读取数据从数据文件中读取数据并转换为python的数据结构**
```python
with open('/tmp/aa.txt', 'rb') as f:
data = pickle.load(f)
```
注意以上代码中的r必须带b
**写入多个对象**
```python
In [25]: import pickle
In [26]: li = [1,2,3]
In [27]: di = {'a':'b'}
In [28]: with open('pickles.db','wb') as f:
...: pickle.dump(li,f)
...: pickle.dump(di,f)
...:
```
**读取多个对象**
```python
In [29]: with open('pickles.db','rb') as f:
...: l2 = pickle.load(f)
...: d2 = pickle.load(f)
...:
In [30]: l2
Out[30]: [1, 2, 3]
In [31]: d2
Out[31]: {'a': 'b'}
```
**在有序列化数据的基础上追加数据**
```python
In [2]: import pickle
In [1]: d={"name":"fulei","age":28,"shengao":18} # 第一次存储数据
In [3]: with open("a.txt","wb") as f:
...: pickle.dump(d,f)
In [6]: e={"name":"fulei","age":28,"shengao":18}
In [7]: with open("a.txt","ab") as f: # 第一次追加
...: pickle.dump(e,f)
In [9]: l={"xingming":"fulei","nianling":27,"gaodu":180}
In [10]: with open("a.txt","ab") as f: # 第二次追加
...: pickle.dump(l,f)
In [13]: with open("a.txt","rb") as f: # 取数据时要按顺序取3次
...: e=pickle.load(f)
...: t=pickle.load(f)
...: v=pickle.load(f)
In [14]: e
Out[14]: {'name': 'fulei', 'age': 28, 'shengao': 18}
In [15]: t
Out[15]: {'name': 'fulei', 'age': 28, 'shengao': 18}
In [16]: v
Out[16]: {'xingming': 'fulei', 'nianling': 27, 'gaodu': 180}
```
**json模块**
```python
In [1]: import json
In [2]: s = json.dumps({"a": "b"})
In [3]: s
Out[3]: '{"a": "b"}'
In [4]: json.loads(s)
Out[4]: {'a': 'b'}
```
```python
In [5]: import json
In [6]: li = [1,2,3]
In [7]: di = {'a':'b'}
In [8]: with open('json.db','w') as f:
...: json.dump(li,f) #序列化存储列表'li'到文件中
...:
In [9]: !cat json.db #json序列化的文件是直接可读的
[1, 2, 3]
In [15]: with open('json.db','r') as f:
...: l2 = json.load(f) #反序列化
...:
In [16]: l2
Out[16]: [1, 2, 3]
```
**序列化多个对象到文件中**
```python
In [20]: with open('json.db','w') as f:
...: f.write(json.dumps(li)+'\n') # 需要换行符保证每个对象占一行
...: f.write(json.dumps(di)+'\n')
```
**从一个文件读取多个序列化对象时需用 loads 配合readline一次读一行**
```python
In [21]: with open('json.db','r') as f:
...: l2 = json.loads(f.readline())
...: d2 = json.loads(f.readline())
...:
In [22]: l2
Out[22]: [1, 2, 3]
In [23]: d2
Out[23]: {'a': 'b'}
```
## 扩展练习
**----编写程序,实现程序功能为修改指定文件内指定内容**
```python
[root@python python]# cat alterfile.py
#!/usr/bin/env python3
# 程序执行方式python alterfile.py test.txt 旧关键字 新关键字
import sys
file_name = sys.argv[1]
old_str = sys.argv[2]
new_str = sys.argv[3]
def alter(file,old_str,new_str):
file_data = ""
with open(file,"r") as f:
for line in f:
if old_str in line:
line = line.replace(old_str,new_str)
file_data += line
with open(file,"w") as f:
f.write(file_data)
alter(file_name,old_str,new_str)
[root@python python]# cat test.txt
hello world
nice to meet you
nihao every body
[root@python python]# python alterfile.py test.txt world 世界
[root@python python]# cat test.txt
hello 世界
nice to meet you
nihao every body
```

1051
09-Python函数详解.md Normal file

File diff suppressed because it is too large Load Diff

737
10-Python模块详解.md Normal file
View File

@ -0,0 +1,737 @@
# 10-Python模块详解
## 一、何为模块
模块让你能够有逻辑地组织Python代码段。把相关的代码分配到一个模块里能让你的代码更好用更易懂。模块也是Python对象。简单地说模块就是一个保存了 Python代码的文件能定义函数类和变量。
模块文件,需要以 `.py` 结尾;比如 time.py模块名为time可以通 过`import time`使用。
library-->modules-->functions(methods)-->python指令
**模块的分类**
从来源来分,可以分成
1. 内置
2. 第三方
3. 自定义
```python
__import__()
查询模块是内建模块还是属于某一个模块文件
In [5]: __import__("sys")
Out[5]: <module 'sys' (built-in)>
In [3]: __import__("os")
Out[3]: <module 'os' from '/usr/lib64/python2.7/os.pyc'>
In [4]: __import__("os").__file__
Out[4]: '/usr/lib64/python2.7/os.pyc'
```
**查看模块存放位置**
通过查看模块存放路径就知道我们自己制作的模块应该放在哪个位置
查看python默认的模块存放路径。
```python
>>> import sys
>>> sys.path
['', '/usr/local/python27/lib/python27.zip', '/usr/local/python27/lib/python2.7', '/usr/local/python27/lib/python2.7/plat-linux2', '/usr/local/python27/lib/python2.7/lib-tk', '/usr/local/python27/lib/python2.7/lib-old', '/usr/local/python27/lib/python2.7/lib-dynload', '/usr/local/python27/lib/python2.7/site-packages']
列表内的第一个元素''表示当前工作目录,也就是说模块在当前目录下也可使用
默认存放模块的目录是:/usr/local/python27/lib/python2.7/
```
**查看模块内定义的标识符**
```
__dir__()函数返回一个排好序的字符串列表,内容是一个模块里定义过的名字。容纳了在一个模块里定义的所有模块,变量和函数。
```
```python
>>> import keyword
>>> keyword.__dir__()
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', '__all__', 'kwlist', 'softkwlist', 'iskeyword', 'issoftkeyword']
```
在这里,特殊字符串变量`__name__`指向模块的名字,`__file__`指向该模块的导入文件名。
**模块的意义**
1、从文件级别组织程序功能重复利用更方便管理
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做,程序的结构会更清晰,可方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。
2、偷懒提升开发效率
同样的原理,我们也可以下载别人写好的模块然后导入到自己的项目中使用,这种偷懒,在 python 中是大力支持的,可以极大地提升我们的开发效率
**模块相关站点**
https://pypi.python.org/pypi/
PyPI(Python Package Index,PyPI) python包索引
为Internet上的第三方Python模块提供一个集中的存储库
## 二、制作模块
**模块结构**
用模块来合理组织Python 代码应该建立一种统一且容易阅读的结构,并将它应用到每一个文件中去。
一个典型模块的内部结构:
(1) 起始行
(2) 模块文档
(3) 模块导入
(4) 变量定义
(5) 类定义
(6) 函数定义
(7) 主程序
**一个叫做mod的模块制作和调用的例子**
一个叫做aname的模块里的Python代码一般都能在一个叫aname.py的文件中找到。
```python
[root@wing python]# cat mod.py
#!/usr/bin/env python3.8
'''
这是一个模块实例
'''
import sys,os
name="wing"
def hello():
print("hello world")
if __name__ =="__main__":
hello()
使用模块:
In [1]: import mod
In [2]: mod.hello()
hello world
In [3]: print(mod.__doc__)
这是一个模块实例
In [4]: print(mod.name)
wing
```
**模块中的特殊变量**
1、`__file__`
存储当前 py 文件的文件名或此模块的绝对路径
```python
In [1]: import mod # 导入模块,如果是脚本需要把命令放在脚本的顶端
In [2]: mod.__file__
Out[2]: '/root/Development/python_code/day01/mod.py'
```
2、`__name__`
Python内置了全局变量`__name__`,使用 `__name__` 控制 .py 文件的用途,用来控制.py文件在不同的应用场景下执行不同的逻辑
编写好的一个python文件可以有两种用途
1脚本一个文件就是整个程序用来被执行当文件被当做脚本执行时`__name__` 等于'`__main__`'
2模块文件中存放着一堆功能(函数或类),这些功能可以用来被导入使用,当文件被当做模块导入时:`__name__`等于模块名
下例中可以使用两种方法调用main函数但是每次在python解释器里第一次import模块时都会执行main函数如果又想可以把模块当脚本一样在命令行整体执行又想在其他脚本调用模块内单独的某一个函数可以使用第二种方式
```python
# vim pysysinfo_func.py
#!/usr/bin/env python3.8
import subprocess
def uname_func():
uname = "uname"
uname_arg = "-a"
print("Gathering system information with %s command:\n" % uname)
subprocess.call([uname,uname_arg])
def disk_func():
diskspace = "df"
diskspace_arg = "-Th"
print("Gathering diskspace information with %s command:\n" % diskspace)
subprocess.call([diskspace,diskspace_arg])
def main():
uname_func()
disk_func()
#第一种方式:
main()
#第二种方式:
if __name__ == "__main__":
main()
# 第一种方式的结果如下会在导入模块的时候执行main函数
In [1]: import pysysinfo_func
Gathering system information with uname command:
Linux vm2.up.com 2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
Gathering diskspace information with df command:
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root
ext4 18G 4.1G 13G 25% /
tmpfs tmpfs 565M 224K 565M 1% /dev/shm
/dev/sda1 ext4 485M 34M 427M 8% /boot
/dev/sr0 iso9660 3.5G 3.5G 0 100% /mnt
# 第二种方式的结果如下:
In [1]: import pysysinfo_func # 不会在导入模块的时候执行main函数
```
**理解`__name__`**
```python
Py1.py
#!/usr/bin/env python3.8
def test():
print('__name__ = ',__name__)
if __name__ == '__main__':
test()
Py2.py
#!/usr/bin/env python
import Py1.py
def test():
print('__name__ = ',__name__)
if __name__ == '__main__':
test()
print('Py1.py __name__ = ',Py1.__name__)
执行结果:
__name__=__main__
Py1.py __name__=Py1
```
通过结果可以知道Py2.py直接执行那么内建变量`__name__`的值为`__main__`,否则为模块的名字,通过这个特性可以
在if语句里面添加测试代码
```python
if __name__ == '__main__':
test()
```
## 三、导入模块
以echo.py为例来介绍模块的使用文件名 echo.py,模块名 echo
```python
# vim echo.py
#!/usr/bin/env python3.8
print('from the echo.py')
s = 'wing'
x = 100
def get_info1():
print('来自 echo 模块的 {}'.format(s))
def get_info2():
print('来自 echo 模块的 get_info2 函数')
get_info1()
```
**import 语句**
想使用Python模块可以在另一个源文件里执行import语句
一个模块只会被导入一次不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。
导入模块其实就是告诉Python解释器去解释那个py文件模块可以包含可执行的语句这些语句的目的是初始化模块它们只在模块第一次被导入import 语句时才执行
**第一次导入模块时会做三件事**
1、为源文件(echo模块)创建新的命名空间,对于 echo.py 文件中的函数来说,它们的全局变量就在这个命名空间了。
2、在新创建的命名空间中再去执行模块中包含的代码。
3、把 echo 这个名字分配给该命名空间,这个名字本质上就是变量名
**语法**
import module1[, module2[,... moduleN]
当解释器遇到import语句如果模块在当前的`搜索路径`就会被导入。
**搜索路径**
是一个解释器会进行搜索的所有目录的列表
当你导入一个模块Python解析器对模块位置的搜索顺序是内存中已经加载的模块—>sys.path包含的路径中
1、在第一次导入某个模块时比如echo会先检查该模块是否已经被加载到内存中如果有则直接引用Python解释器在启动时会自动加载一些模块到内存中可以用sys.modules查看
2、如果还没有找到就从 sys.path 给出的目录列表中依次寻找`模块名.py` 文件。搜索时按照sys.path中从左到右的顺序查找位于前面的优先被搜索。
python程序可以修改sys.path,路径放到前面的优先被使用。
```python
import sys
sys.path.append('/a/b/c')
sys.path.insert(0,'/x/y/z')
```
**使用模块中的变量或者函数等对象**
用模块名加上点,后面跟上要使用的变量名或者函数名即可
```python
import echo
print(echo.x)
func = echo.get_info1
func()
```
**每个模块都是一个独立的命名空间**
定义在这个模块中的函数,会把这个模块的命名空间当做全局命名空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中的全局变量会在被导入时,与使用者的全局变量冲突了。
```python
# test.py 文件的内容
import echo
x=10
print(echo.x)
执行 test.py 文件后的结果如下:
from the echo.py
100
```
**模块别名**
为已经导入的模块起别名的方式对编写可扩展的代码很有用
```python
import echo as sm
print(sm.x)
```
使用场景:
假如有两种sql模块mysql和oracle根据用户的输入可以选择不同的sql功能
```python
# vim mysql.py
#!/usr/bin/env python3.8
def select():
print('from mysql')
# vim oracle.py
#!/usr/bin/env python3.8
def select():
print('from oracle')
# vim test.py
#!/usr/bin/env python3.8
db_type=input('>>: ')
if db_type == 'mysql':
import mysql as db
elif db_type == 'oracle':
import oracle as db
else:
sys.exit('请输入 mysql 或 oracle')
db.select()
```
**From…import 语句**
Python的from语句让你从模块中导入一个指定的部分到当前命名空间中。
在当前命名空间中直接使用名字就可以了、无需加前缀echo.
好处:使用起来方便了
坏处:容易与当前执行文件中的名字冲突
语法如下:
```python
from modname import name1[, name2[, ... nameN]]
```
```python
from echo import get_info1 as read # 同样支持 as
from echo import get_info1,get_info2,x # 在一行导入多个名字
```
例如要导入模块fib的fibonacci函数使用如下语句
```python
from fib import fibonacci
```
这个声明不会把整个fib模块导入到当前的命名空间中它只会将fib里的fibonacci单个引入到执行这个声明的模块的全局符号表。
**From…import * 语句**
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
```python
from modname import *
```
这提供了一个简单的方法来导入一个模块中的所有项目,但是不包括以单个下划线 _ 开头的名字。然而这种声明不该被过多地使用。 因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字,而且可读性极其的差。
也可以使用模块的内置属性 `__all__` 来控制 *只需要在echo.py中新增一行
```python
__all__ = ['x','get_info1']
# 这样在另外一个文件中用from echo import * 就能导入列表中规定的两个名字
```
**Python解释器开启时自动调用模块**
正常情况下使用python解释器使用模块的方法时需要导入模块一些自己比较常用的模块比如os,process每次开始python解释器都得重新调用,下面的方法可以为你解除痛苦
只需设置一个变量,变量的值为某个.py文件的路径在.py文件内设置预先想要导入的模块
```python
# export PYTHONSTARTUP=/a.py
# cat /a.py
import os
import subprocess
# python3.8
>>> os.system("ls") # 可以看到测试的OS模块的时候可以直接使用无需事先导入模块OS
anaconda-ks.cfg Documents install.log.syslog Public a.py Downloads Music
```
**重载模块**
当一个模块被导入到一个脚本模块顶层部分的代码只会被执行一次。因此如果你想重新执行模块里顶层部分的代码可以用reload()函数。该函数会重新导入之前导入过的模块。
语法
```python
from imp import reload
reload(module_name) # 这里module_name要直接放模块的名字而不是一个字符串形式。
```
比如想重载hello模块如下
```python
from imp import reload
reload(hello)
```
1.同一个模块导入,第一次代码全部运行,第二次很多的代码都不运行的,其实中间只是重复执行
2.尝试在第一次导入后,修改源文件,然后第二次导入,结果跟第一次一样。
原因
导入操作的开销非常大它把文件先编译成字节码然后再导pvm(python virtual machine)上去执行,在编译的过程中,消耗资源非常多,所以,导入操作只编译执行一次,第二次只是重复执行,不再编译
如果想再次执行完整的代码,就需要 `reload()` 这个函数他会把源代码重新载入然后执行一遍但是在执行reload前必须保证已经import那个模块
例:
```python
1.编写模块a.py
#!/usr/bin/env python3.8
print ("hello world")
2.进入Ipython导入模块
In [1]: import a
hello world # 第一次导入结果有输出
In [2]: import a
# 第二次导入结果就没有输出了
In [3]: import a
# 修改源文件后再次导入仍然没有输出结果,必须的用reload()重载模块才行
```
## 四、发布自己的模块
以一个处理嵌套列表的代码为例,把他做成可以发给别人使用的模块
1.创建父目录
```python
# mkdir /nester
```
2.准备源代码文件
```python
#vim /nester/nester.py
#!/usr/bin/env python3.8
"这是模块文档字符串"
def print_list(name):
"这是函数文档字符串"
for each_item in name:
if isinstance(each_item,list):
print_list(each_item)
else:
print(each_item)
```
3.准备setup.py文件
```python
# vim /nester/setup.py
#!/usr/bin/env python3.8
from distutils.core import setup
setup(
name = 'nester',
version = '1.0.0',
py_modules = ['nester'],
author = 'wing',
author_email = '276267003@qq.com',
url = 'www.fklinux.com',
description = 'A simple printer of nested lists',
)
```
4.构建发布文件
```python
# cd /nester
# python setup.py sdist
```
5.构建成功之后/nester目录下会出现dist目录,dist目录下会出现构建好的模块打包文件这个文件就可以发给别人使用了
```python
[root@host nester]# ls dist/
nester-1.0.0.tar.gz
```
6.测试安装模块
```python
# tar xvzf nester-1.0.0.tar.gz
# cd nester-1.0.0
# python setup.py install
# python3.8
>>> import nester # 其实到这里,如果你能导入模块成功的话,恭喜你,^_^说明你的模块儿没问题了,下面是这个模块的具体使用
>>> a=[1,2,3,[4,5,[6,7]]]
>>> nester.print_list(a)
1
2
3
4
5
6
7
```
## 五、包
在创建许许多多模块后,我们可能希望将某些功能相近的文件组织在同一文件夹下,这里就需要运用包的概念了。包对应于文件夹,使用包的方式跟模块也类似,唯一需要注意的是,当文件夹当作包使用时,文件夹需要包含`__init__.py`文件,主要是为了避免将文件夹名当作普通的字符串。`__init__.py`的内容可以为空,一般用来进行包的某些初始化工作,创建包的目的不是为了运行,而是被导入使用,其实,包只是模块的一种形式而已,包的本质就是一种模块
**软件开发规范**
```python
.
├── bin # 存放命令执行文件
├── conf # 存放配置文件
├── src # 存放主程序代码
├── data # 存放程序的数据
└── lib # 存放程序的库文件,比如公共的函数库
```
**包的使用**
示范文件
[![file://C:\Users\86186\AppData\Local\Temp\.2IK5Q0\1.png](assets/1.png)]()
文件初始内容
run.py
```python
from core import main
main.main_func()
```
settings.py
```python
HOST = '1.1.1.1'
```
main.py
```python
from conf import settings
host = settings.HOST
def main_func():
print('from main')
print(host)
```
1、包的使用之from ... import ...
比如在 run.py 中导入 core 下的 main
```python
from core import main
```
但是这样还是不能正常导入
这是因为,环境变量的 sys.path 的目录是以执行文件为基准的。
也就是,当我们现在执行 run.py 文件时,会把 run.py 文件所在的当前目录添加到 sys.path 中,也就是 bin 目录,而我们要导入的 main 是从 core 导入,但是 bin 目录下并没有 core 。
解决办法是,将他们共同的上一级目录添加到 sys.path 中。
在 run.py 文件中添加以下内容即可
```python
import os, sys
BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(BASEDIR)
sys.path.insert(0, BASEDIR)
from core import main
main.main_func()
```
```python
# 运行run.py文件
[root@workstation bin]# python run.py
/root/qf
from main
1.1.1.1
```
2、包的使用之import
单独导入包时不会导入包中所有包含的所有子模块,如
在与qf同级的test.py中写下如下内容后执行
```python
import qf # 导入包名qf
qf.bin # 执行qf下的bin包
执行结果会报错:
AttributeError: module 'qf' has no attribute 'bin'
```
解决方法:在包 qf 下面的 `__init__.py` 文件下添加如下内容
```python
from . import bin
```
```python
# 如果想执行bin包下的run文件也需要在bin目录下添加__init__.py文件
[root@workstation ~]# vim qf/bin/__init__.py
from . import run
# 执行test.py文件
[root@workstation ~]# python3.8 test.py
/root/qf
from main
1.1.1.1
```
## 六、技巧-python和shell互传变量
**python -> shell**
**1.环境变量**
```python
import os
var=123或var='123'
os.environ['var']=str(var) # environ的键值必须是字符串
os.system('echo $var')
```
**2.字符串连接**
代码如下:
```python
import os
path='/root/a.txt'
var=[1]
var='bash'
os.system('echo ' + path) # 注意echo后有空格
os.system('echo ' + str(var[0]))
os.system('echo ' + var + ' /root/c.sh') # 注意echo后和/root前有空格
```
**3.通过管道**
```python
import os
var='123'
os.popen('wc -c', 'w').write(var)
```
**4.通过文件**
```python
output = open('/tmp/mytxt', 'w')
output.write(S) #把字符串S写入文件
output.writelines(L) #将列表L中所有的行字符串写到文件中
output.close()
```
**5.通过重定向标准备输出**
```python
buf = open('/root/a.txt', 'w')
print >> buf, '123\n', 'abc'
```
```python
print >> open('/root/a.txt', 'w'), '123\n', 'abc' #写入或生成文件
print >> open('/root/a.txt', 'a'), '123\n', 'abc' #追加
```
**shell -> python**
**1.管道**
```python
import os
var=os.popen('echo -n 123').read( )
print var
```
2.(python3已经移除)
```python
import commands
var=commands.getoutput('echo abc') # 输出结果
var=commands.getstatusoutput('echo abc') # 退出状态和输出结果
```
**3.文件**
```python
input = open('/tmp/mytxt', 'r')
S = input.read( ) # 把整个文件读到一个字符串中
S = input.readline( ) # 读下一行(越过行结束标志)
L = input.readlines( ) # 读取整个文件到一个行字符串的列表中
```