基本语法
本次以 JS 为对比来解释 Python 的语法特点。
最明显的区别 - 没有大括号!
Python 用缩进(空格或 tab )代替了 JS 的大括号块
# Python
if x > 5:
print("大于5") # 属于if块
print("依然在if块内") # 同级缩进属于同一代码块
print("已退出if块") # 减少缩进表示退出块
# 等效JS
if (x > 5) {
console.log("大于5");
console.log("依然在if块内");
}
console.log("已退出if块");
变量声明不需要关键字
# Python
name = "Alice" # 直接赋值,不用let/const/var
# JS
let name = "Alice";
函数定义用 def 而不是 function
# Python
def greet(name):
return "Hello " + name
# JS
function greet(name) {
return "Hello " + name;
}
常见符号差异
- 布尔值:
True/False
(首字母大写) 空值:None
(相当于 JS 的null
)- 相等比较:
==
或 is (JS的===
) - 不等于:
!=
或is not
- 逻辑与/或:
and/or
(不是&&/||
)
列表 vs 数组
# Python列表(类似JS数组)
fruits = ["apple", "banana"]
fruits.append("orange") # 相当于JS的push
# JS
let fruits = ["apple", "banana"];
fruits.push("orange");
字典 vs 对象
# Python字典(类似JS对象)
person = {"name": "Alice", "age": 25}
print(person["name"]) # 访问属性
# JS
let person = {name: "Alice", age: 25};
console.log(person.name);
导入模块 vs import/require
# Python
import math
from datetime import date
# JS
const math = require('math');
import { date } from 'datetime';
类语法差异
# Python
class Person:
def __init__(self, name): # 构造函数
self.name = name
def greet(self): # 方法必须带self参数
print(f"Hello {self.name}")
# JS
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello ${this.name}`);
}
}
调试
- 用
print()
代替console.log()
- 类型检查用
type(obj)
代替typeof obj
- 注意缩进错误(会直接报错)
- Python 没有自动分号插入,换行就是语句结束
问题
为什么 Python 可以执行代码块,而不是整个文件 ?
这主要得益于 Python 解释器的设计:
- Python 支持交互式环境(REPL - Read-Eval-Print Loop),可以一行一行地输入并立即执行代码。
- 解释器会把每个代码块(无论是一行还是多行)先编译成字节码,然后马上执行。
- Python 以“代码块”为基本单位,可以是一个表达式、函数、类,甚至整个文件。
- 全局命名空间可以动态更新,方便逐步测试和调试。
- 这种机制让你可以快速测试代码片段、交互式调试和逐步构建程序,非常适合学习和实验。
直接调用函数,跟在主程序调用的差别?
在 Python 中,直接调用函数和在主程序中调用函数的主要区别在于代码的执行时机和模块的 __name__
属性:
- 直接执行脚本时:
__name__
会被设置为__main__
- 被导入为模块时:
__name__
会变为模块的文件名(不含.py
)
# 示例:module.py
def foo():
print("Function foo is called")
if __name__ == "__main__":
print("直接执行脚本时运行")
foo()
else:
print("被导入为模块时运行")
最佳实践总结:
- 功能函数:直接定义在模块中,供其他代码导入复用
- 脚本入口:用
if __name__ == "__main__"
保护,避免导入时执行 - 测试代码:放在主程序块中,或使用单元测试框架(如 unittest)
# 正确示例:兼顾模块化和脚本执行
def useful_function():
return "This is reusable"
if __name__ == "__main__":
# 仅直接执行时运行
print(useful_function())
通过区分这两种调用方式,可以写出既适合导入复用又可独立运行的 Python 代码。
is
、is not
是用在什么场景?
提示:
is
用于判断对象标识(内存地址),而不是内容是否相等。判断内容要用==
。
判断 None:
a = None
if a is None:
print("a 是 None")
if a is not None:
print("a 不是 None")
判断单例对象:
比如 True、False、Ellipsis(...)、NotImplemented 这些单例对象
flag = True
if flag is True:
print("flag 是 True")
if flag is not False:
print("flag 不是 False")
判断两个变量是否指向同一个对象(内存对象):
a = []
b = a
c = []
print(a is b) # True,因为 b 和 a 指向同一个列表对象
print(a is c) # False,虽然内容一样,但不是同一个对象
判断类型对象:
if type(a) is list:
print("a 是列表")
注意:
is
和is not
判断的是“对象标识”(内存地址),不是内容是否相等- 判断内容要用
==
或!=
Python 文件命名规范
在 Python 中,文件命名遵循一些约定俗成的规范,这些规范主要来自 PEP 8(Python 官方风格指南)和社区共识。以下是关键要点:
基本规范:
- 小写字母:文件名应全部使用小写字母(例如
module.py
而非Module.py
) - 下划线分隔:单词间用下划线
_
连接(例如data_processor.py
而非dataprocessor.py
或DataProcessor.py
) - 简短明确:文件名应清晰表达内容用途(例如
utils.py
比misc.py
更明确)
特殊文件命名:
- 测试文件:以
test_
开头(例如test_models.py
) - 主程序入口:通常命名为
main.py
或app.py
- 配置文件:常用
config.py
或settings.py
- 私有模块:以单下划线开头表示内部使用(例如
_internal.py
)
扩展名规范:
- Python 文件:
.py
- 编译文件:
.pyc
(自动生成,无需手动命名) - C 扩展模块:
.pyx
(Cython)或.pyd
(Windows)
应避免的命名:
- 空格或特殊字符(如
my module.py
) - 连字符(如
data-processor.py
) - 与 Python 关键字冲突(如
class.py
) - 与标准库模块同名(如
os.py
)
项目结构示例:
my_project/
├── main.py # 主程序入口
├── config.py # 配置文件
├── requirements.txt # 依赖文件
├── src/ # 主要代码
│ ├── data_loader.py # 数据加载模块
│ ├── utils.py # 工具函数
│ └── _internal.py # 内部使用模块
└── tests/ # 测试目录
├── test_loader.py # 测试文件
└── conftest.py # pytest 配置
注意事项:
- 在 Unix/Linux 系统中,文件名是大小写敏感的
- Windows 系统不区分大小写,但建议统一小写以避免跨平台问题
- 导入时模块名应与文件名一致(
import data_loader
对应data_loader.py
)
遵循这些规范可以提高代码的可读性和可维护性,尤其是在团队协作中。
最后
记住 Python 的这些设计哲学:
- 明确优于隐晦
- 简单优于复杂
- 可读性很重要
刚开始可能会觉得别扭,但适应后你会爱上 Python 的简洁优雅。建议边看代码边用 Python 交互环境尝试小片段,很快就能找到感觉。