惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Apple Machine Learning Research
Apple Machine Learning Research
Blog — PlanetScale
Blog — PlanetScale
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
G
Google Developers Blog
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Threat Research - Cisco Blogs
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Cloudflare Blog
博客园 - 【当耐特】
AWS News Blog
AWS News Blog
U
Unit 42
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
T
Tor Project blog
Microsoft Security Blog
Microsoft Security Blog
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Recorded Future
Recorded Future
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threatpost
Latest news
Latest news
GbyAI
GbyAI
S
SegmentFault 最新的问题
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
Hacker News: Ask HN
Hacker News: Ask HN
美团技术团队
N
News | PayPal Newsroom
J
Java Code Geeks
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The Hacker News
The Hacker News
The GitHub Blog
The GitHub Blog
V
V2EX
N
News and Events Feed by Topic
T
Troy Hunt's Blog
Security Latest
Security Latest
博客园 - 叶小钗
P
Palo Alto Networks Blog

ControlNet Blog

异星工厂中的高品质产率分析 比之前更进一步的终极看番工具栈 探索数据潜力:预训练模型与Masked Autoencoder的表征学习之旅 异星工厂原版原创蓝图分享 学习AI绘画,从Diffusion和CLIP开始 怎么通信比较快?Python跨进程通信测试 Python编程基础08:单元测试和异常处理 Python编程基础07:标准库和第三方库 LightIoC: Scala原生基于注解的依赖注入库 Python编程基础06:Python的面对对象编程 Windows最佳动画观看环境配置指南(MPC-HC, madvr, SVP, Anime4K) 计算机视觉中的Transformer续 解锁网易云变灰曲目PC版(Windows, MacOS) Python编程基础04:Python高级集合类型和一些杂项 Aria2傻瓜安装部署指南 Python编程基础03:数据结构和Python集合类型 在UEFI Secure Boot下的Linux安装N卡驱动 计算机视觉中的Transformer 一些邮箱客户端的使用对比
Python编程基础05:Python的过程分解和文件IO
ControlNet · 2021-07-19 · via ControlNet Blog

人生苦短,我用Python![1]

这次的主要内容主要是介绍Python中的过程分解和文件IO。过程分解包括了函数(function),模块(module)。而文件IO主要是介绍使用Python打开文件并进行读写操作。

过程分解概念

过程分解是一种解决编程问题的策略。它将一个复杂的问题分解为一个一个的小问题,这些小问题更简单,更独立,并且更易于管理,然后通过某种方式来解决这些小问题。通过使用这种方法,编程也会变得简单,更容易理解,更方便做规划和实现。

desktop-example
Fig. 1. 台式机的硬件可拆分也是一种分解思维. Adapted from [2]

要合理的分解这些组件,需要清晰的认识每一个部件的输入和输出。在Python中,过程分解是主要由函数(Function),模块(Module)和类(Class)组成。其中最主要的关键,是提升整体代码的复用性(Reusability)。

函数

函数(Function)是Python中的重要组成部分。函数是一种独立的语句集合,是为完成某一个特定的任务,解决一个特定的问题而定义的。

它可以使用任意数量的参数作为输入,并且返回任意数量任意类型的值。函数需要先创建,然后再进行调用。

函数是对过程或者功能的一种抽象。用户只需要知道怎么把函数用起来去解决问题,而不需要知道函数内部是怎么工作的。

Python中的函数

在Python中,函数是使用关键字def定义的。在函数的开头,需要定义函数的名称和参数(Argument)。函数的名称,参数和返回值构成了函数签名。

函数的组成部分:

  • 函数名
  • 参数(0或多个)
  • 文档注释(可选)
  • 函数体
  • 返回值(可选)

函数的命名规范:

  • 与变量名相同
  • 使用camelCase或者underscore
  • 必须以字母或者下划线开头,并且只能包含字母、数字或者下划线

define_func
Fig. 2. 创建一个函数.

定义一个函数(有参数)

1
2
3
def addition_func(first_arg, second_arg):
result = first_arg + second_arg
return result

定义一个函数(默认参数)

1
2
3
def addition_func(first_arg=0, second_arg=0):
result = first_arg + second_arg
return result

调用函数:

  • 位置参数(不带关键字): 得按照函数定义的顺序来调用
  • 关键字参数: 使用关键字来调用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    sum = addition_func(10, 8)
    print("The result is", sum)


    sum = addition_func(second_arg=8)
    print("The result is", sum)


    sum = addition_func(2, second_arg=8)
    print("The result is", sum)

return和print的区别

return:

  • return只能用在函数内部,否则会有语法错误
  • 在一个函数中只会运行一次return
  • 在函数里return后面的代码将不会被运行
  • 这个return的值将会赋予函数的调用者

print:

  • print可以用在函数外部,也可以用在函数内部
  • 可以在函数内部执行多次
  • 在函数里print后面的代码可以继续运行
  • 这个print的值将会输出至控制台

main函数

main函数是一个特殊的函数,它指示程序的执行流程,定义了程序的入口点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def function1():
...

def function2():
...

def function3():
...

def main():
function2()
function3()
function1()

if __name__ == "__main__":
main()

function_flow
Fig. 3. 函数的执行流程.

模块

Python中的模块(module)是一个包含了定义和语句的Python源代码文件。模块可以被其他程序引用,以使用它们中的函数,类,以及变量。

为了在另一个Python程序中使用别的模块(.py文件):

  • 使用import关键字
  • 语法:
    • import <module_name>
    • import <module_name> as alias

使用已导入模块中的某一个函数:

  • 语法:
    • <module_name>.<function_name>
    • <alias>.<function_name>
1
2
3
4
5
6
7
8
9
10
11
12
13
14


def addition_func(first_arg, second_arg):
result = first_arg + second_arg
return result
def subtraction_func(first_arg, second_arg):
result = first_arg - second_arg
return result
def multiplication_func(first_arg, second_arg):
result = first_arg * second_arg
return result
def division_func(first_arg, second_arg):
result = first_arg // second_arg
return result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import arithmetic as arm

def main():
num1 = int(input("Enter first number: "))
num2 = int(input("Enter second number: "))
operator = input("Enter +, -, *, or /: ")
if operator == "+":
output = arm.addition_func(num1, num2)
print("The result is", output)
elif operator == "-":
output = arm.subtraction_func(num1, num2)
print("The result is", output)
elif operator == "*":
output = arm.multiplication_func(num1, num2)
print("The result is", output)
elif operator == "/":
output = arm.division_func(num1, num2)
print("The result is", output)
else:
print("Invalid operator!")

if __name__ == "__main__":
main()

为什么要使用函数

  • DRY法则: 不要重复你的代码(Don’t Repeat Yourself)
  • 将复杂任务分解为一系列简单任务
  • 提升代码的可读性
  • 代码复用

文件IO

打开文件: open(file, mode)

  • 创建一个文件句柄(对文件进行各种操作的对象)
  • 两个关键的参数:
    • file: 文件路径(可以是绝对路径,也可以是相对路径)
    • mode: 文件的操作模式(如下所示)[3]

在中文的Windows系统中,可能需要使用encoding="UTF-8"来指定文件的编码方式,否则可能会出现乱码。因为文件的写入格式和读取格式需要相同。

mode 含义
"r" 读取(默认)
"w" 覆盖写入
"x" 新建文件并写入
"a" 在文件末尾追加写入
"b" 二进制
"+" 打开文件用于更新(可读可写)

读取文件

读取一个文件: input_handle = open(file, "r")

  • input_handle.readline(): 从文件中读取一行(包含\n)
  • for line in input_handle: 遍历文件中的每一行
  • input_handle.readlines(): 读取整个文件,返回一个列表,每个元素为一行
  • input_handle.read(): 读取整个文件,返回一整个字符串

关闭一个文件: input_handle.close()

  • 使用完之后,不要忘记关闭文件
1
2
3
4
5
6
7
8
9
10
11

file_handle = open("input_file.txt", "r")

list_of_lines = []

for line in file_handle:
list_of_lines.append(line)

print(list_of_lines)

file_handle.close()

也可以使用with关键字

1
2
3
4
5
6
7
8
9

with open("input_file.txt", "r") as file_handle:

list_of_lines = []

for line in file_handle:
list_of_lines.append(line)

print(list_of_lines)

写入文件

打开一个文件用于写入:

  • open(file, "w"): 覆盖原有文件中的内容
  • open(file, "a"): 在文件的末尾追加写入

写入文件:

  • file_handle.write(the_line): 写入一行
  • 注意: \n作为换行符,需要手动添加到每行的末尾。
1
2
3
4
5
6
7
8
9
10
11
12

input_handle = open(input_file, "r")

output_handle = open(output_file, "w")

for line in input_handle:

line = line.lower()
output_handle.write(line)

input_handle.close()
output_handle.close()

也可以使用with关键词

1
2
3
4
5
with open(input_file, "r") as input_handle, open(output_file, "w") as output_handle: 
for line in input_handle:

line = line.lower()
output_handle.write(line)

实践试试

这次我们来试试看使用学到的文件IO和Python函数的知识。使用Jupyter Notebook来试试看吧。

文件基础操作

我们有一个文本文件simple_file.txt,里面包含了以下内容。

1
2
3
4
1 2 five
5 7 one
6 9 three
9 8 four

文件的每一行中包含三个值,前两个是数字,第三个是表示数字的英文字符串,比如说”one”。我们需要做的是将第三个值转换为数字,并且将整个文件的结果写入到output_file.txt里,我们只拿1~5作为例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


with open("simple_file.txt","r") as input_handle, open("output_file.txt","w") as output_handle:

for line in input_handle:
line = line.strip("\n")
line_number = line.split(" ")
if line_number[2] == "one":
line_number[2] = "1"
elif line_number[2] == "two":
line_number[2] = "2"
elif line_number[2] == "three":
line_number[2] = "3"
elif line_number[2] == "four":
line_number[2] = "4"
elif line_number[2] == "five":
line_number[2] = "5"
new_line = line_number[0] + " " + line_number[1] + " " + line_number[2] + "\n"
output_handle.write(new_line)


学生信息系统

这里有两个文件,一个是student_data.txt,里面包含着学生的ID,名字和课程。如下所示。

1
2
3
4
5
1,tom,clayton
2,alex,caulfield
3,sarah,clayton
4,philip,clayton
5,david,caulfield

另一个文件是enrollment.txt,包含着学生选课的记录,每一行分别是学生ID和课程名称。

1
2
3
4
5
6
7
8
9
10
1 mathematics
1 english
2 programming
3 mathematics
3 physics
4 mathematics
4 chemistry
4 literature
5 english
5 history

我们的任务是建立一个基础的查询系统,这个系统通过输入学生的名字,先判断学生在不在这个系统中,如果在,再输出学生选的课程列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def query(student_name):

unit_list = []
with open("student_data.txt","r") as student_file, open("enrollment.txt","r") as enrollment_file:

for student_line in student_file:
student_line = student_line.strip("\n")
student_list = student_line.split(",")
if student_name in student_list:
student_no = student_list[0]
for enrollment_line in enrollment_file:
enrollment_list = enrollment_line.split(" ")
if student_no in enrollment_list:
unit_list.append(enrollment_list[1].strip("\n"))
if unit_list == []:
print("Cannot find the student")
return unit_list

name = input("enter the student name. ")
print(query(name))

括号匹配检查

在求解一个数学表达式的时候,括号代表着计算的更高优先级。比如说:

$$(5+3)+((6-9)/(5+7))$$

其中$(6-9)$和$(5+7)$会在除法运算之前计算。

为了使这个能正常工作,我们需要检查括号是否匹配。匹配的括号意思是,对于每一个左括号都有一个对应的右括号,而且括号也需要正确嵌套。例如,以下是正确的括号字符串:

()()()()()
(()())
((()))

而以下的字符串是错误的:
((()
()()()(()
((()))(

区分正确的括号匹配是编程语言中的重要部分。编写一个程序,从左到右读取一串括号,并检查括号是否平衡。提示:可以使用一个叫做栈(Stack)的数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def check_for_balanced_parenthesis(string_of_parenthesis):
stack = []
for char in string_of_parenthesis:
if char == '(':
stack.append(char)
elif char == ')':
if len(stack) == 0:
return False
else:
stack.pop()
if len(stack) == 0:
return True
else:
return False

check_for_balanced_parenthesis(input("Please enter a string to check parenthesis balance."))

像这样将一段逻辑包装在代码中,可以方便以后在其他地方进行调用,提高代码的可读性和复用性。

参考文献

  • [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/.
  • [2] A. Bell, "Standard 1 - Objective 1: Demonstrate understanding of computer hardware, peripherals and troubleshooting.", slideplayer, 2021. [Online]. Available: https://slideplayer.com/slide/5809212/.
  • [3] "Python3 File 方法 | 菜鸟教程", Runoob.com, 2021. [Online]. Available: https://www.runoob.com/python3/python3-file-methods.html.