一、变量
1.1 变量的定义与使用
message="Hello Python world!"print(message)message="Hello Python Crash Course world!"print(message)输出:
Hello Python world! Hello Python Crash Course world!1.2 变量命名规则
# ✅ 有效的变量名message="Hello"message_1="Hello"_message="Hello"# ❌ 无效的变量名(会报错)1_message="Hello"# 不能以数字开头message-1="Hello"# 不能包含连字符greeting message="Hello"# 不能包含空格命名规则总结:
- 只能包含字母、数字和下划线
- 不能以数字开头
- 不能包含空格
- 不能使用Python关键字
- 区分大小写
1.3 Python关键字(不能用作变量名)
False,None,True,and,as,assert,break,class,continue,def,del,elif,else,except,finally,for,from,global,if,import,in,is,lambda,nonlocal,not,or,pass,raise,return,try,while,with,yield1.4 与Java变量对比
Java:变量是容器,类型固定,基本类型存值、对象存引用
Python:变量是标签,类型动态,一切皆对象、一切皆引用
1.4.1 变量本质(最核心差异)
Java:
- 变量是固定类型的内存盒子,变量本身有类型,盒子里存数据值(基本类型)或者对象引用地址(引用类型)。
- 声明时必须指定类型,变量类型终身固定,不能再存别的类型。
// Javainta=10;// a 是int类型盒子,只能放整数Strings="hi";// s存对象的地址
Python:
- 变量是标签 / 名字,贴在对象上;对象才有类型,变量本身没有类型。
a=10a="hello"# 合法,把标签a撕下来贴到字符串对象上 a只是名字,没有类型;真正有类型的是右边的对象10、"hello"。- 同一个变量名可以反复绑定不同类型对象。
1.4.2 声明与赋值
Java:显式类型声明
- 先声明,再赋值;声明必须写类型
- 局部变量不会自动初始化,不赋值不能使用。
// 基本类型intage=25;doubleprice=19.99;booleanisActive=true;chargrade='A';// 引用类型Stringname="Alice";List<String>list=newArrayList<>();Map<String,Object>map=newHashMap<>();// 变量类型一旦声明,不能改变intx=10;x="hello";// ❌ 编译错误:不兼容的类型
Python:无类型声明
- 没有单独声明步骤,赋值即创建变量
- 没有变量预先声明语法
# 无需声明类型,直接赋值age=25price=19.99is_active=Truegrade='A'name="Alice"my_list=[]my_dict={}# 变量可以重新指向不同类型x=10x="hello"# ✅ 完全合法x=[1,2,3]# ✅ 完全合法
1.4.3 赋值语义差异
Java:
- 基本数据类型(int,double,boolean…):值拷贝
- 引用类型(类、数组):拷贝引用地址,两个变量指向同一个对象
// 1. 基本类型赋值:值复制inta=10;intb=a;// b = 10(复制值)b=20;System.out.println(a);// 10// 2. 对象类型赋值:引用复制List<String>list1=newArrayList<>();list1.add("A");List<String>list2=list1;// list2 获得 list1 的引用list2.add("B");System.out.println(list1);// [A, B](list1 也被修改)// 3. 字符串赋值(不可变对象)Strings1="hello";Strings2=s1;// s2 获得 s1 的引用s2=s2+" world";// 创建新对象,s1 不受影响System.out.println(s1);// hello
Python:
- 一切皆对象,没有原生基本类型;
- 所有赋值都是"引用赋值"。
- 不可变对象重新赋值不是修改对象,是更换标签绑定。
# 1. 不可变对象(int, float, str, tuple)a=10b=a# b 指向 a 指向的对象 10b=20# b 指向新对象 20,a 不受影响print(a)# 10# 2. 可变对象(list, dict, set)list1=[1,2,3]list2=list1# list2 指向 list1 指向的同一个列表list2.append(4)print(list1)# [1, 2, 3, 4]# 3. 字符串(不可变)s1="hello"s2=s1# s2 指向 s1 指向的字符串对象s2+=" world"# 创建新字符串对象,s1 不受影响print(s1)# hello
1.4.4 常量
Java:final修饰,变量引用不可修改
// final 变量:只能赋值一次finalintMAX_SIZE=100;// MAX_SIZE = 200; // ❌ 编译错误// final 引用:引用不能变,但对象内容可以变finalList<String>list=newArrayList<>();list.add("A");// ✅ 可以修改对象内容// list = new ArrayList<>(); // ❌ 编译错误// 真正不可变:使用不可变类finalStrings="hello";// s = s + " world"; // ❌ 编译错误(String 不可变)Python:约定 + 机制
# Python 没有真正的常量机制# 约定:全大写表示常量MAX_SIZE=100# 仍然可以修改(只是约定)MAX_SIZE=200# ✅ 不会报错# 模拟不可变性:使用元组defget_config():return("host","localhost","port",8080)# 返回元组# 使用 @property 实现只读属性classCircle:def__init__(self,radius):self._radius=radius@propertydefradius(self):returnself._radius@propertydefarea(self):return3.14*self._radius**2c=Circle(5)print(c.radius)# 5print(c.area)# 78.5# c.radius = 10 # ❌ AttributeError: can't set attribute冻结对象(frozenset, tuple):
# frozenset:不可变集合s=frozenset([1,2,3])# s.add(4) # ❌ AttributeError# tuple:不可变列表t=(1,2,3)# t[0] = 10 # ❌ TypeError# 注意:tuple中的可变元素仍可修改t=([1,2],3)t[0].append(4)# ✅ 可以修改!print(t)# ([1, 2, 4], 3)1.4.5 多变量赋值
Java:
inta,b,c;a=b=c=10;// 支持链式赋值Python:
# 链式赋值a=b=c=10# 序列解包(Java没有)x,y=10,20x,y=y,x# 交换变量,不需要临时变量1.4.6 类型系统差异
Java:
- 静态类型系统,强制转换,变量类型不变
// 编译时类型检查Strings="hello";inti=10;// 类型转换需要显式进行Objectobj="hello";Stringstr=(String)obj;// 需要强制类型转换// 自动装箱/拆箱Integerboxed=10;// 自动装箱intunboxed=boxed;// 自动拆箱
Python:
- 动态类型系统,转换产生新对象,变量本身类型不受限制
# 运行时类型检查s="hello"i=10# 无需类型转换,直接重新赋值obj="hello"str_val=obj# 无需转换,直接引用# 没有基本类型和包装类型的区分# Python中 int 就是对象,没有 int vs Integer 的区别x=10# x 是 int 对象print(type(x))# <class 'int'>
1.4.7 变量作用域
Java:
- 块级作用域:
{ }就会产生新作用域{intx=10;}// x 外面不可见
Python:
- 没有块级作用域(if/for/while 不会新建作用域),只有函数、类、模块作用域
foriinrange(3):num=100print(num)# 可以访问,for的块不隔离变量
1.4.8 内存模型对比
Java 特点:
- 基本类型(int, double, boolean等):值直接存储在栈中
- 对象类型(String, List等):引用存储在栈中,对象存储在堆中
- 赋值给另一个变量时:基本类型复制值,对象类型复制引用
// Javainta=10;intb=a;// b 获得 a 的值副本b=20;System.out.println(a);// 10(a 不受影响)Strings1="hello";Strings2=s1;// s2 获得 s1 的引用副本// s1 和 s2 指向同一个字符串对象// 但 String 是不可变的,所以修改 s2 不会影响 s1Python 特点:
- 没有基本类型:所有数据都是对象,存储在堆中
- 变量只是名字/标签,指向堆中的对象
- 赋值操作:只是让变量指向新的对象(类似Java的对象引用赋值)
- 使用引用计数进行内存管理
# Pythona=10b=a# b 指向 a 指向的同一个对象b=20# b 现在指向新的对象 20print(a)# 10(a 仍然指向 10)# 但注意:对于可变对象list1=[1,2,3]list2=list1# list2 指向 list1 指向的同一个列表对象list2.append(4)print(list1)# [1, 2, 3, 4](list1 也被修改了!)1.5 可变对象 vs 不可变对象
1.5.1 与Java对比
| 类型 | Java | Python |
|---|---|---|
| 不可变 | String, Integer, Double(包装类) | int, str, tuple, float, bool |
| 可变 | ArrayList, HashMap, StringBuilder | list, dict, set |
| 特点 | 基本类型值传递,对象引用传递 | 一切皆引用,可变性决定行为 |
1.5.2 可变对象
# 可变对象:创建后可以修改# list, dict, set# 示例1:列表lst=[1,2,3]print(id(lst))# 4389562048lst.append(4)# 原地修改print(id(lst))# 4389562048(相同地址)# 示例2:字典d={"a":1}print(id(d))# 4389562048d["b"]=2# 原地修改print(id(d))# 4389562048(相同地址)# 示例3:集合s={1,2,3}print(id(s))# 4389562048s.add(4)# 原地修改print(id(s))# 4389562048(相同地址)1.5.3 不可变对象
# 不可变对象:创建后不能被修改# int, float, bool, str, tuple, frozenset# 示例1:整数x=10print(id(x))# 140735892123456x+=1# x 指向新的对象 11print(id(x))# 140735892123488(不同地址)# 示例2:字符串s="hello"print(id(s))# 4389562048s+=" world"# 创建新字符串print(id(s))# 4389563088(不同地址)# 示例3:元组t=(1,2,3)# t[0] = 10 # ❌ TypeError: 'tuple' object does not support item assignment1.6 深拷贝与浅拷贝
1.6.1 与Java对比
| 操作 | Java | Python |
|---|---|---|
| 引用赋值 | List b = a; | b = a |
| 浅拷贝 | new ArrayList<>(a) | a[:] 或 a.copy() |
| 深拷贝 | 手动递归或使用序列化 | copy.deepcopy(a) |
1.6.2 深拷贝(Deep Copy)
深拷贝特点:
- 完全独立,不影响原始对象
importcopy original=[1,2,[3,4]]deep=copy.deepcopy(original)deep[0]=100deep[2][0]=300print(original)# [1, 2, [3, 4]]print(deep)# [100, 2, [300, 4]]1.6.3 浅拷贝(Shallow Copy)
浅拷贝特点:
- 创建新对象
- 但只复制最外层,嵌套对象仍然是引用
importcopy# 方式1:切片shallow1=original[:]# 方式2:list()构造函数shallow2=list(original)# 方式3:copy模块shallow3=copy.copy(original)original=[1,2,[3,4]]shallow=original.copy()# 或 original[:]shallow[0]=100# 不影响 originalshallow[2][0]=300# 影响 original!因为嵌套列表是引用print(original)# [1, 2, [300, 4]]print(shallow)# [100, 2, [300, 4]]二、字符串
2.1 字符串的定义方式
# 单引号name='Alice'# 双引号name="Alice"# 三引号(多行字符串)message="""This is a multi-line string."""# 包含引号的字符串description='He said, "Python is awesome!"'description="It's a beautiful day."2.2 字符串常用方法
text=" Hello, Python World! "# 大小写转换print(text.upper())# " HELLO, PYTHON WORLD! "print(text.lower())# " hello, python world! "print(text.title())# " Hello, Python World! "print(text.capitalize())# " hello, python world! "print(text.swapcase())# " hELLO, pYTHON wORLD! "# 去除空白print(text.strip())# "Hello, Python World!"print(text.lstrip())# "Hello, Python World! "print(text.rstrip())# " Hello, Python World!"# 查找与替换print(text.find("Python"))# 9(索引位置)print(text.index("Python"))# 9(索引位置,找不到会报错)print(text.replace("Python","Java"))# " Hello, Java World! "print(text.count("o"))# 3(出现次数)# 分割与连接words=text.split()# ['Hello,', 'Python', 'World!']joined="-".join(words)# "Hello,-Python-World!"# 判断print(text.startswith(" Hello"))# Trueprint(text.endswith("! "))# Trueprint("123".isdigit())# Trueprint("abc".isalpha())# Trueprint("abc123".isalnum())# Trueprint(" ".isspace())# True2.3 f-string格式化
first_name="ada"last_name="lovelace"full_name=f"{first_name}{last_name}"print(f"Hello,{full_name.title()}!")# 输出:Hello, Ada Lovelace!# 格式化数字pi=3.1415926print(f"Pi ={pi:.2f}")# Pi = 3.14print(f"Pi ={pi:.4f}")# Pi = 3.1416# 对齐和填充print(f"{'left':<10}")# 'left 'print(f"{'right':>10}")# ' right'print(f"{'center':^10}")# ' center 'print(f"{'center':*^10}")# '*center***'# 千分位分隔符number=1234567print(f"{number:,}")# 1,234,567旧式格式化方法:
name="Alice"age=25# format()方法print("My name is {} and I am {} years old.".format(name,age))# 位置参数print("My name is {0} and I am {1} years old.".format(name,age))# 关键字参数print("My name is {n} and I am {a} years old.".format(n=name,a=age))# %格式化(最古老)print("My name is %s and I am %d years old."%(name,age))三、数字
3.1 整数
# 整数运算2+3# 53-2# 12*3# 63/2# 1.5(Python 3中/总是返回浮点数)3//2# 1(整除,类似Java的/)3%2# 1(取余)2**3# 8(乘方)10**6# 10000003.2 浮点数
0.1+0.2# 0.30000000000000004(浮点数精度问题)# 处理精度问题fromdecimalimportDecimal,getcontext getcontext().prec=6result=Decimal('0.1')+Decimal('0.2')print(result)# 0.33.3 类型转换
# 字符串转数字age=int("25")price=float("19.99")# 数字转字符串str_age=str(25)str_price=str(19.99)# 浮点数转整数(截断小数)int(3.7)# 3int(-3.7)# -3# 四舍五入round(3.7)# 4round(3.2)# 3round(3.14159,2)# 3.14