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
2
3
4
5
6
7
8
try:
# 代码
except 缺省/ValueError等/(ValueError, TypeError):
# 捕获异常后执行的操作
else:
# try块执行成功后的操作
finally:
# 不管try块是否执行成功,都要进行的操作

选择结构

1
2
3
4
5
6
if   条件:
# 代码
elif 条件:
# 代码
else:
# 代码

三元表达式:

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)(默认升序)

适用于可迭代对象的函数

  1. sorted(可迭代对象, key=None, reverse=False)函数:返回排序后的列表(一个新的list)

  2. zip(可迭代对象, …)函数:将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的zip对象(如果各个迭代器的元素个数不一致,则返回zip对象的长度与最短的对象相同)。可以用list()转换为列表。

a=[1,2,3]
b=[4,5,6]
list(zip(a,b))
结果:[(1, 4), (2, 5), (3, 6)]

  1. 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) ),传入了三个对象。

  1. 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def  make_closure(a):
def closure():
print('hello %d' % a)
return closure

clo1=make_closure(5)
# 这里clo1是一个动态生成的函数,其定义相当于:
# def clo1():
# print('hello %d' % 5)
clo1()

clo2=make_closure(6)
clo2()
结果:hello 5
hello 6

可变长度参数

元组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
2
3
4
5
6
7
8
9
10
11
def square(n=10):
print('generating squares from 1 to %d' % (n**2))
for i in range(1,n+1):
temp = yield i**2
print(temp)
gen=square()
print(gen.__next__())
print(gen.__next__())
print(gen.send('tep'))
结果:generating squares from 1 to 100
1 None 4 tep 9

以延迟的方式返回一个值序列,作用:如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。

send()方法和__next__()一样,都能让生成器继续往下走一步(遇到yield停),但send()能传一个值,这个值作为上一个yield表达式值

生成器表达式:gen=( x**2 for x in range(10) )

面向对象编程

基本概念

  • 类(class)为属于该类的全部对象提供了统一的抽象描述。任何对象都是某个类的实例
  • 任何对象(object)都是由属性(property)方法(method)组成的。各个对象之间通过消息(message)相互联系、相互作用。发消息实际就是调用对象的成员函数。
  • 封装(encapsulation)是指对象的数据(属性)和操作数据的过程(方法)结合在一起,形成独立单元,对外界隐蔽内部信息,只能通过类提供的外部接口访问,保证了数据的安全性。类是数据封装的工具,对象是封装的实现。
  • 当定义完一个类后,就产生了一个类对象(直接用大写字母开头的类名表示。注意与实例对象不同)。类对象支持两种操作:引用和实例化。引用操作是通过类对象去调用类中的类属性和类方法;实例化是产生出一个类的实例,成为实例对象。

访问控制

如果在属性名前面加2个下划线“_ _”,则表示该属性是私有的,不能在类外通过对象名访问,否则为公有的。方法也可以同样的方式定义公有/私有。

类的概念

代码实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Person:
place='Beijing' # 公有的类属性
__age=18 # 私有的类属性

# 构造方法
def __init__(self, name, sex, phone='12345'):
self.name=name
self.sex=sex # 公有的实例属性
self.__phone=phone # 私有的实例属性

def __del__(self): # 析构方法
print('Deleting Person object..')

@classmethod
def setPlace(cls, place): # 类方法
cls.place=place

def getPlace(self): # 实例方法
return self.place

@staticmethod
def getAge(): # 静态方法
return Person.__age

p=Person('Mike', 'male')
print(p.place) # 通过实例对象访问类属性,不推荐
print(Person.place) # 通过类对象访问类属性
#print(Person.__age) # 错误,私有属性不能在类外访问
Person.id='210015' # 在类外通过类名增加类属性

print(p.sex) # 通过实例对象访问实例属性
p.num=8210 # 在类外通过实例对象增加实例属性

p.setPlace('Shanghai') # 通过实例对象调用实例方法
Person.setPlace('Shanghai') # 通过类对象调用类方法
print(p.getPlace()) # 通过实例对象调用类方法
print(Person.getAge) # 通过类对象调用静态方法

继承

  • 形式:class 子类名(父类名):
  • 如果父类和子类都定义了构造方法,在进行子类实例化时,子类的构造方法不会自动调用父类的构造方法,必须在子类中显式调用
  • 如果要在子类中调用父类的方法,需要以“父类名.方法”的方式调用,并传递self参数
  • 子类不继承父类的私有的属性/方法,在子类中无法通过父类名来访问
  • 多重继承

多态

  • 指不同对象收到同一种消息时产生不同的行为,即调用同名的方法时,根据对象的类型执行不同的函数。如内置函数len()
  • 类似于C++中的重写

Python笔记-Python基础知识
https://leo.zz.ac/posts/3d8c.html
作者
AquariusLeo
发布于
2025年11月15日
更新于
2025年11月15日
许可协议