#函数
#函数的定义(定义的过程就是将函数体以字符串的形式存于内存空间中)
TIPS:
#函数的定义要在调用之前
#函数的名字本身的值为存放函数的内存地址,函数名后加()代表运行函数内存空间中存放的字符串
#函数的作用域跟定义的位置有关,跟调用函数的位置无关,且嵌套在函数中的函数不能直接被调用
a = '111'
def test() :
a = '222'
def test1() :
a = '333'
def test2() :
print(a)
return test2
return test1
test()()() --> 333
#分全局变量和局部变量(局部变量小写,全局变量大写)
#函数中没有定义局部变量的话默认寻找上一级的同名变量
a = (11,22,33)
def text() :
a = 3
def textt() :
print(a)
return 0
textt()
text() --> 3
#子程序也就是函数中的 pass
# 载入time模块 time.sleep(1) 代表延时1秒
import time
print(11)
time.sleep(1)
print(22)
#pycharm里点击左边选择断点,然后右键选择Debug,可以用来一步步执行代码
#函数定义
def sum1(x,y) : --> 也可不传参数或传入多个参数
'this function is used in caculation' --> 注释,可以说明此函数的信息
x = x + y
return x --> 若没有返回值则(返回None)成为过程
(此说明python中没意义,别的程序语言可能就有用)
return 1,2,['adsf',11] 这样返回的是一个元组(1,2,['adsf',11])
#函数的参数
形参 : def sum1(x,y) 里面的 x , y就是形式参数,每次被调用时才有值,调用结束后取消指向的内存空间
实参 : a = 0 之类的参数
#一个参数不能传两次值
#位置参数(必须一一对应)
sum1(1 , 2) -->其中的 1 ,2 就叫位置参数, 跟调用函数的形参一一对应
#关键字参数(无序一一对应,但参数数量得相同)
sum1(x = 1 , y = 2)
也可以对应位置进行修改
def text(x, y=1):
print(y)
text(1,2)
#两者混用时位置参数一定要在关键字参数的左边,同时注意关键字参数得在**kwargs左边,如sum1(x,*args,y=1,*kwargs)
sum1(1 , y = 2)
#直接定义值
def name(x , y = 'alex') :
#参数组 *列表
def test(x,*args) :
print(args)
return ()
test(1,2,3,4,'dsfds',{'name': 'alex'},*[111,222]) --> (2, 3, 4, 'dsfds',{'name': 'alex'},111,222)
元组形式
#参数组 **字典
def test(x,*args,**kwargs) : -->*args 得在 **kwargs 左边
print(kwargs)
return 0>
test(1,*[1,2,3],name = 'alex' ,b = 3) --> {'name': 'alex', 'b': 3}
或
test(1,*[1,2,3],**{'name': 'alex', 'b': 3})
总结:
# 普通参数必须一一对应,必须传
# 默认参数可传可不传 实参的级别大于形参的级别,位置可以不对应。
# 一个形参只能给它传一次,不能被赋予多个值
# *args除了关键字参数、**字典,其它都可以传,它是一个元组,不传也可以
# **kwargs只能接收关键字参数,如果接收字典的话,在字典前面要加**,不传也可以
# 优先级别 先是位置一一对应,普通参数,默认参数,*参数,**参数
#在函数中修改全局变量
a =1
def test() :
global a #此声明后下面所有有关变量a的定义全为全局变量 (本质上是一个指针指向了全局变量a的内存地址,如果没有此声明,下面定义的a的内存地址其实不是全局变量的a内存地址,相当于开辟新地址)
a =2 #在定义的global声明之前 ,不许再定义局部变量(因为一个指向局部开辟的新内存,一个指向全局变量的内存,会报错)
return 0
print(a) --> 2
#在函数中修改上一级变量
a = (11,22,33)
def text() :
a = 3
def textt() :
nonlocal a
a = [1,2,3]
return 0
textt()
print(a)
text() --> [1,2,3]
#递归函数(函数中嵌套自己),需要满足以下条件
#必须有一个明确的结束条件
#用递归函数执行循环功能
#每进行更深一层的递归时,问题规模要有所减少
#递归效率不高,递归层次过多会导致内存空间被占满
n = input('输入一个整数\n')
a = 0
def sum1(x) :
global a
a = a + x
if x == 0 :
return a
return (sum1(x-1))
account = sum1(int(n))
print(account) --> n = 100 --> 5050
#匿名函数(lambda)
#没有名字的函数,本身的值为函数地址
#定义
a = lambda x,y,z:(x+y+z,x-y) --> 形参:返回值
print(a(1,2,3)) --> (6,-1)
#主流的编程方法:函数式、面向过程、面向对象
#函数式编程(精简但可读性差)
1、不可变:不用变量保存状态,不修改变量(右为面向过程)
def test(x) : | def test(x) :
return x+1 | res = x + 1
| return res
2、第一类对象,函数即'变量'(函数本身即为内存地址,可以把函数当做一个参数传给另一个函数)
def a(x) :
print(x)
def b(y) :
pass
a(b(123)) --> None
3、高阶函数 --> 满足一下两点之一
#函数接受的参数是函数
#返回值中包含函数
#尾调用优化
#尾调用指函数运行的最后一步(并非是函数的最后一行)为调用另一函数
def text(x) : def text(x) :
return text(x)+1 -->不为尾调用,实际= res = text(x) + 1
return res
#由于函数中调用其他函数,系统会保存原函数的状态在去执行下一个函数,如果嵌套的函数多了,占用内存空间大、效率低。因此在函数式编程的时候,最好进行尾调用优化,即函数运行的最后一步为调用下一个函数,这样就能保证前一个函数完全运行完,在不继续占用内存空间的情况下运行下一个函数。
—————————————三个函数式编程的内置函数—————————————
#map函数
#对列表的每个元素逐一用指定函数处理,返回一个迭代器
a = map(lambda x : (x+1),[9,2,3]) --> map的值a为一个迭代器(只能迭代一次)的地址 print(list(a))
print(a) --> list命令将可迭代对象依次添加成列表 (但在python2中,map的处理结果就是一个列表)
#以上map函数的功能也可以用以下代码实现
add1 = lambda x : (x+1)
def test(func,array) :
list1 = []
for i in array :
list1.append(func(i))
return list1
print(test(add1,[9,2,3]))
#filter函数
#用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
#该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
#用于筛选出列表中含'alex的元素'
list1 = ['sssf' , 'alex' , " 11 alex's friends "]
a = filter(lambda x:x.count('alex'),list1)
print(a)
print(list(a))
#以上map函数的功能也可以用以下代码实现
list1 = ['sssf' , 'alex' , " 11 alex's friends "]
def find_new(x) :
return x.count('alex')
def filter_new(func,array) :
listt = []
for i in array :
if func(i) :
listt.append(i)
return listt
print(filter_new(find_new,list1))
#reduce函数 (reduce(function,iterable,initializer))
#对参数序列中元素进行累积 --> 将序列中的1、2个元素交给function处理,处理的结果在跟第3个元素一起交给fuction处理,以此类推
function -- 函数,有两个参数
iterable -- 可迭代对象
initializer -- 可选,初始参数
#python2 中可以直接用 ,python3 中需要导入模块
from functools import reduce
#将列表中的元素相乘,这里的初始参数100代表添加一个100到序列的第一位后处理
from functools import reduce
a = [1,2,3,4,5,6]
print(reduce(lambda x,y:x*y,a,100))
#此功能也可以表示为以下代码
a = [1,2,3,4,5,6]
def multify(x,y) :
return x*y
def reduce_new(func,array) :
res = array.pop()
for i in array :
res = func(res,i)
return res
print(reduce_new(multify,a))
——————————————————————————————————
#一些内置函数
abs() -->取绝对值
all(可迭代对象) --> 判断布尔值,所有元素为True则输出True,否则为False,如果可迭代对象为空则也返回True : e.g. all('')
any() --> 用法同all,or逻辑(all为and逻辑)
bin() -->十进制转二进制 注(进制前缀): 0x 十六进制 0b 二进制 0 八进制 0d 十进制
hex() -->十进制转十六进制
oct() -->十进制转八进制
bool() --> 判断布尔值
bytes('你',encoding='utf-8') -->将字符串用指定编码方式编码(e.g. utf-8) \x 代表16进制
b'\xc4\xe3'.decode('gbk') -->用指定编码(不写默认为utf-8)方式解码
chr(97) --> 得到指定ascii码的字符
ord('a') --> 得到字符的ascill码
dir() --> 列出对象中有什么方法
divmod(10,3) --> (3,1) 取商和余数 (可做分页功能)
eval() -->将字符串str转换成有效的表达式(e.g. eval('123') + 1 --> 124)
(e.g. eval('5+3**2') --> 14)
globals() -->以字典形式返回所有全局变量
locals() -->以字典形式返回当前代码块下的局部变量
vars() -->无参数默认以字典形式输出当前代码块下的变量
hash()
#hash() 函数就是对某数据进行一种运算,具有以下特点
#1 可hash的均为不可变数据类型
#2 无法通过hash运算后的结果反推原数据
#3 可用于检测文件的完整型
help()
isinstance('abc',str) -->判断一个数据是否是指定类型(这里是判断'abc'是否为字符串类型)
list(zip([1,2,3],('a','b','c','d'))) --> [(1, 'a'), (2, 'b'), (3, 'c')] 将两个可迭代对象一一对应 放入元组中 (不对应的元素会被舍弃e.g. 'd')
#max()
a = {'a1': 11 , 'a2' : 22 , 'a3' : 1}
b = list(zip(a.keys(),a.values()))
print(b) -->[('a1', 11), ('a2', 22), ('a3', 1)]
print(max(b)) -->('a3', 1)
#迭代a中的每一个元素,用 ' key= '里的函数处理,返回的值比较大小,输出最大的那一个元素
a = [
{'name':'alex' , 'age' : 18} ,
{'name' : 'lalalal' , 'age' : 1000}
]
print(max(a,key=lambda x:x['age']))
min()
pow(2,2, 3) --> 相当于 2**2%3
reversed('abcde') --> 反转一个可迭代对象,返回一个迭代器
round() -->四舍五入
slice() --> 定义一个切片,相当于一个切片变量
s1 = slice(0,3)
s2 = slice(0,3,2)
a = 'abcde'
print(a[0:3],a[s1],a[s2]) -->abc abc ac
s1.start -->查看切片变量的开始 、结束 、步长
s1.stop
s1.step
sorted() --> 排序(只能同种数据类型比较)
type() --> 查看数据类型(多用于变量类型判断)
import -->导入模块(_import_导入名字是字符串类型的模块名,e.g. 'test')
注: 调用import的过程图 : import -->sys -->_import_()