python语法学习
一.赋值
a=3 #整型赋值
a=3.0 #浮点型赋值
Python语言完全不需要像 C/C++/Java 那样显式声明变量的数据类型(比如 int、char、float 等),Python 是动态类型语言,赋值时无需声明int/char等数据类型,解释器会自动推导变量类型。
# Python 示例
age = 25 # 自动识别为int(整数)
gender = 'M' # 自动识别为str(字符串,Python没有单独的char类型,单/双引号都是字符串)
height = 1.75 # 自动识别为float(浮点数)
注意:python中没有char类型,单个字符也会被识别为
str(字符串)类型
Python的同一个变量可以在运行中被赋值为不同类型,解释器会实时更新类型:
x = 10 # 此时x是int类型
x = "hello" # 无需任何声明,x直接变成str类型
x = [1,2,3] # 再变成list类型
二.打印
a=3 #整形赋值
a=3.0 #浮点型赋值
print(a)
print("a")
该段代码的输出如下:

在 Python 的打印操作(print() 函数)中,括号内加不加双引号("",单引号 '' 同理)有本质区别,核心是区分「字符串字面量」和「Python 可识别的对象 / 表达式」。
1. 加引号:打印「字符串本身」
当内容被 "" 或 '' 包裹时,Python 会把它识别为字符串字面量,print() 会原封不动地打印引号内的内容(不会打印引号本身)。简单说:你写在引号里的是什么,输出就是什么。
2. 不加引号:打印「对象 / 表达式的结果」
当内容没有被引号包裹时,Python 会把它当作变量、数字、表达式、关键字等可执行的对象来处理,print() 会打印这个对象的「实际值 / 计算结果」,而不是字面内容。
a=3
b=4
print(a,b) #一次打印多个变量
a,b=b,a #变量值的交换
print(a,b)
Python语言无论是一次打印多个结果或者交换变量的值都十分方便
三.字符串
name="ligekaoyan" #字符串
print(name) #打印字符串
print(name[2]) #打印字符串中指定位置
该段代码执行结果如下:

现来逐步解释:
name="ligekaoyan"——————定义字符串变量name,赋值为"ligekaoyan"
print(name)——————————输出整个字符串
print(name[2])——————————输出字符串中索引为2的字符即g
补充实用知识点:
1.反向索引:Python 支持从末尾倒数(用负数索引)
print(name[-1]) # 输出最后一个字符n
print(name[-3]) # 输出倒数第三个字符y
2.切片取值:如果想取一段字符,可用[起始索引:结束索引](左闭右开,结束索引取不到)
print(name[0:5]) # 输出前5个字符:ligek
print(name[5:]) # 从索引5开始取到末尾:aoyan
print(name[:5]) # 输出前5个字符:ligek
注意索引的省略写法:
print(name[5:])————省略了结束索引,表示从索引5开始取到末尾:aoyan
print(name[:5])————省略了起始索引,表示从开头取到索引5结束:ligek
3.不可修改性:字符串是「不可变对象」,不能直接修改某个索引的字符
name[2] = 'G'
这行代码会报错!如果要修改,需要重新构造字符串(比如切片拼接):
name = name[:2] + 'G' + name[3:]
print(name) # 输出:liGekaoyan
四.列表
list1=[1, 2, 3, 4, 5] #定义列表
定义列表变量list1,赋值为[1,2,3,4,5]
print(list1) #打印列表
print(list1[2]) #打印列表中指定位置
print(list1[-1]) #打印列表中最后一个
print(list1[-2]) #打印列表中倒数第二个
for i in list1[1:4]:
print(i) #打印列表中索引1-3
列表 list 的索引规则和字符串完全一致,都支持正向和反向索引。但是列表是可变对象(和字符串不同):可以直接修改指定索引的元素
list1[2] = 30 # 把索引2的元素从3改成30
print(list1) # 输出:[1, 2, 30, 4, 5]
list3=[1,2,3,4,5,6]
list3.remove(3) #删除数值为3的值,而不是删除list[3],即不是按下标删除的.输出结果为[1,2,4,5,6]
del list3[3] #按下标删除list[3].输出结果为[1,2,4,6]
list3.append(7) #结尾插入数值7.输出结果为[1,2,4,6,7]
list3.extend([8,9,10]) #结尾插入新的列表[8,9,10].输出结果为[1,2,4,6,7,8,9,10]
list3.insert(0,0) #在下标为0的位置插入元素0.输出结果为[0,1,2,4,6,7,8,9,10]
Python 列表和其他语言的数组不同,元素可以是任意数据类型,甚至可以嵌套其他复杂对象(比如字典、列表、函数等):
dict2={"name":"ligekaoyan","age":28,20:80} #字典
list2=[1,'art',dict2] #列表
print(list2)
# 输出结果:[1, 'art', {'name': 'ligekaoyan', 'age': 28, 20: 80}]
list2 = [1,'art',dict2] 中:
-
第 0 个元素:整数
1 -
第 1 个元素:字符串‘
art' -
第 2 个元素:字典
dict2
那么如何访问嵌套列表中的字典元素呢?可以这样写:
# 先取list2的第2个元素(字典),再取字典的"name"键对应的值
print(list2[2]["name"]) # 输出:ligekaoyan
# 取字典中键20对应的值
print(list2[2][20]) # 输出:80
列表的循环后置
list4=[i for i in range(10)]# print(list4) # #等效于 list4=[] for i in range(10): list4.append(i) print(list4)
五.字典(哈希表)
# 定义字典dict1,键可以是字符串(name/age)或数字(20),值可以是任意类型
dict {key1:value1,key2:value2}
key可以是字符串(name/age)或数字(20),值可以是任意类型
dictionary #字典
dict1={"name":"ligekaoyan","age":28,20:80}
print(dict1["name"]) #打印关键字对应的value
print(dict1["age"])
print(dict1[20])
print(dict1["name"],dict1["age"],dict1[20])
print(dict1["name"])————通过键"name"获取对应的值并打印
print(dict1["age"]) ————通过键age获取对应的值并打印
print(dict1[20])————通过键20获取对应的值并打印
print(dict1["name"],dict1["age"],dict1[20])————同时打印多个键对应的值,用逗号分隔会自动用空格隔开输出
补充实用知识点
1.字典的可变性:字典是可变对象,可以直接修改 / 新增 / 删除键值对:
# 修改已有key的值
dict1["age"] = 29
print(dict1["age"]) # 输出:29
# 新增键值对
dict1["gender"] = "male"
print(dict1["gender"]) # 输出:male
# 删除键值对
del dict1[20]
print(dict1) # 输出:{'name': 'ligekaoyan', 'age': 29, 'gender': 'male'}
2.避免 key 不存在的报错:用get()方法更安全。如果访问不存在的 key(比如dict1["score"]),会直接报错;而get()方法可以指定默认值,更健壮
# 存在的key,返回对应值
print(dict1.get("name")) # 输出:ligekaoyan
# 不存在的key,返回指定默认值(这里是0)
print(dict1.get("score", 0)) # 输出:0
# 不存在的key且不指定默认值,返回None(不会报错)
print(dict1.get("score")) # 输出:None
3.获取所有 key/value
# 获取所有键
print(dict1.keys()) # 输出:dict_keys(['name', 'age', 20])
# 获取所有值
print(dict1.values()) # 输出:dict_values(['ligekaoyan', 28, 80])
六.判断语句
a=4
if a==3: #符合条件
print("正确的")
else:
print('错误的')
加入嵌套:
a=3
b=4
c=5
if b>a:
if b<c:
print("a<b<c")
else:
print("b>=c")
else:
print("b<=a")
注意缩进规则:前面4个空格,表示它属于上文
七.空值
A=None
None是 Python 中唯一的空值对象,它既不是空字符串""、数字0,也不是空列表[]/ 空字典{},而是一个专门表示「无」「空」「不存在」的特殊值。Python 官方更推荐用is关键字判断 None(因为is判断的是「对象是否是同一个」,而 None 是单例对象,效率更高、语义更准确。
A = None
# 更规范的写法
if A is None:
print('A是空的')
八.循环
1.for循环:for i in 范围
list1=[1, 2, 3, 4, 5]
for i in list1:
print(i)
遍历列表,并依次打印列表中的每个元素,其执行结果如下:

for i in list1[1:4]:
print(i)
for i in range(10): #[0,10) 左闭右开
print(i)
for i in range(1,10):#[1,10)
print(i)
遍历范围内的整数:
range(10):从0开始,到10结束但不包含10
range(1:10):从1开始,到10结束但不包含10
for i in range(1,10,2):#1是开头,10是结尾,2是步长
print(i)
range(1,10,2):从1开始,步长为2,到10结束但不包含10
dict1={"name":"ligekaoyan","age":28,20:80}
for each in dict1:
print(each) #遍历字典,打印字典的所有key值
遍历字典时each默认取key,打印所有key:name、age、20。若想打印所有的key对应的value值,可用以下代码:
for each in dict1:
print(dict1[each]) #遍历字典,打印字典的所有value值
遍历字典,打印字典的所有value值。
1.
range的核心规则(新手必记)
range(start, end, step)始终是左闭右开(包含 start,不包含 end):
range(10)→ 等价于range(0,10,1)(start 默认 0,step 默认 1);range(1,10)→ 取 1~9(不包含 10);range(1,10,2)→ 从 1 开始,每次 + 2,直到接近但不超过 10(最后一个是 9)。2. 字典遍历的优化写法(新手进阶)
通过
for each in dict1取 key、再dict1[each]取 value 的写法是对的,但 Python 提供了更直观的方式:# 直接遍历key和value(推荐) for key, value in dict1.items(): print('key:',key,'value:',value)) # 输出: # 键:name,值:ligekaoyan # 键:age,值:28 # 键:20,值:80 # 只遍历value(简化写法) for value in dict1.values(): print(value) # 效果和你写的一样,更直观
2.while循环
i=0
while i<10:
i+=1
print(i)
while 循环的核心特点:先判断条件,再执行循环体
上述代码运行后会依次输出 1 到 10。
1. 循环变量的顺序影响结果
如果把
i += 1放到print(i)之后,输出结果会不同(打印 0 到 9):i = 0 while i < 10: print(i) # 先打印,再自增 i += 1 # 输出:0 1 2 ... 92. 避免「死循环」(新手最易踩的坑)
while 循环必须保证「循环变量会逐步满足终止条件」,否则会无限执行(死循环):
# 错误示例:死循环(i永远等于0,i<10永远成立) i = 0 while i < 10: print(i) # 没有i += 1,循环永远不会终止避坑技巧:while 循环中必须有修改循环变量的语句(比如
i += 1),确保条件最终会变为 False。3. while 循环的终止方式
除了「条件不成立」,还可以用
break主动终止循环:i = 0 while i < 10: i += 1 if i == 5: break # 当i=5时,强制终止循环 print(i) # 输出:1 2 3 4(循环在i=5时提前结束)最终输出:1 2 3 4(循环在i=5时提前结束)
4. 跳过当前循环:continue
如果想跳过某次循环的后续代码,用
continue:(配合判断语句使用)i = 0 while i < 10: i += 1 if i % 2 == 0: # 只要i是偶数,就跳过打印 continue print(i) # 输出:1 3 5 7 9(只打印奇数)最终输出:1 3 5 7 9(只打印奇数)
九.类
1.定义类
class Person(): #别忘加:
def __init__(self,name,age):#初始化
self.name=name
self.age=age
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
class Person():
定义Person类(类名首字母大写是Python的命名规范,更易读),括号可省略,写成class Person: 也可以.
def __init__(self, name, age):
初始化方法(构造方法):创建实例时自动执行,用于初始化属性.
self.name = name
self.age = age
给实例绑定属性:将传入的 name 参数绑定为当前实例的 name 属性(self 是实例本身的引用);
将传入的 age 参数绑定为当前实例的 age 属性(self 是实例本身的引用)
def print_name(self):
print(self.name)
定义实例方法:打印name(实例方法:必须带self参数(代表实例),用于实现类的功能)
def print_age(self):
print(self.age)
定义实例方法:打印age(实例方法:必须带self参数(代表实例),用于实现类的功能)
2.实例化类(创建对象)
xiaoyan=Person('yyp',23)#实例化
xiaoyan.print_name()
xiaoyan.print_age()
xiaoyan=person('yyp',23)
创建Person类的实例xiaoyan,传入name和age参数
xiaoyan.print_name()
调用实例方法,打印姓名
xiaoyan.print_age()
调用实例方法,打印年龄
print("直接访问属性:", xiaoyan.name, xiaoyan.age)
也可以直接访问实例的属性(不通过方法)
最关键的
self(新手必懂)
self不是关键字,但是 Python 的约定俗成:代表当前创建的实例对象;定义实例方法时,第一个参数必须是
self(名字可以改,但绝对不推荐);调用方法时,不需要手动传
self参数,Python 会自动把实例传进去。比如:xiaoyan
.print_name()等价于Person.print_name(xiaoyan)(Python 自动帮你补了xiaoyan这个参数)。
3.总结
Ⅰ.类的使用流程(核心三步)
-
定义类:用
class关键字描述「事物的特征(属性)和行为(方法)」; -
实例化:xiaoyan
= Person("ligekaoyan", 28)→ 创建类的具体对象; -
调用方法 / 访问属性:xiaoyan
.print_name()(方法)或 xiaoyan.name(属性)。
Ⅱ.给属性设置默认值
如果某些属性有默认值,可在__init__中直接赋值:
class Person():
def __init__(self, name, age, gender="male"): # gender默认值为male
self.name = name
self.age = age
self.gender = gender
# 创建实例时,可省略gender参数
p2 = Person("zhangsan", 30)
print(p2.gender) # 输出:male
# 也可以覆盖默认值
p3 = Person("lisi", 25, "female")
print(p3.gender) # 输出:female
Ⅲ.方法中调用其他方法
实例方法内部可以通过self调用其他方法或属性:
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
# 新增方法:打印所有信息(调用其他方法)
def print_all(self):
self.print_name() # 调用自身的print_name方法
self.print_age() # 调用自身的print_age方法
p1 = Person("ligekaoyan", 28)
p1.print_all() # 输出:ligekaoyan 28
4.类的继承
Python 中具有「子类继承父类」的逻辑 ——子类继承父类的属性和方法,还可以扩展自己的专属属性和方法
# 父类:person
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
# 子类:Superman(继承自person)
class Superman(Person):
def __init__(self, name, age):
# 调用父类的初始化方法,继承name和age属性
super(Superman, self).__init__(name, age)
# 子类扩展的专属属性:fly
self.fly = True
# 子类扩展的专属方法:fly_
def fly_(self):
if self.fly == True:
print('I can fly')
# 实例化子类superman
lige = superman('lige', 28)
# 调用从父类继承的方法
lige.print_name()
# 访问从父类继承的属性
print(lige.name)
# 调用子类自己的方法
lige.fly_()
1.首先补充父类person的定义,让代码能独立运行;
2.继承的核心语法class superman(person):
表示superman是子类,继承person父类的所有属性和方法(比如print_name()方法、name属性)。
3.def __init__(self, name, age):
调用父类的初始化方法,继承name和age属性
4.super(superman, self).__init__(name, age)
self.fly = True:
子类扩展的专属属性:fly
5.def fly_(self):
if self.fly == True:
print('I can fly'):
子类扩展的专属方法:fly_
6.lige = superman('lige', 28)
实例化子类superman
7.lige.print_name()
调用从父类继承的方法
8.print(lige.name)
访问从父类继承的属性
9.lige.fly_()
调用子类自己的方法
核心逻辑解释:
1. 继承的核心语法
class superman(person):→ 表示superman是子类,继承person父类的所有属性和方法(比如print_name()、name属性)。2.
super()的关键作用
super(superman, self).__init__(name, age)→ 调用父类person的__init__方法,让子类实例也能拥有name和age属性(相当于「复用父类的初始化逻辑」)。
- 简化写法(Python 3 推荐):
super().__init__(name, age)(无需写子类名和 self,解释器会自动识别)。3. 子类的扩展特性
- 新增属性:
self.fly = True→ 只有superman实例有这个属性,父类person没有;- 新增方法:
fly_()→ 只有superman实例能调用这个方法,父类person不能。
补充实用知识点(新手进阶)
1. 子类重写父类方法
如果子类想修改父类的方法,直接定义同名方法即可(「重写 / 覆盖」):
class superman(person): def __init__(self, name, age): super().__init__(name, age) self.fly = True # 重写父类的print_name方法 def print_name(self): print(f"超人的名字是:{self.name}") lige = superman('lige', 28) lige.print_name() # 输出:超人的名字是:lige(不再执行父类的print_name)2. 子类调用父类被重写的方法
如果重写后还想调用父类的方法,可以用
super():class superman(person): def __init__(self, name, age): super().__init__(name, age) self.fly = True def print_name(self): # 先调用父类的print_name super().print_name() # 再执行子类自己的逻辑 print("(我是超人!)") lige = superman('lige', 28) lige.print_name() # 输出: # lige # (我是超人!)
十.函数
1.常见算数运算
#加,减,乘,除,乘方
a=3
b=2
print(a+b)
print(a-b)
print(a*b)
print(a/b)
print(a//b)#地板除,向下取整
print(a**b)#乘方
print(a%b)#取模运算,求余数
除法
/的特性(新手易混淆)Python 中
/的结果永远是浮点数,哪怕能整除.如果想得到整数结果,可结合int()转换(但仅适用于正数整除场景):print(int(4 / 2)) # 输出:2
2.定义一个函数
Python 函数的核心结构 ——「定义函数→传入参数→执行逻辑→返回结果」
# 定义函数:接收参数A,返回A的平方
def myfun(A): # 函数名+参数列表,末尾必须加冒号
c = A ** 2 # 计算A的平方,赋值给临时变量c
return c # 返回计算结果
# 定义变量a并赋值为3
a = 3
# 调用函数myfun,传入参数a,打印返回值
print(myfun(a))
def myfun(A):定义名为myfun的函数,A是「形参」(形式参数,函数定义时的占位符)
return c:将计算结果 c 返回(函数执行到 return 会立即结束,后续代码不执行)
a = 3:定义「实参」(实际参数,调用函数时传入的具体值)
print(myfun(a)):调用函数,将实参 a(值为 3)传给形参 A,接收返回值并打印
如何实现有参数用参数,无参数用默认值的需求呢?可以在定义函数时给形参设置一个默认值
#如果传入B,就返回A的B次方;如果没有传入B,就返回A的平方
def myfun3(A,B=2):#注意:带=的数据必须放在不带=数据的后面
return A**B
a=2
b=3
print(myfun3(a))
print(myfun3(a,b))
注意:默认参数必须放在普通参数后面
print(myfun3(a)):
只传A,使用B的默认值2 → 2²=4
print(myfun3(a, b)):
传A和B,b的实参值覆盖默认值 → 2³=8
默认参数的「坑」:不要用可变对象当默认值
如果默认参数是列表、字典等可变对象,会导致多次调用函数时共享同一个对象,出现意外结果:
# 错误示例:默认参数用空列表 def add_item(item, lst=[]): lst.append(item) return lst print(add_item(1)) # [1](第一次调用正常) print(add_item(2)) # [1,2](第二次调用不是[2],而是追加到同一个列表)正确写法:用
None作为默认值,在函数内部初始化可变对象:def add_item(item, lst=None): if lst is None: lst = [] # 每次调用都创建新列表 lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [2]
十一.矩阵
1.定义矩阵
# 导入NumPy并简写为np(行业通用写法)
import numpy as np
导入numpy并简写为np(行业通用写法)
list1 = [
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15]
]
定义一个二维列表用来模拟矩阵(但实际上列表只是一维的)
# 1. 列表转NumPy矩阵(数组)
array = np.array(list1)
定义矩阵变量array,并对其进行赋值(将列表list1转numpy矩阵(数组))
2.切矩阵
numpy 矩阵切片格式:array[行切片, 列切片],索引从 0 开始,遵循「左闭右开」规则
Ⅰ.索引切片
import numpy #import
import numpy as np #引用,导入
list1=[
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15]
]
array=np.array(list1) #array 矩阵 把list1转化为矩阵
print(array)
print(array[1:3,3:5])# 先行后列:横轴从1~2 竖轴从3~4
按索引切片,取出从1-2行,3-4列的矩阵(序列从0开始),取出结果为

切片的「步长」用法(跳行 / 跳列切):
# 取所有行,列从0到5,步长2(取第0、2、4列) print(array[:, 0:5:2]) # 输出: # [[ 1 3 5] # [ 6 8 10] # [11 13 15]]取所有行,列从0到5,步长2(取第0、2、4列)
Ⅱ.全切片
print(array[:,:])
全切片,取出该矩阵
Ⅲ.跳切片
#跳着切 切第1列和第3列
# idx=[1,3]
# print(array[:,idx])
跳切片,取第1列和第3列(索引从0开始).显然,跳切片需要借助列表来实现.
3.矩阵合并
#矩阵合并
array2=array
array3=np.concatenate((array,array2)) #concatenate 串联(默认向下串联)注意:array和array2要加()括起来
array3=np.concatenate((array,array2),axis=1)#axis 轴 默认axis=0表示向下串联;axis=1,表示向右串联
np.concatenate ()是矩阵合并的核心方法,重点注意维度匹配
Ⅰ.向下合并
array2 = array
array3 = np.concatenate((array, array2), axis=0)
print("向下合并:\n", array3)
向下合并(axis=0,默认):要求列数相同
运行结果为:

Ⅱ.向右合并
array4 = np.concatenate((array, array2), axis=1)
print("向右合并:\n", array4)
向右合并(axis=1):要求行数相同
运行结果为:

十二.张量
1.引入张量
import numpy as np
import torch#引入张量
2.创建张量
Ⅰ.利用已知已知二维列表创建张量
torch.tensor(列表) 是将 Python 列表转换为 PyTorch 张量的基础方法,语法简单且常用.同时张量默认类型为int64(整数)
list1=[
[1,2,3,4,5],#别忘加,
[6,7,8,9,10],
[11,12,13,14,15]
]
tensor1=torch.tensor(list1)#张量可以求梯度
print(tensor1)
其执行结果如下:(第1个结果为二维列表输出形式,第二个结果为相应矩阵输出形式,第3个结果为张量输出形式)

Ⅱ.统一化创建张量
tensor1=torch.ones((100,4))#创建100行,4列全为1的张量
print(tensor1)
tensor2=torch.zeros((10,4))#创建10行,4列全为0的张量
print(tensor2)
tensor3=torch.normal(0,1,(10,4))#创建10行4列,取值为自然数(平均数为0,标准差为1)的张量
print(tensor3)
tensor1=torch.ones((100,4)):
创建100行4列、元素全为1的张量(默认类型:float32)
tensor2=torch.zeros((10,4)):
创建10行4列、元素全为0的张量(默认类型:float32)
tensor3=torch.normal(0,1,(10,4)):
创建10行4列、服从正态分布的张量(均值0,标准差0.01)
自定义张量数据类型
默认创建的张量是
float32(浮点型),可通过dtype参数指定类型:tensor_int = torch.ones((2,2), dtype=torch.int64) print(tensor_int.dtype) # 输出:torch.int64 print(tensor_int) # 输出:tensor([[1, 1], [1, 1]])
3.张量梯度计算
Ⅰ.张量的梯度计算
梯度计算的关键前提:只有requires_grad=True的张量,才能计算梯度.
x=torch.tensor(3.0)
x.requires_grad_(True)#需要对x求导进行声明
y=x**2
y.backward()#y对其参数x求导
print(x.grad)
x=torch.tensor(3.0)
x.requires_grad_(True)可以等效成
x=torch.tensor(3.0,requires_grad=True)
y.backward():
计算张量 y 对「所有参与计算且开启梯度追踪(requires_grad=True)的上游张量」的导数,并将结果存储到对应张量的 .grad 属性中。它是 PyTorch 中反向传播求梯度的核心方法
Ⅱ.张量的梯度累加:
x=torch.tensor(3.0)
x=torch.tensor(3.0,requires_grad=True)
y=x**2
y.backward()#y对其参数x求导
print(x.grad)
y1=x**2
y1.backward()#y1对其参数x求导
print(x.grad)#在 PyTorch 中,默认情况下张量会记录自身的计算路径(即「计算图」),用于反向传播求梯度。张量相加:6+6=12
PyTorch 中grad不会自动清零,多次反向传播(backward())会累加梯度:
- 第一次
y=x²,导数dy/dx=2x=6→x.grad=6; - 第二次
y1=x²,导数仍为 6 → 累加后x.grad=12; - ✅ 清零梯度的正确写法(实战必备):
x.grad.zero_()(反向传播前清零).即如下所示:
x=torch.tensor(3.0)
x=torch.tensor(3.0,requires_grad=True)
y=x**2
y.backward()#y对其参数x求导
print(x.grad)
y1=x**2
x.grad.zero_() #梯度清零
y1.backward()#y1对其参数x求导
print(x.grad)
x=x.detach()
detach () 作用:生成一个requires_grad=False的新张量,这个新张量和原张量的关系是:
- 数据共享:新张量和原张量指向同一块内存(修改其中一个,另一个也会变);
- 梯度隔离:新张量
requires_grad=False,完全脱离计算图,后续对它的所有操作都不会被记录,也不会影响原计算图的梯度传播。
简单说:detach() 是「切断梯度流」,但不切断「数据流」。
举例如下:
import torch
# 1. 基础场景:未使用detach()
x = torch.tensor(3.0, requires_grad=True)
y = x ** 2
z = y * 2
z.backward()
print("未detach时x的梯度:", x.grad) # 输出:tensor(12.)(dz/dx = 2*2x = 12)
# 2. 使用detach():切断梯度流
x = torch.tensor(3.0, requires_grad=True)
x_detach = x.detach() # 生成脱离计算图的新张量
y = x_detach ** 2 # 对detach后的张量操作
y.backward() # 报错!因为x_detach无梯度追踪,y也没有计算图
报错原因说明:
y = x_detach **2 时,因为 x_detach.requires_grad=False,所以 y 也没有计算图,调用 y.backward() 会触发:RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
Ⅲ.张量的求和
tensor1=torch.ones((10,4))
print(tensor1)
sum1=torch.sum(tensor1,dim=0)#dim=0,竖着加;dim=1,横着加;不写dim,全加
print(sum1)
输出结果为:

sum2=torch.sum(tensor1,dim=1,keepdim=True)#dim=0,行求和;dim=1,列求和;不写dim,全加
print(sum2)
输出结果为:

其中:keepdim=True表示求和后依然保留维度,否则会出现以下情况
sum3=torch.sum(tensor1)#dim=0,竖着加;dim=1,横着加;不写dim,全加
print(sum3)
输出结果为:
![]()
Ⅳ.张量的形状查看
print(tensor1.shape)#打印tensor的形状:10行4列
tensor1.shape:返回torch.Size([10,4]),表示 10 行 4 列(PyTorch 中「行 = 第一维度,列 = 第二维度」);- 等价写法:
tensor1.size()(效果完全一样,shape是更直观的写法)。
十三.模块导入
from my_tensor import tensor1#会先将my_tensor里的所有代码运行一遍
表示从文件my_tensor中导入变量tensor1,同时会先将my_tensor里的所有代码运行一遍
导入语法的两种常见形式(对比理解)
| 语法形式 | 作用 | 优缺点 |
|---|---|---|
from A import B | 只导入 A 模块中的 B(变量 / 类 / 函数) | 简洁,直接用 B 即可;但如果多个模块有同名 B 会冲突 |
import A | 导入整个 A 模块 | 避免命名冲突;使用时需写A.B(如my_tensor.tensor1) |
更多推荐

所有评论(0)