news 2026/10/8 22:55:20

python 基本结构语句(函数和模块)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python 基本结构语句(函数和模块)

前言


Python 程序的基本积木只有两样东西:函数(function)把一段逻辑打包成可以 反复调用的单元,模块(module)把一个.py文件打包成可以反复导入的单元。 两者的关系是"层层套娃"——模块里装函数,包(package)里装模块。


初学者常有的误解有两个。第一,以为"模块必须是一个很正式的东西",其实任何 一个.py文件就是一个模块,你随手写的tools.py就是一个模块,import tools就能用它。第二,以为import只是"引用一下",不会产生副作用——实际上import会从头到尾执行目标模块的顶层语句,这决定了模块里哪些代码该写、 哪些该放进函数里。


本文讲清楚def的定义与调用规则、模块与导入的几种写法、以及__name__的 作用。所有写法都以 Python 3 为准,不涉及早已停止维护的 Python 2。


一、函数:定义与调用


用def定义函数,用"函数名加括号"调用。函数体靠缩进界定,return把结果 交回调用方。


# 适用于 Python 3.8+

def area(width, height):
"""返回矩形面积。"""
return width * height

result = area(3, 4)
print(result) # 12

要点:



  • return是可选参数。没写return,或者只写return不带值,函数都


返回None。这不是"什么都不返回",而是"返回None"。



  • def是可执行语句。解释器执行到def那一行时,才创建函数对象并把


名字绑定上去。所以函数必须在调用之前定义(在模块顶层按从上到下的顺序)。



  • 参数有五种形态:普通参数、带默认值的参数、*args(收集多余位置参数)、


**kwargs(收集多余关键字参数)、以及*后面的仅关键字参数。默认值在函数定义时求值一次,这一点在"常见坑点"里单独说。


二、模块:一个文件就是一个模块


把上面那个函数单独存成shapes.py,它就变成一个模块。另一个文件里这样用:


# 适用于 Python 3.8+

import shapes

print(shapes.area(2, 5)) # 10

import做三件事:找到shapes.py、执行它的顶层代码、把得到的模块对象 绑定到名字shapes上。之后用shapes.area访问里面的函数。


导入有多种写法,各有适用场景:




写法调用方式适用场景



import shapesshapes.area()最推荐,来源清晰

import shapes as spsp.area()模块名太长

from shapes import areaarea()只用一两个名字

from shapes import area as aa()避免与本地名字冲突

from shapes import *area()不推荐,污染名字空间



包(package)就是含有__init__.py的目录,里面可以放多个模块,用点号 分层导入,例如import mypkg.shapes。从 Python 3.3 起还有"命名空间包", 不一定需要__init__.py,但初学阶段老老实实放一个__init__.py最不容易 出问题。


三、模块的执行与 __name__


前面说过import会执行模块的顶层代码。那如果这个模块既想被导入、又想在 命令行直接运行时执行一些额外逻辑,怎么办?答案是判断__name__。


__name__是每个模块都有的变量:被导入时,它的值就是模块名;作为脚本直接 运行时,它的值是字符串"__main__"。于是就有了那句著名的守卫:


# 适用于 Python 3.8+
# 文件 shapes.py

def area(width, height):
return width * height

if __name__ == "__main__":
print(area(3, 4))


  • 直接python shapes.py运行:__name__ == "__main__"成立,会打印 12。

  • 在别的文件里import shapes:__name__ == "shapes",那段print**不会


执行**,只把area导入进来。


这就是"主入口"的含义:把只应该在直接运行时做的事,放进if __name__ == "__main__":里。背后的机制是:直接运行的那个脚本文件,其模块名被设为"__main__"。


四、把函数和模块组织好的几条经验



  1. 一个模块负责一件事。shapes.py就只放几何相关的函数,不要塞进数据库


连接、字符串工具等无关内容。



  1. 顶层只放定义,不放动作。顶层写def、class、常量赋值是安全的;


写"打印、读写文件、发网络请求"这类动作就要小心,因为导入方一import就会执行。



  1. 函数尽量小而单一。一个函数只做一件事,参数和返回值都清晰,测试和复用


都更容易。



  1. 数据用参数传,不要藏在全局变量里。全局可变状态会让函数行为随调用


顺序变化,很难排查。


# 适用于 Python 3.8+

# tools.py
def normalize(text):
"""去掉首尾空白并转小写。"""
return text.strip().lower()

def split_words(text):
"""按空白切成单词列表。"""
return normalize(text).split()

# 适用于 Python 3.8+

# main.py
from tools import split_words

print(split_words(" Hello World ")) # ['hello', 'world']

五、函数签名速查




语法名称行为



def f(a, b)普通参数必须传,可按位置或关键字

def f(a=1)带默认值可省略,省略时用 1

def f(*args)可变位置参数多余的按位置参数收成元组

def f(**kwargs)可变关键字参数多余的关键字参数收成字典

def f(a, *, b)仅关键字参数b只能写b=...传

def f(a, /, b)仅位置参数a只能按位置传(3.8+)



def f(a, /, b)的/是Python 3.8 才引入的(PEP 570)。在 3.7 及更早 版本里写/会直接语法错误。仅位置参数常用于内建函数那种"参数名不重要、 不该按关键字传"的接口。


常见坑点



  1. 忘了 return,结果拿到 None


``python # ❌ 只打印不返回,外面拿到的是 None def double(x): print(x * 2) # ✅ 用 return 把结果交出去 def double(x): return x * 2``



  1. 函数在定义之前调用


``python # ❌ def 还没执行到,名字不存在 foo() def foo(): pass # ✅ 先定义后调用 def foo(): pass foo()``



  1. 导入模块时执行了不该执行的动作


``python # ❌ 顶层直接干活,一 import 就触发 # report.py print("正在生成报表...") # ✅ 放进守卫或函数里 if __name__ == "__main__": print("正在生成报表...")``



  1. **用 from x import * 造成名字覆盖**


``python # ❌ 不知道导入了什么,可能覆盖本地名字 from math import * # ✅ 只导入用到的 from math import sqrt, pi``



  1. 循环导入


``python # ❌ a.py 导入 b,b.py 又导入 a,可能 ImportError # ✅ 把共用部分抽到第三个模块;或在函数内部延迟导入 def need_b(): import b # 延迟到调用时才导入 return b.something()``



  1. 把可变数据挂在模块顶层被到处改


``python # ❌ 谁都来改 CACHE,行为随调用顺序漂移 CACHE = [] def add(x): CACHE.append(x) # ✅ 用参数传,或封装进类里管理``



  1. 函数里给模块级变量赋值忘了 global


``python COUNT = 0 # ❌ 有赋值语句,COUNT 被当成局部变量,读取时未绑定 → UnboundLocalError def bump(): COUNT = COUNT + 1 # ✅ 声明 global 后改的才是模块级那个 def bump(): global COUNT COUNT += 1``



  1. 默认参数写成可变对象


``python # ❌ lst 只在定义时创建一次,会跨调用累积 def add_item(x, lst=[]): lst.append(x) return lst # ✅ 用 None 当哨兵 def add_item(x, lst=None): if lst is None: lst = [] lst.append(x) return lst``


总结




概念关键点



函数def是可执行语句,必须在调用前定义

返回值没有return就返回None

参数普通 / 默认 /*args/**kwargs/*//

模块一个.py文件就是一个模块

导入import x会执行x的顶层代码

主入口if __name__ == "__main__":区分脚本与导入



把"函数负责一件事、模块顶层只做定义、导入不做副作用"这三条原则记牢,代码结构 就不会乱。参数形态和__name__是最容易记混的两处,动手写几个小模块跑一跑 就能形成稳定的直觉。





版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 22:54:31

我想做一个智能体专栏,顺便把博客也搭起来

最近一直在想一件事:智能体到底能帮我解决什么实际问题?网上关于 AI Agent 的内容很多,但看多了容易有一种感觉:概念很热闹,真正落到自己手上时,还是不知道从哪开始。于是我想,不如直接开一个专…

作者头像 李华
网站建设 2026/10/8 22:52:14

SSH 常见用法(二):通过 SSH 认证访问 Git 仓库

SSH 常见用法(二):通过 SSH 认证访问 Git 仓库 系列导读 本系列共包含一篇总览和四篇专题文章: 系列位置文章主题主要内容总览浅谈 SSH:原理、认证与四种常见用法认识 SSH 及其四种常见用法第一篇SSH 常见用法&…

作者头像 李华
网站建设 2026/10/8 22:51:24

2026双智造基地官网正式上线,一站速览智造前沿动态

2026双智造基地官网正式上线,一站速览智造前沿动态当门窗行业还在拼单品性能时,头部玩家已经开始亮出“智造底牌”。2026年,金致尚品门窗双智造基地官网正式上线,这意味着什么?不仅是企业数字化形象的全面升级&#xf…

作者头像 李华
网站建设 2026/10/8 22:51:07

远程线程注入

基础概念 注入定义:在第三方进程不知情 / 未授权的前提下,把代码 / 模块写入目标进程虚拟地址空间并执行 安全领域:注入与反注入持续对抗 常见注入:远程线程注入、APC 注入、钩子注入、输入法注入、导入表注入远程线程注入核心思路…

作者头像 李华
网站建设 2026/10/8 22:51:00

e2e视口配置完全指南:多分辨率Web测试最佳实践

e2e视口配置完全指南:多分辨率Web测试最佳实践 【免费下载链接】e2e Next generation e2e testing framework for web and mobile apps. 项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2e e2e 视口(viewport)配置是这套开源 A…

作者头像 李华