Python笔记-Python基础知识
本文最后更新于 2025年11月15日 下午
万物皆对象
Python中所有的类型、数据结构、函数、类、模块都在一个个“盒子”里,即“对象”
对变量赋值实质上是创建等号右侧对象的一个引用
a=[1,2,3]
b=a b和a指向同一个对象。可以使用is关键字(或is not)判断两个引用是否指向同一个对象,而**==运算符**只判断两个变量值是否相等。
赋值(assignment)也称绑定(binding)。把一个对象绑定到一个变量名。可以用**isinstance(变量名, 类型)**函数来判断一个变量是否是某个特定类型。
类型只与对象本身有关,而与绑定到其上的变量名无关。因此可以把一个变量名先后绑定到不同的类型上。
Python函数中是按引用传递参数的。在函数中,当对数值、字符串等形参整体赋值时,不影响实参的值(因为创建了新对象);当修改列表、字典等可变对象的部分元素时,会影响实参(因为只修改了原内存块的部分数据);当对列表、元组、字典等数据结构整体赋值时,不会影响实参(因为创建了新对象)
标量类型
- None Python中只有一个实例对象None
- int
- long 非常大的int值会自动转换为long,一般不用程序员考虑
- float 双精度64位浮点数
- str
- bool
可变性
可变对象(mutable):可以改变所包含的对象或值,如列表、字典、NumPy数组、用户自定义类型等
不可变对象(immutable):不可改变所包含的对象或值,如标量类型、字符串、元组(若元组中有可变对象的元素,则元组也会变为可变对象)
可以用hash()函数判断,可哈希就代表是不可变对象
字符串str
字符串是不可变对象
Python内置的字符串方法:


既可以用单引号,也可以用双引号。带有换行符的多行字符串,可以用三重引号(’’’或”””)
不可变:字符串不能改变元素值,只能创建新的字符串
转义符:反斜杠\,作用是使特殊字符转换为字面含义(如\n、\t)。在左边引号前加“r”可以使所有特殊字符转换为字面含义,无需反斜杠。
字符串可以用加号+拼接
字符串格式化:参考C语言
布尔值bool
- True/False,可以用and/or连接
- Python中大多数对象可以表示布尔值,可以用bool(变量)函数来判断所表示的布尔值,如bool([1,2])
时间日期datetime
需要导入datetime包:import datetime
有datetime、date、time三种类型,datetime整合了另外两种,可以用**date()和time()**方法提取date、time对象。
dt=datetime.datetime(2020,10,1,12,31)
mydate=dt.date()
mytime=dt.time()两个datetime对象相减将产生timedelta对象,timedelta对象可以再加到datetime对象上
**strftime(格式字符串)**方法:将datetime格式化为字符串 str=dt.strftime(‘%m%d%Y %H:%M’)
**strptime(str,格式字符串)**函数:将字符串解析为datetime对象 dt=datetime.strptime(‘20191031’, ‘%Y%m%d’)
可以直接用dateutil.parser.parse函数解析字符串,而不用写格式定义。这个函数几乎可以解析任意的人类能够理解的日期表示形式
from dateutil.parser import parse
dt=parse(‘2020-01-03’)
运算符
- 二元运算符:+ - * /(与C不同,结果为小数) //(除法,向下取整,丢弃小数) % (取模)**(乘方) == != < <= > >= is
- 逻辑运算符:not and or
异常捕获
1 | |
选择结构
1 | |
三元表达式:
value=表达式1 if 条件 else 表达式2
循环结构
for循环
- for i in 序列/字典/集合/迭代器:
- 序列包括字符串、列表、元组。序列/字典/集合/迭代器都是可迭代对象。
- 如果序列/集合/迭代器的元素是序列,可以将这些元素拆成多个变量:for a,b,c in iterator:
- range(int)/range(start, end, step)函数:生成一个逐个返回整数的迭代器(前闭后开)
- enumerate(可迭代对象)函数:生成一个逐个返回对象的(index, value)元组的迭代器
迭代器iterator
- 包含许多对象的容器,每请求一次,将返回一个对象
- 任何实现了__iter__()和__next__()方法的对象(或者说类)都是迭代器,__iter__()返回迭代器自身,__next__()返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常。
- 任何可迭代对象可使用iter(可迭代对象)函数返回一个迭代器。iter(iterator)函数返回自身,next(iterator)函数将返回下一个值。
while循环
while 条件:
continue 、break 、pass (代表空操作,用于待开发的代码块)关键字
元组tuple
- 定长、不可变、有序
- 定义方法:tup=4,5,6 或 tup=(4,5,6)
- 元组可以用加号+连接来加长,或乘以整数来连接该元组的多个副本
元组拆包:
tup=4,5,(6,7)
a,b,(c,d)=tup
结果:a=4,b=5,c=6,d=7
交换变量名a,b=b,a就是用了该原理
方法
count(值) :计算指定值出现的次数
a=(1,2,2,2,3,4)
a.count(2)
结果:3
列表的索引、切片也可以用在元组上
列表list
- 变长、可变、有序
- 定义方法:lst=[1,2,3,4]
- in关键字用于判断元素是否在列表/元组/字典/集合中
- 列表可以用加号+连接
- 切片:list[start : stop : step],step为负数表示反序
方法
- append(值) :将元素添加到末尾
- insert(index, 值) :将元素插入指定位置
- pop(index) :删除并返回指定位置的元素,index缺省时移除最后一个
- remove(值) :找到第一个值并删除
- extend(list) :合并列表,或者说添加多个元素到末尾(比直接+效率高)
- sort(key=None, reverse=False) :就地排序(不生成新list)(默认升序)
适用于可迭代对象的函数
sorted(可迭代对象, key=None, reverse=False)函数:返回排序后的列表(一个新的list)
zip(可迭代对象, …)函数:将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的zip对象(如果各个迭代器的元素个数不一致,则返回zip对象的长度与最短的对象相同)。可以用list()转换为列表。
a=[1,2,3]
b=[4,5,6]
list(zip(a,b))
结果:[(1, 4), (2, 5), (3, 6)]
- zip(*zip对象)函数:将zip对象或压缩后的list解压为一个个元组,再压缩
zipped=zip(a,b)
tup1,tup2=zip(*zipped)
结果:tup1=(1,2,3) tup2=(4,5,6)
这里*星号加在可迭代对象前面的作用是把可迭代对象(包括zip对象)拆分成一个个独立的元素,作为参数传入函数。如这里zip(*zipped)相当于zip( (1, 4), (2, 5), (3, 6) ),传入了三个对象。
- reversed(序列/迭代器)函数:返回序列逆序排序后的迭代器
字典dict
- 变长、可变、无序(基于哈希表)
- 定义方法:dict={‘a’:1, ‘b’:3, ‘c’:5} 键(key)必须是不可变对象,值(value)可以是任何类型
- 从序列类型创建字典:dict=dict(zip(key_list, value_list))
- del关键字用于删除值
方法
- pop(key) :删除并返回指定位置的元素
- keys() :返回键的迭代器
- values() :返回值的迭代器
- items() :返回(键,值)的迭代器
- update(dict) :合并两个字典
- get(key, default_value=None) :获取指定位置的值,当key不存在时返回default_value
- setdefault(key, default=None) :如果某个键不存在于字典中,将会添加键并将值设为默认值
函数
defaultdict(类型/函数) 函数
from collections import defaultdict
将所有不存在的键设置为默认值。类型/函数用于生成默认值,如list代表空列表,int代表0,函数可以是只返回默认值的函数如lambda: 4
dict=defaultdict(int)
dict=defaultdict(lambda: 4)
集合set
- 变长、可变、无序、唯一(基于哈希表)
- 定义方法:st=set([1,2,3,4]) 或 {1,2,3,4}
集合运算
- 交:a&b
- 并:a|b
- 差:a-b
- 异或:a^b(=a|b-a&b)
方法
- add(x) :添加元素到集合
- remove(x) :删除元素
- a.issubset(b) :a是b的子集
- a.issuperset(b) :b是a的子集
- a.isdisjoint(b) :a,b没有公共元素(a&b为空集)
列表/字典/集合的推导式
作用:对一组元素进行过滤,并对得到的元素进行相同操作后组成一个列表/字典/集合
列表推导式:
[expression for val in collection if condition ],if condition 可省略
strings=[‘a’, ‘as’, ‘bat’, ‘car’]
newstrs=[a.upper(x) for x in strings if len(x)>2]
结果:newstrs=[‘BAT’, ‘CAR’]
字典推导式:
{key-expr : value-expr for val in collection if condition }
dict={v : i for i, v in enumerate(strings)}
结果:dict={‘a’:0, ‘as’:1, ‘bat’:2, ‘car’:3}
集合推导式:
{expression for val in collection if condition }
嵌套列表推导式:
嵌套for循环
tuples=[(1,2,3), (4,5,6), (7,8,9)]
flat=[x for tuple in tuples for x in tuple ]
结果:flat=[1, 2, 3, 4, 5, 6, 7, 8, 9]
函数
命名空间
- 命名空间就是一个字典dict,记录了当前作用域的变量名和值,分为local namespace、global namespace、built-in namespace(嵌套函数还会有父函数的local namespace)
- 可以用locals()获得当前位置的局部命名空间(字典形式)和globals()获得全局(模块)命名空间
使用import module时,module本身被引入,但是保存它原有的命名空间,所以我们需要使用module.name这种方式访问它的函数和变量。
使用from module import这种方式,是将其它模块的函数或者变量引到当前的命名空间中,所以就不需要使用module.name这种方式访问其它模块的函数了。
作用域
四种作用域
- 局部作用域Local:如函数/方法的内部
- 嵌套作用域Enclosing:嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
- 全局作用域Global:当前模块(py文件)的全局变量
- 内建作用域Built-in:内建的变量/关键字等
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
访问变量(搜索变量)的顺序:L-E-G-B,就是在不同作用域的命名空间搜索变量
访问:内部可以访问外部的变量,但外部不能访问内部的变量。局部变量只能在其被定义的函数内部访问。
修改/赋值:若要在内部作用域修改/赋值外部作用域的变量,需要加上global(全局作用域)或nonlocal(嵌套作用域)关键字来声明。否则不加关键字,直接修改/赋值,将创建一个与外部变量同名的局部变量。
对于一个对象的部分元素的修改也属于访问。如全局变量列表a,在函数中可以直接a[0]=3或a.append(3),不用加global。但是对于序列/字典/集合等的整体赋值属于修改操作,需要global
访问指的是在函数中如print(a)的读取操作,修改/赋值指的是在函数中如a=4的写入操作
参数传递
- Python中一切事物皆对象,变量是对内存中的对象的存储地址的抽象。
- Python参数传递统一使用的是引用传递方式
- 当传递的参数是可变对象的引用时,因为可变对象的值可以修改,因此可以通过修改参数值而修改原对象,这类似于C语言中的引用传递
- 当传递的参数是不可变对象(标量类型、字符串、元组)的引用时,虽然传递的是引用,参数变量和原变量都指向同一内存地址,但是不可变对象无法修改,只能复制一份,所以参数的重新赋值不会影响原对象,这类似于C语言中的值传递
函数返回多个值
返回元组:
def func():
a=5; b=6
return a, b
c, d=func() # 其实是返回了一个元组
返回字典:
def func():
a=5; b=6
return {‘a’:a, ‘b’:b}
dict=func()
函数亦为对象
函数名可作为列表元素、其他函数的参数等
匿名函数lambda
lambda 参数 : 表达式
strs=[‘foo’, ‘card’, ‘aaaa’]
strs.sort(key=lambda x:len(set(list(x)))) # 根据各字符串中不同字母的数量排序
结果:strs=[‘aaaa’, ‘foo’, ‘card’]
闭包closure:返回函数的函数
闭包是由其他函数动态生成并返回的函数。被返回的函数可以访问其创建者的局部命名空间中的变量,即使创建者已经执行完毕。
1 | |
可变长度参数
元组def func(*t):接受多个参数并放在一个元组中
字典def func(**t):关键字和参数被放在一个字典中
def func(x, y=30, *z1, **z2)
func(1,20,2,3,4,5,k1=10,k2=30)
结果:x=1 y=20 z1=(2,3,4,5) z2={‘k1’:10, ‘k2’:30}
装饰器
用来包装函数的函数,用于实现函数代码的复用
def deco(func):
def new_func(x, y):
print(‘原始数据:’, x, y)
return func(x, y)
return new_func
@deco
def sum(x, y):
return x+y
相当于
def sum(x, y):
print(‘原始数据:’, x, y)
return x+y
柯里化currying
部分参数应用,从现有函数派生出参数更少的新函数
def add_nums(x, y):
return x+y
add_five=lambda y : add_nums(5,y)
或from functools import partial
add_five=partial(add_nums, 5)
生成器generator
一种特殊的迭代器。将函数定义中的return换为yield,调用这个函数将返回一个生成器对象。当显式(直接调用next(gen)函数或gen.__next__()方法)或隐式(放在for循环中迭代)调用next()时,运行至yield,并返回一个值,暂停运行,直到下一个值被请求,继续运行。因此生成器中一般都有循环。
1 | |
以延迟的方式返回一个值序列,作用:如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
send()方法和__next__()一样,都能让生成器继续往下走一步(遇到yield停),但send()能传一个值,这个值作为上一个yield表达式值
生成器表达式:gen=( x**2 for x in range(10) )
面向对象编程
基本概念
- 类(class)为属于该类的全部对象提供了统一的抽象描述。任何对象都是某个类的实例。
- 任何对象(object)都是由属性(property)和方法(method)组成的。各个对象之间通过消息(message)相互联系、相互作用。发消息实际就是调用对象的成员函数。
- 封装(encapsulation)是指对象的数据(属性)和操作数据的过程(方法)结合在一起,形成独立单元,对外界隐蔽内部信息,只能通过类提供的外部接口访问,保证了数据的安全性。类是数据封装的工具,对象是封装的实现。
- 当定义完一个类后,就产生了一个类对象(直接用大写字母开头的类名表示。注意与实例对象不同)。类对象支持两种操作:引用和实例化。引用操作是通过类对象去调用类中的类属性和类方法;实例化是产生出一个类的实例,成为实例对象。
访问控制
如果在属性名前面加2个下划线“_ _”,则表示该属性是私有的,不能在类外通过对象名访问,否则为公有的。方法也可以同样的方式定义公有/私有。
类的概念

代码实例
1 | |
继承
- 形式:class 子类名(父类名):
- 如果父类和子类都定义了构造方法,在进行子类实例化时,子类的构造方法不会自动调用父类的构造方法,必须在子类中显式调用
- 如果要在子类中调用父类的方法,需要以“父类名.方法”的方式调用,并传递self参数
- 子类不继承父类的私有的属性/方法,在子类中无法通过父类名来访问
- 多重继承
多态
- 指不同对象收到同一种消息时产生不同的行为,即调用同名的方法时,根据对象的类型执行不同的函数。如内置函数len()
- 类似于C++中的重写