一.赋值                                        

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 ... 9
2. 避免「死循环」(新手最易踩的坑)

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.总结

Ⅰ.类的使用流程(核心三步)

  1. 定义类:用class关键字描述「事物的特征(属性)和行为(方法)」;

  2. 实例化:xiaoyan = Person("ligekaoyan", 28) → 创建类的具体对象;

  3. 调用方法 / 访问属性: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的新张量,这个新张量和原张量的关系是:

  1. 数据共享:新张量和原张量指向同一块内存(修改其中一个,另一个也会变);
  2. 梯度隔离:新张量 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)
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐