python边学边写
divmod()函数同时得到商和余数。例:divmod(13,3)
round()函数可以返回四舍五入的值 例:round(4.5) 5
time.time()函数可以获得1970年到当前时刻,返回值以秒为单位,但是要导入time,import time
len()用于计算字符串含有多少字符
str()将其他 数据类型转换为字符串
import random
random.shuffle(a)打乱顺序
help(函数名.__doc__)
海龟绘图——坐标系问题——画笔各种方法
import turtle #导入turtle模块
turtle.showturtle() #显示箭头
turtle.write("高清") #写字符串
turtle.forward(300) #前进300像素
turtle.color("red") #画笔颜色改为red
turtle.left(90) #箭头左转90度
turtle.forward(300)
turtle.goto(0,50) #去坐标(0,50)
turtle.penup() #抬笔
turtle.pendown() #下笔
turtle.circle(100) #画圆
turtle.width(10) #画笔的粗细
python中,一切皆对象。每个对象由:标识(identity)、类型(type)、value(值)组成。
对象的材质就是:一个内存块,拥有特定的值,支持特定类型的相关操作。
python仅仅对比较小的整数对象进行缓存范围为[-5,256]
在python中,变量也成为:对象的引用。因为,变量存储的就是对象的地址。变量通过地址引用了“对象”
变量位于:栈内存 对象位于:堆内存。
链式赋值
x=y=123相当于 x=123;y=123
系列解包赋值
a,b,c=4,5,6 相当于:a=4;b=5;c=6;
变量互换 : a,b=1,2 a,b=b,a
比较运算符:== >= <= > < !=
逻辑运算符:or and not
同一运算符用于比较两个对象的存储单元,实际比较的是对象的地址
is 是判断两个标识符是不是引用同一个对象
is not 是判断两个标识符是不是引用不同对象
不换行打印,print("sxt",end='任意字符串')实现末尾增加任何内容
print("xuxu",end''):不换行打印
str()将数据转换成字符串
正向搜索:最左侧第一个字符,偏移量是0,第二个偏移量是1,以此类推,直到len(str)-1为止
反向搜索:最右侧第一个字符,偏移量是-1,倒数第二个偏移量是-2,以此类推,直到len(str)为止
a='abcdefg' a[0]=a,a[3]=d,a[-1]=g,a[-2]=f
replace()实现字符串替换
字符串是“不可改变”的,我们通过【】可以获取字符串指定位置的字符,但是我们不能改变字符串。我们尝试改变字符串中某个字符,发现报错了。但是我们确实有时候需要替换某些字符
a = 'abcdefg' a.replace('c','高') a = 'ab高defg
字符串切片slice操作,可以让我们快速的摄取子字符串,标准格式为:
[起始偏移量start"终止偏移量end : 步长step]
[:] 提取整个字符串
[start:] 从start索引开始到结尾
[:end] 从头开始直到end-1
[start:end] 从start到end-1
[start:end:step] 从start提取到end-1,步长是step
a = 'abcdefg' a[1:5:2] =bdf
[-3:] 倒数三个
[-8:-3] 倒数第八个到倒数第三个包头不包尾
[::-1] 步长为负,从右到左反向提取
split()分割和join()合并
split()可以基于指定分隔符将字符串分隔成多个子字符串(存储到列表中)。如果不指定分隔符,则默认使用空白字符(换行符、空格、制表符)
a = 'to be or not to be'
a.split()=['to','be','or','not','to','be'] a.split('be')='to',' ','or note to ',' ']
join()的作用和split()作用刚好相反,用于将一系列子字符串连接起来。示例代码 如下:
b = ['my','name','is','xuxu']
print(' '.join(b)) --> my name is xuxu
字符串驻留机制和字符串比较
驻留:仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串驻留池中。对于符合标识符规则的字符串(仅包含下划线(_)、字母和数字)会启用字符串驻留机制
a = 'xuxu_66' b = 'xuxu_66' a is b = true
a = 'xuxu#' b = 'xuxu#' a is b = flase
使用is/not is ,判断两个对象是否同一个对象,比较的是对象的地址,即id(obj1)是否和id(obj2)相等
a = 'my name is xuxu' 'xuxu'in a = ture 'you' in a = flase 'you' not in a = ture
in/not in ,判断某个字符(子字符串)是否在于字符串中
字符串_常用查找方法_去除首位信息_大小写_排版
a = 'my name is xuxu'
len(a) 字符串长度
a. startswith('my name') 以指定字符串开关 true
a.endswith('xuxu') 以指定字符串结尾 true
a.find('x') 第一次出现指定字符串的位置 12
a.rfind('x') 最后一次出现指定字符串的位置 14
a.count('m') 指定字符串出现了几次 2
a.isalnum() 所以字符全是字母或数字 true
去除首尾信息,可能通过strip()去除字符串首尾指定信息。通过lstrip()去除字符串左边指定信息
rstrip()去除字符串右边指定信息
"*s*x*t*".strip("*") = s*x*t
"*s*x*t*".lstrip("*") = s*x*t*
"*s*x*t*".rstrip("*") = *s*x*t
大小写转换
a = 'my name IS Xuxu'
a.capitalize() 产生新的字符串,首字母大写 My name is xuxu
a.title() 产生新的字符串,每个单词都首字母大写My Name Is Xuxu
a.upper() 产生新的字符串,所有字符全转成大写
a.lower() 产生新的字符串,所有字符全转成小写
a.swapcase() 产生新的,所以字母大小写转换 MY NAME is xUXU
格式排版
center()/ljust()/rjust()用于对字符串实现排版
a = 'XUXU' a.center(10,'*') ***XUXU***
a = 'XUXU' a.center(10) XUXU
a = 'XUXU' a.ljust(10,'*') XUXU******
a = 'XUXU' a.rjust(10,'*') ******XUXU
isalnum() 是否为字母或数字
isalpha() 检测字符串是否只由字母组成(含汉字)
isdigit() 是否只由数字组成
isspace() 是否为空白符
isupper() 是否为大写字母
islower() 是否为小写字母
format()用法
通过{}和:来代替以前的%
填充与对齐
^ < >分别是居中,左对,右对,后面带宽度
"{:*>8}".format("245") ='*****245"
数字化,浮点数通过f,整数通过d进行需要的格式化
a = '我是{0},我的存款有{1:.2f}'
a.format('xuxu',388.234) = ‘我是xuxu,我的存款有388234’
序列是一种数据存储方式 ,用来存储一系列的数据,在内存中,序列就是一块用来存放多个值的连续的内存空间。比如一个整数序列[10,20,30,40]
列表增加元素
list.append(x): 将元素x增加到列表list尾部
list.extend(aList):将列表alist所有元素加到列表list尾部
list,insert(index,x):在列表list指定位置index处插入元素x
删除元素
list.remove(x):在列表list中删除首次出现的指定元素x
list.pop([index]):删除并返回列表list指定为上index处的元素,默认是最后一个元素
list.clear():删除列表所有元素,并不是删除列表对象
list.index(x)访问元素:返回第一个x的索引位置,若不存在x元素抛出异常
list.count(x)计数:返回指定元素x在列表list中出现的次数
len(list)列表长度:返回列表中包含元素的个数
list.reverse()翻转列表:所有元素原地翻转
list.sort()排序:所有元素原地排序
list.copy()浅拷贝:返回列表对象的浅拷贝
python的列表大小可变,根据需要随时增加或缩小
字符串和列表都是序列类型,一个字符串是一个字符序列, 一个列表是任何元素的序列。我们前面学习的很多字符串的方法,在列表中也有类似的用法,几乎一模一样。
列表的创建
基本语法[]创建
a = [10,20,'xuxu','sxt']
a = [] //创建一个空的列表对象
list()创建,使用list可以将任何可迭代的数据化成列表
a = list() #创建一个空的列表对象
a = list(range(10)) = [0,1,2,3,4,5,6,7,8,9]
a= list("xuxu,xuegod") = ['x','u','*********]
range可以帮助我们非常方便创建整数列表
range([start],end[step])
start:可选,表示起始数字,默认是0
end:必选,表示结尾数字
step:可选,表示步长,默认为1
python3中range()返回的是一个range对象,而不列表。我们需要通过list方法将其转换成列表对象
list(range(3,15,2)) = [3,5,7,9,11,13]
list(range(15,3,-1)) = [15,14,13,12,11,10,9,8,7,6,5,4]
list(range(3,-10,-1)) = [3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9]
列表元素的增加效率
append()方法最快,推荐使用
+运算符操作
a = a+[50] #a的地址发生变化,创建了新的列表对象,不建议使用
extend()方法将目标列表的所有元素添加到本列表的尾部,属于原地操作
insert
a = [10,20,30]
a.insert[2,100] = [10,20,100,30]
乘法扩展
a = ['xuxu',100]
b = a*3 = ['xuxu',100,'xuxu',100,'xuxu',100]
列表元素删除-本年是数组元素拷贝
del删除-指定位置的元素
a = [10,20,30]
del a[1]
a = [10,30]
pop()-如果未指定位置则默认操作列表最后一个元素
a = [10,20,30,40,50]
a.pop()
a = [10,20,30,40]
remove()-删除首次出现的指定元素,若不存在该 元素抛出异常
a = [10,20,30,40,50,20,30,20,30]
a.remove(20)
a = [10,30,40,20,30,20,30]
index()获得指定元素在列表中首次出现的索引
index(value,[start,[end]])
start和end指定了搜索的范围
count()获得指定元素在列表中出现的次数
len()返回列表长度
列表——切片slice操作
[起始偏移量start:终止偏移量end[:步长step]]
列表遍历
for obj in listobj:
print(obj)
列表排序
修改原列表,不建新列表的排序,一定要和print分开写
a = [20,10,30,40]
a.sort() #默认是升序排列
a.sort(reverse=True) #降序排序
import random
random.shuffle(a) #打乱顺序
使用内置函数sorted()进行顺序,不对原列表做修改
a = sorted(a)#默认升序
a = sorted(a,reverse=True)#降序
reversed()返回迭代器
内置函数reversed()也支持进行逆序排列,不对原列表做任何修改,只是返回一个逆序排列的迭代器对象
a = [20,30,10,40]
c = reversed(a) = <list_reverseiterator object at 0x0000000002BCCEBB>
list(c) = [40,30,10,20]
max和min函数返回最大和最小值
sum函数求和,对非数值会报错
多维列表
a = [
['xuxu',19,30000,'hacker'],
['nongnong,38,40000,'hacker'],
]
元组tuple
列表属于可变序列,可以任意修改列表中的元素。元组属于不可变序列,不能修改元组中的元素。因此,元组没有增加元素、修改元素、删除元素相关的方法
因此,我们只需要学习元组的创建和删除,元组中元素的访问和计数即可。元组支持如下操作:
1.索引访问 2.切片操作 3.连接操作 4.成员关系操作 5.比较运算操作 6.计数:元组长度,最小值等
元组的创建
a = (10,20,30)或者a = 10,20,30
如果元组只有一个元素,则必须后面加逗号。这是因为解释器会把(1)解释为整数1,(1,)解释为元组
a = (1)
type(a) = <class 'int'>
a = (1,) #或者 a= 1
type(a) = <class 'tuple'>
通过tuple()创建元组
tuple(可迭代的对象)
b = tuple() #创建一个空元组对象
b = tuple('abc')
b = tuple(range(3))
b = tuple([2,3,4,5])
tuple()可以接收列表/字符串/其它序列类型/迭代器/等生成元组
list()可以接收元组/字符串/其他序列类型/迭代器等 生成列表
元组的元素访问和计数
1. 元组的元素不能修改
a = (20,10,30,9,8)
a[3] = 33
这个就是错的
2. 元组的元素访问和列表一样,只不过返回的仍然是元组对象
a = (20,10,30,9,8)
print(a[3])
print(a[1:3])
3. 列表关于反序的方法list.sorted()是修改原列表对象,元组没有该方法。如果要对元组排序,只能使用内置函数sorted(tupleObj),并生成新的列表对象
a = (20,10,30,9,8)
sorted(a) = 8,9,10,20,30
zip
zip(列表1,列表2,...) 将多个列表对劲应位置的元素组合成为元组,并返回这个zip对象
a = [10,20,30]
b = [40,50,60]
c = [70,80,90]
d = zip(a,b,c)
print(list(d)) = [(10,40,70),(20,50,80),(30,60,90)]
生成器推导式创建元组
从形式上看,生成与列表推导式相似,只是生成推导式使用小括号,列表推导式直接生成列表对象,生成器推导生成的不是列表也不是元组,而是一个生成器对象
我们可以通过生成器对象,转化成列表或元组,也可以使用生成器对象的_next_()方法进行遍历,或者直接作为迭代器对象来使用。不管什么 方式使用,元素访问结束后,如果需要重新访问其中的元素,重新创建该生成器对象
操作:生成器的使用测试
s = (x*2 for x in range(5))
s = <generator object <genexpr> at 0x7fd5a942b740>
tuple(s) = (0,2,4,6,8)
list(s) = [] # 只能访问一次元素,第二次就为空,需要再生成一次
s = <generator object <genexpr> at 0x7fef9539b740>
s = (x*2 for x in range(5))
s.__next__() = 0
s.__next__() = 2
元组总结
1.元组的核心特点是:不可变序列
2.元组的访问和处理速度比列表快
3.与整数和字符串一样,元组可以作为字典的键,列表则永远不能作为字典的键使用
字典
字典是“键值对”的无序可变序列,字典中的每个元素都是一个“键值对”,包含:“键对象”和“值对象”。可以通过“键对象”实现快速获取/删除/更新对应的“值对象”
列表中我们通过“下标数字”找到对应的对象,字典中通过“键对象”找到对应的“值对象”。“键”是任意的不可变数据,比如:整数/浮点数/字符吕/元组。但是:列表/字典/集合这些可变对象,不能作为“键”,并且“键”不可重复
一个典型的字典的定义方式:
a = {'name':'xuxu','age':'18','job':'hacker'}
1.可以通过{},dict()来创建字典对象
b = dict(name='xuxu',age=18,job='hacker')
a = dict([("name","xuxu"),("age",18)])
c = {} #空的字典对象
d = dict() #空的字典对象
2. 通过zip创建字典对象
k = ['name','age','job']
v = ['xuxu',18,'hacker']
d = dict(zip(k,v))
3. 通过fromkeys创建值为空的字典
a = dict.fromkeys(['name','age','job'])
prin(a) = ['name':None,'age':None,'job':None]
字典元素的访问
为了测试各种访问方法,我们这里设定一个字典对象
1.通过键获得值,若键不存在,则抛出异常
a = {'name':'xuxu','age':18,'job':hacker'}
a['name'] = xuxu
2.通过get()方法获得’值‘,推荐使用。优点:指定键不存在,返回None;也可以设定指定键不存在时默认返回的对象,推荐使用get()获取“值对象”。2.通过get()方法获得’值‘,推荐使用。优点:指定键不存在,返回None;也可以设定指定键不存在时默认返回的对象,推荐使用get()获取“值对象”。
a.get('name') = 'xuxu'
a.get('sex') = None
a.get('sex','xuxu') = 'xuxu'
3.列出所有的键值对
a.items() = dict_items([('name',xuxu'),('age',18),('job','hacker)])
4.列出所有的键,列出所有的值
a.keys() = dict_keys([('name','age','job')])
a.values() = print(a.values())
5.len()键值对的个数
6.检测一个“键”是否在字典中
a = {"name":"xuux","age",18}
"name" in a = true
字典元素的添加,修改,删除
1.给字典新增“键值对”,如果“键”已经存在,则覆盖旧的键值对;如果“键”不存在,则新增“键值对”。
a = {'name':'xuxu','age':18,'job':'hacker'}
a['address'] = 'jiangsu'
a['age'] = 16
a = {'name': 'xuxu', 'age': 17, 'job': 'hacker', 'address': 'jangsu'}
2.使用update()将新字典中所有键值对全部添加到字典对象上,如果key有重复,则直接覆盖
a = {'name':'xuxu','age':18,'job':'hacker'}
b = {'name':'zzq','money':1000,'sex':'nan'}
a.update(b) = {'name': 'zzq', 'age': 18, 'job': 'hacker', 'money': 10000, 'sex': 'nan'}
3.字典中元素的删除,可以使用del()方法,或者clear()删除所有键值对;pop()删除指定键值对,并返回对应的“值对象”;
a = {'name':'xuxu','age':18,'job':'hacker'}
del(a['name']) = {'age':18,'job':'hacker'}
b = a.pop('age') = 18
序列解包
序列解包可以用于元组,列表,字典。序列解包可以让我们方便的对多个变量赋值
x,y,z = (10,20,30)
x = 10
y = 20
z = 30
(a,b,c) = (9,8,10)
a = 9
[a,b,c] = [10,20,30]
a = 10
b = 20
序列解包用于字典时,默认是对“键”进行操作;如果需要对键值对操作,则需要使用items();如果需要以地“值”进行操作,则需要使用values();
s = {'name':'xuxu','age':18,'job':'hacker'}
a,b,c = s #默认对键进行操作
a = name
d,e,f = s.items() #对键值对进行操作
a = ('name','xuxu')
h,i,j = s.values() #对值进行操作
h = xuxu
字典-复杂表格数据存储-列表和字典综合嵌套
字典-核心底层原理-内在分析-存储键值对过程
字典对象的核心是散列表。散列表是一个稀疏组(总是空白元素的数组),数组和每个单元叫bucket。每个bucket有两部分:一个是键对象的引用,一个是值对象的引用。由于,所有bucket结构和大小一致,我们可以通过偏移量来读取指定bucket
将一个键值对放进字典的底层过程
a = {}
a['name'] = 'xuxu'
查找键值对的底层过程
当我们调用a.get('name'),就是根据'name'查找到“键值对”,从而找到值对象'xuxu'
第一步仍然要计算name对象的散列值
用法总结:
1.数字/字符串/元组/都是可散列的
2.自定义对象需要支持下面三点:
支持hash()函数
支持通过_seq_()方法检测相等
若a==b为真,则hash(a)==hash(b)也为真
2.字典在内在中开销巨大,典型的空间换时间
3.键查询速度很快
4.往字典里面添加新建可能导致扩容,导致散列表中键的次序变化。因此,不要在遍字典的同时进行字典的修改
集合特点-创建和删除—交集-并集差集运算
集合是无序可变,元素不能重复。实际上,集合谨慎是字典实现,集合的所有元素都是字典中的“键对象”,因此不能重复的且唯一的
1.使用{}创建集合对象,并使用add()方法添加元素
a = {3,5,7}
a.add(9) = {9,3,5,7}
2.使用set(),将列表/元组可迭代对象转成集合,如果原来数据存在重复数据,则只保留一个。
a = ['a','b','c','b']
b = set(a) = {'b',a','c'}
3.remove()删除指定元素;clear()清空整个集合
a = {10,20,30,40,50}
a.remove(10) = {40, 50, 20, 30}
集合相关操作
a = {1,3,'sxt'}
b = {'he','it','sxt'}
a | b # 并集
{1,3,'sxt','he','it'}
a & b #交集
{'sxt'}
a - b #差集
{1, 3}
a.union(b) #并集
{'he', 1, 3, 'it', 'sxt'}
a.intersection(b) #交集
{'sxt'}
a.difference(b) #差集
{1, 3}
结构开始
单分支选择结构-条件表达式
选择结构通过判断条件是否成立,来决定执行哪 个分支。选择结构有多种形式,分为:单分支,双分支,多分支
if a < 10 :
print("xuxu")
if 3<c<20:
print('3<c<20')
双分支选择结构-三元运算符的使用详解
if 条件表达式:
语句1/语句块1
else:
语句2/语句块2
三元表达式
if (条件表达式) else 条件为假时的值
num = input('请输入一个数字')
print( num if int(num)<10 else '数字太大')
多分支选择结构
if 条件表达式1 :
语句1
elif 条件表达2:
语句2
elif 条件表达式n:
语句3
[else:
语句n+1
]
选择结构的嵌套
使用时一定要注意 控制好不同级别代码块的缩进量,因为缩进量决定了代码的从属关系
if 表达式1:
语句1
if 表达式2:
语句2
else:
语句3
else :
if 表达式4:
语句4
while 循环结构
循环体里面的语句至少应该 包含改变条件表达式的语句,以使用循环趋于结束;否则,就会变成一个死循环
while 循环的语法格式如下:
while 条件表达式:
循环语句
for 循环结构——遍历各种可迭代对象——range对象
for循环通常用于可迭代对象的遍历
for 变量 in 可迭代的对象:
循环体
可迭代的对象:
1.序列。包含:字符串/列表/元组
2.字典
3.迭代器对象(iterator)
4.生成器函数(generator)
遍历字符串中的字符
for x in "sxt001":
range 对象是一个迭代器对象,用来产生指定范围的数字序列
range(start,end,[step])
生成的数值序列从start 开始到end 结束(不包含end)。若没有填写start,则默认从0开始。step是可选的步长,默认为1
for i in range(10) # 0 123456789
for i in range(3,10) # 3456789
for i in range(3,10,2) # 3 5 7 9
嵌套循环
打印以下
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
for m in range(5):
for n in range(5):
print(m,end='\t')
print()
break语句
break 语句可用于while和for循环,用来结束整个循环,当有嵌套循环时,break语句只能跳出最近一层的循环
continue语句
else语句
while/for循环可以附带一个else语句(可选)。如果for/while语句没有被break语句结束,则会执行else子句,否则不执行。语法格式如下:
while 条件表达式:
循环体
else:
语句块
for 变量 in 可迭代的对象:
循环体
else:
语句块
循环代码优化技巧
1.尽量减少循环内部不必要的计算
2.嵌套循环中,尽量减少内层循环的计算,尽可能的向外提
3.局部变量查询较快,尽量使用局部变量
使用zip()并行迭代
可以通过zip()函数对多个序列进行并行迭代,zip()函数在最短序列“用完”时就会停止
names = ('xuxu','hack','three')
ages = (18,16,14)
jobs = ('hacker','teacher','computer')
for name,age,job in zip(names,ages,jobs)
print("{0}{1}{2}".format(name,age,job))
推导式创建序列——列表推导式-字典推导式-集合推导式-生成器推导式
推导式是从一个或者多个迭代器快速创建序列的一种方式。它可以将循环和条件判断结合,从而避免冗长的代码。推导式是典型的python风格,会使用它代表你已经超过Python初学者的水平
1.列表推导式
语法如下:
[表达式 fro item in 可迭代对象]
或者:{表达式 for item 可迭代对象 if 条件判断}
2.字典推导式:
{key_expression:value_expression for 表达式 in 可迭代对象}
my_text = 'i love you , i love sxt ,i love xuxu'
char_count = {c:my_text.count(c) for c in my_text}
char_count
3.集合推导式:
{表达式 for item in 可迭代对象}
或者:{表达 for item 可迭代对象 if 条件判断}
{x for x in range(1,100) if x%9 == 0}
4.生成器推导式(生成元组)
(x for x in range(1,100) if x % 9 == 0)
可以发现是一个生成器对象,显然,元组是没有推导式的。
一个生成器只能运行一次,第一次迭代可以得到数据,第二次迭代发现数据已经没有了
综合练习-绘制不同颜色的多个同心圆-绘制棋盘
import turtle
t = turtle.Pen()
my_colors = ('red','green','blue','black')
for i in range(5):
t.penup()
t.goto(0,-i*50)
t.pendown()
t.color(my_colors[i%len(my_colors)])
t.circle(100+i*50)
turtle.done()
函数用法和底层分析
函数是可征用的程序代码块。
1.一个程序由一个个任务组成;函数就是代表一个任务或者一个功能
2.函数是代码利用的通用机制。
内置函数,标准库函数,第三方库函数,用户自定义函数
函数的定义和调用
定义语法
def 函数名 ([参数列表]):
"文档字符串"
函数体/若干语句
要点:
Python执行def时,会创建一个函数对象,并绑定到函数名变量上
圆括号内是形式参数列表,有多个参数则使用逗号隔开
形式参数不需要声明类型,也不需要指定函数返回值类型
无参数,也必须保留空的圆括号
实参列表必须与形参列表 一一对应
文档字符串相当于注释
形参和实参-文档字符串-函数注释
函数通过三个单引号或者三个双引号来实现,中间可以加入多行文字进行说明
我们调用help(函数名.__doc__)可以打印输出函数的文档字符串
返回值
如果函数体中包含return 语句,则结束函数执行并返回值
如果函数体中不包含return语句,则返回None值
要返回多个返回值,使用列表/无组/字典/集合将多个值存起来即可
函数也是对象-内存分析
一切都是对象 实际:执行def定义函数后,系统就创建了相应的函数对象。
变量的作用域(全局变量和局部变量)
变量起作用的范围称为变量 的作用域,不同作用域内同名变量之间互不影响,变量分为:全局变量,局部变量
全局变量 :
1.在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始直到模块结束
2.全局变量降低了函数的通用性和可读性。应尽量避免全局变量 的使用
3.全局变量一般做常量使用
4.函数内要改变全局变量的值,使用global声明一下
局部变量:
1.在函数体中(包含形式参数)声明
2.局部变量的引用比全局变量 快,优先考虑考虑使用
3.如果局部变量和全局变量同名,则在函数内隐藏全局变量,只使用同名的局部变量
局部变量和全局变量-效率测试
在特别强调效率的地主或者循环次数较多的地方可以通过全局变量转为局部变量提高运行速度
import math
import time
def test1():
start = time.time()
for i in range(100000):
math.sqrt(30)
end = time.time()
print(end-start)
def test2():
b = math.sqrt
start = time.time()
for i in range(100000):
b(30)
end = time.time()
print(end-start)
test1()
test2()
参数的传递-传递可变对象-内存分析
1.对可变对象进行写操作,直接作用于原对象本身
2.对不可变对象进行写操作,会产生一个新的对象空间,并用新的值填允这块空间
可变对象有:字典/列表/集合/自定义的对象等
不可变对象有:数字/字符串/元组/function等
浅拷贝和深拷贝
可以使用内置函数:copy(浅拷贝)/deepcopy(深拷贝)
浅拷贝:不拷贝子对象,只是拷贝子对象的引用
深拷贝:会连子对象的内存也全部拷贝一份,对子对象的修改不会影响源对象
参数的传递—不可变对象含可变子对象-内存分析
传递参数是不可变对象(例如:int float 字符串 元组 布尔值)实际传递的还是对象的引用。但在写操作时,会创建一个新对象拷贝,这个拷贝使用的是浅拷贝不是深拷贝
传递不可变对象时。不可变对象里面包含的子对象是可变的,则方法内修改了这个可变对象,源对象也发生了变化
参数的类型-位置参数-默认值参数-命令参数
位置参数:函数调用时,实参默认按位置顺序传递,需要个数和形式参匹配。按位置传递的参数,称为:位置参数
def f1(a,b,c):
print(a,b,c)
f1(2,3,4)
#f1(2,3) # 报错,位置参数不匹配
默认参数:可以为某些参数设置默认值,这样这些参数在时就是可选的。称为“默认值参数”默认值参数放到位置参数后面。
命名参数:可以按照的名称传递参数,称为“命名参数”,也称“关键字参数”
可变参数-强制命名参数
可变参数:
1.*param(一个星号),将多个参数收集到一个”元组“对象中。
2.**param(两个星号),将多个参数收集到一个“字典”对象中。
def f1(a,b,*c):
print(a,b,c)
f1(8,9,19,20)
def f2(a,b,**c):
print(a,b,c)
f2(8,9,name='xuxu',age=18)
def f3(a,*b,**c):
print(a,b,c)
f3(8,9,10,name='xuxu',age=18)
强制命名参数:在带星号的可变参数后面增加新的参数,必须是强制命名参数
def f4(*a,b,c):
print(a,b,c)
#f4(2,3,4) 会报错。由于a是可变参数,将2,3,4全部收集。造成b和c没有同仁
f4(2,b=3,c=4)
lambda表达式和匿名函数
lambda表达可以用来声明匿名函数。lambda函数是一种简单的,在同一行中定义函数的方法。lambda函数实际生成了一个函数对象
lambda表达式只允许包含一个表达式,不能包含复杂语句,该表达式的计算结果就是函数的返回值。
lambda的表达式的基本语法如下:
lambda arg1,arg2,arg3...:<表达式>
arg1/arg2/arg3为函数的参数。<表达式>相当于函数体。去处结果是:表达式的运算结果
f = lambda a,b,c:a+b+c
print(f)
print(f(2,3,4))
g = [lambda a: a*2,lambda b: b*3,lambda c: c*4]
print(g[0](6),g[1](7),g[2](8))
**************结果***************************
<function <lambda> at 0x7fcccad061f0>
9
12 21 32
eval()函数
功能:将字符串str当成有效的表达式来求值并返回计算结果。
语法:eval(source[,globals[,locals]]) ->value
参数:source:一个Python表达式或函数compile()返回的代码对象
globals:可选。必须是dictionary
locals:可选,任意 映射对象
递归函数—函数调用内存分析-栈帧的创建
递归函数指的是:自己调用自己的函数,在函数体内部直接或间接的自己调用自己。
# 阶乘
def test(n):
if n == 1:
return 1
else:
return n*test(n-1)
for i in range(1,6):
print(i,'!=',test(i))
嵌套函数-内部函数-数据隐藏
在函数内部定义函数
一般在什么情况下使用嵌套函数
1.封装-数据隐藏
外部无法访问“嵌套函数”
2.贯彻DRY原则
嵌套函数,可以让我们在函数内部避免重复代码
3.闭包
后面会详细讲解
nonlocal用来声明外层的局部变量
global用来声明全局变量
LEGB规则
python在查找“名称”时,是按照LEGB规则查找的:local-->Enclosed-->Global-->Built in.
local:指的就是函数或者类的方法内部
Enclosed:指的是嵌套函数(一个函数包裹另一个函数,闭包)
Global:指的就是模块中的全局变量
Built in 指的是python为自己保留的特殊名称