之前写了Python的基础语法和循环语句,有读者说:“基础的我都练了,但写稍微复杂一点的程序,感觉代码还是一团乱麻。怎么才能写出‘像样’的代码?”
这个问题问到点子上了。
会用变量、循环、判断,就像是学会了造砖头。但要盖一座能住人的房子,你还需要知道怎么砌墙、怎么搭梁、怎么布线。
今天这篇,就聊聊Python里那些“让代码从能跑变成好看”的进阶特性。不是让你成为专家,而是让你在写科研代码时,能少掉点头发。
一、函数进阶:让代码“像积木一样拼”
上篇我们讲了函数的基本写法。今天再深入一点,看看函数还能怎么玩。
1.1 参数的花式玩法
默认参数——给参数一个“保底值”
python
def greet(name, greeting="你好"):
return f"{greeting},{name}"print(greet("小冰"))# 你好,小冰print(greet("小冰","早上好"))# 早上好,小冰科研场景:处理实验数据时,校准系数可能经常不变,就可以设默认值。
python
def calibrate(data, coeff=1.02):
return[x * coeff for x in data]
# 大部分时候用默认校准
normal_data = calibrate(raw_data)
# 偶尔需要特殊校准
special_data = calibrate(raw_data, coeff=1.05)
可变参数——不知道传多少个参数时用*args
python
def sum_all(*numbers):
return sum(numbers)
print(sum_all(1,2,3,4,5))# 15
关键字参数——用**kwargs接收键值对
python
def record_exp(**info):
for key, value in info.items():
print(f"{key}: {value}")record_exp(name="温度实验", date="2024-06-01", temp=298.15)
# name: 温度实验
# date: 2024-06-01
# temp: 298.15
1.2 lambda表达式:一句话写完的函数
有时候函数太简单,连def都不想写,就可以用lambda。
python
# 普通函数
def square(x):
return x **2
# lambda写法
square =lambda x: x **2
最常用在需要“临时函数”的地方,比如排序。
python
students =[
{"name":"张三","score":85}, {"name":"李四","score":92}, {"name":"王五","score":78}]
# 按分数排序
students.sort(key=lambda s: s["score"], reverse=True)
1.3 函数作为参数:高阶函数
Python可以把函数当成普通变量传来传去。
python
def apply(func, data):
return[func(x) for x in data]
def square(x):
return x **2
def cube(x):
return x **3
numbers =[1,2,3,4]
print(apply(square, numbers))# [1, 4, 9, 16]
print(apply(cube, numbers))# [1, 8, 27, 64]
这在数据处理中特别有用——你可以写一个通用的“处理流程”,具体怎么处理,通过传不同的函数来决定。
二、模块与包:把代码“装进抽屉”
写代码就像整理实验室。如果一个实验台上堆满东西,你什么都找不到。但如果每个抽屉里分类放好,就方便多了。
模块,就是Python里的“抽屉”。
2.1 导入模块
python
# 导入整个模块
import math
print(math.sqrt(16))# 4.0
# 导入特定函数
from math import pi, sin
print(pi)# 3.14159...
# 导入并起别名(常用)
import numpy as np
2.2 自定义模块
把你写好的函数保存到一个.py文件中,比如my_tools.py:
python
# my_tools.py
def calculate_bmi(weight, height):
return weight /(height **2)
def get_category(bmi):
if bmi <18.5:
return"偏瘦"# ... 省略
然后在另一个文件里:
python
import my_toolsbmi = my_tools
calculate_bmi(70,1.75)
print(my_tools.get_category(bmi))
2.3 if __name__ == "__main__" 的妙用
很多Python文件末尾都会有这段代码:
python
def main():# 这里是主程序逻辑
pass
if __name__ =="__main__":
main()
它的作用是:当这个文件被直接运行时,执行main();当这个文件被别的文件导入时,不执行main()。
这样,一个文件既可以作为工具库被别人用,也可以独立运行。
三、文件操作:让程序“记住”数据
实验数据不能每次都手动输入,得学会读写文件。
3.1 读文本文件
python
# 推荐使用 with,自动关闭文件
with open("data.txt","r", encoding="utf-8")as f: content = f.read()# 全部读出来
# 或者一行一行读
for line in f:
print(line.strip())# strip去掉换行符
3.2 写文本文件
python
data =["实验1: 23.5","实验2: 24.1","实验3: 22.8"]
with open("result.txt","w", encoding="utf-8")as f: for line in data:
f.write(line +"\n")# 手动加换行
"w"是覆盖写入,"a"是追加写入。
3.3 科研常用的:读取CSV文件
CSV(逗号分隔值)是实验数据最常用的格式之一。
python
import csv
with open("experiment.csv","r", encoding="utf-8")as f: reader = csv.reader(f)
for row in reader:
print(row)# row是一个列表,每个元素是一列
如果第一行是表头,可以用csv.DictReader直接得到字典:
python
with open("experiment.csv","r")as f: reader = csv.DictReader(f)
for row in reader:
print(row["温度"], row["压力"])
四、异常处理:让程序“摔倒了能爬起来”
写代码最怕的是,一运行就报错,程序直接崩了。
用异常处理,可以优雅地处理错误。
4.1 基本用法
python
try:
num =int(input("请输入一个整数:")) result =10/ num
print(f"结果是:{result}")except ValueError:
print("输入的不是整数!")except ZeroDivisionError:
print("不能除以0!")except Exception as e:
print(f"其他错误:{e}")else:
print("没有发生异常,一切正常")finally:
print("无论如何都会执行的代码")科研场景:读取可能不存在的文件
python
filename ="data.csv"
try:
with open(filename,"r")as f:
data = f.read()
except FileNotFoundError:
print(f"文件{filename}不存在,使用默认数据") data ="默认数据"
4.2 主动抛出异常
有时候发现数据有问题,想主动报错:
python
def check_temperature(temp):
if temp <-273.15:
raise ValueError(f"温度{temp}低于绝对零度!") return temp
check_temperature(-300)# 会抛出异常
五、面向对象编程:让代码“更像现实世界”
面向对象是Python的核心特性,简单说就是把数据和操作数据的方法打包在一起。
5.1 一个简单的类
python
class Experiment:"""实验记录类"""
def__init__(self, name, date):
self.name = name
# 属性
self.date = date
self.results =[]
# 初始为空列表
def add_result(self, value):
"""添加实验结果"""
self.results.append(value)
print(f"已添加结果:{value}") def get_average(self):
"""计算平均值"""
if self.results:
return sum(self.results)/len(self.results)
else:
return0
def report(self):
"""输出报告"""
print(f"实验:{self.name}") print(f"日期:{self.date}") print(f"结果:{self.results}") print(f"平均值:{self.get_average():.2f}")使用:
python
exp = Experiment("飞轮储能测试","2024-06-01")exp.add_result(23.5)
exp.add_result(24.1)
exp.add_result(22.8)
exp.report()
输出:
text
实验:飞轮储能测试
日期:2024-06-01
结果:[23.5, 24.1, 22.8]
平均值:23.47
5.2 为什么用类?
封装:把相关的数据和函数放在一起,代码更清晰
复用:可以基于一个类创建多个实例(多个实验)
扩展:可以通过继承增加新功能
六、生成器与迭代器:处理大数据时的“省内存神器”
如果你的数据很大(比如几百万行实验记录),一次性读进内存可能直接卡死。
生成器可以“按需生成”,用一点吐一点。
6.1 用yield创建生成器
python
def read_large_file(filename):
"""逐行读取大文件,不一次性加载到内存"""
with open(filename,"r") as f:
for line in f:
yield line.strip()# 每次yield一行,然后暂停
# 使用
for line in read_large_file("big_data.csv"): process(line)# 处理一行,内存里永远只有一行
6.2 生成器表达式
类似列表推导式,但用()而不是[],不会立即生成所有元素。
python
# 列表推导式:立即生成全部,占用内存
squares_list =[x**2for x inrange(10000000)]
# 可能卡死# 生成器表达式:按需生成,内存友好
squares_gen =(x**2 for x in range(10000000))for s in squares_gen:
if s >1000:
break# 只需要前面的,后面的根本不计算
写在最后
今天这篇内容有点多,但都是你写出“优雅、健壮、可维护”代码的必备武器。
总结一下:
函数进阶让代码可复用
模块让代码可管理
文件操作让数据可持久
异常处理让程序可容错
面向对象让逻辑可组织
生成器让内存可节省
不需要一次性全记住,但遇到问题的时候,知道“哦,Python有这个工具,我去查一下”就够了。
如果你正在学Python,遇到了什么卡点,欢迎在评论区告诉我。我们一起踩坑,一起进步。