python开发基础----函数

python中函数定义:函数是逻辑结构化和过程化的一种编程方法,用来实现某一功能。(函数即变量,只有在调用的时候才会执行,没调用的时候,相当于把函数体当成字符串赋值给函数名)

python中函数定义方法:
 
def test(x):
    "The function definitions"
    x+=1
    return x
     
def:定义函数的关键字
test:函数名
():内可定义形参
"":文档描述(非必要,但是强烈建议为你的函数添加描述信息)
x+=1:泛指代码块或程序处理逻辑
return:定义返回值


调用运行:可以带参数也可以不带
函数名()

 

使用函数的好处:

  •   代码重用
  •   保持一致性,易维护
  •   可扩展性

 

函数和过程

  过程定义:过程就是简单特殊没有返回值的函数

  这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情

  总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None,所以在python中即便是过程也可以算作函数。

  1.   如果没有返回值,则返回的是None
  2.   如果只有一个返回值,则返回的是object
  3.   如果有多个返回值,则返回的是一个元组(tuple)

 

函数的参数

  1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

  2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

  

  3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定),如果混合使用,位置参数必须在关键字参数的左边

def test(x,y,z):
    print(x)
    print(y)
    print(z)
#位置参数,必须一一对应,缺一不行多一也不行
test(1,2,3)
#关键字参数,无须一一对象,缺一不行多一也不行
test(x=3,y=2,z=5)
#位置参数和关键字参数混合使用,位置参数必须在关键字参数的左边
# test(1,y=3,4) #报错
# test(1,4,y=3) #报错

test(1,4,z=3)

 

  4.默认参数,函数定义的时候就给参数默认赋值,调用函数时,可以不传这个参数的值,如果不传,就使用默认值,如果有传值,就用传进来的值

def test(x,type=None): #这里的type为默认参数
    print(x)
    print(type)

test(2)
test(2,5)

  

  5.参数组(** 字典 、 * 列表),非固定长度的参数

def test(x,*args): # *args这个参数可以不传,不传就为空元组,相当于0或多个位置参数
    print(x)
    print(args)

test(1,2,3,4,5,6)
test(1)                 #*args这个参数可以不传,不传就为空元组
test(1,{'name':'alex'}) #如果直接传字典,会把字典当成一个元素传入*args保存到元组
test(1,['x','y','z'])  #如果直接传列表,会把列表当成一个元素传入*args保存到元组,如果想把列表里的元素依次赋值给*args,可以用如下方式
test(1,*['x','y','z']) # *['x','y','z'] 相当于遍历列表之后再把列表中的每个元素传入
test(1,*{'name':'alex'}) #这里只会取字典的key值

结果
1
(2, 3, 4, 5, 6)
1
()
1
({'name': 'alex'},)
1
(['x', 'y', 'z'],)
1
('x', 'y', 'z')
1
('name',)

def test1(x,**kwargs): #相当于n个关键字参数
    print(x)
    print(kwargs)
test1(1,y=2,z=3)
# test1(1,2,3,4,5,y=2,z=3) #会报错,因为函数定义的位置参数只有1个
# test1(1,y=2,z=3,z=4) #会报错,一个参数不能传多次值

#如果两者需要结合到一起,应该位置参数在前面,关键字参数在后面,func test(*args,**kwargs): 如果要传入列表参数,要在参数前面加入* ,字典要用 ** 

  

 局部变量与全局变量

  •   在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
  •   全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
  •   当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用

global关键字:指定全局变量

  如果函数中有global关键字,变量本质上就是全局的那个变量,可读取可赋值

  如果函数中没有global关键字,优先读取全局变量,无法对全局变量重新赋值,但是对于可变类型,可以对内部元素进行操作(如列表的append、pop等操作)

* 全局变量变量名全部大写

* 局部变量变量名全部小写

 

nonlocal 关键字 ,指定上一级变量

 

name='lhf'

def change_name():
    print('我的名字',name)

change_name()


def change_name():
    name='帅了一笔'
    print('我的名字',name)

change_name()
print(name)



def change_name():
    global name
    name='帅了一笔'
    print('我的名字',name)

change_name()
print(name)

 

函数递归调用

在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身

def test(x):
    print(x)
    if int(x/2) == 0:
        return x
    return x,test(int(x/2))

print(test(10))

结果:
10
5
2
1
(10, (5, (2, 1)))
一个简单的递归
ls = ['alex','adqcsa','xieys','sb']

def ask_way(person_ls):
    if len(person_ls) == 0:
        return "没有人知道这个地方怎么走!"
    person = person_ls.pop(0)
    if person == 'xieys':
        return '%s说:这个地方在蛇口,做地铁在水湾站下!' % person
    print('hi,你好,%s ,请问网谷怎么走?' % person)
    print('%s说:我也不知道这个地方怎么走?我帮你问问别人%s.' % (person,person_ls))
    res = ask_way(person_ls)
    print('%s说:%s'% (person,res))
    return  res

ask_way(ls)
递归问路

递归特性:

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]


def binary_search(dataset, find_num):
    print(dataset)

    if len(dataset) > 1:
        mid = int(len(dataset) / 2)
        if dataset[mid] == find_num:  # find it
            print("找到数字", dataset[mid])
        elif dataset[mid] > find_num:  # 找的数在mid左面
            print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:  # 找的数在mid右面
            print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
            return binary_search(dataset[mid + 1:], find_num)
    else:
        if dataset[0] == find_num:  # find it
            print("找到数字啦", dataset[0])
        else:
            print("没的分了,要找的数字[%s]不在列表里" % find_num)


binary_search(data, 20)
二分查找

 

函数的作用域

作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变

例一:
name='alex'

def foo():
    name='lhf'
    def bar():
        print(name)
    return bar

func=foo()
func()


例二:
def foo():
    name = 'xieys'
    def bar():
        name = 'weiwj'
        def tt():
            print(name)
        return tt
    return bar

bar = foo()
tt = bar()
tt()

foo()()() #这里的效果跟前面三句效果一样

  

匿名函数

匿名函数就是不需要显式的指定函数,格式:

  lambda 形参 : 返回值 

a = lambda  x: x + '_sb'
print(a('alex'))

b = lambda x,y:x**y   # lambda 后面紧跟的是函数的形参  : 后面跟的是return返回的值
print(b(2,3))

f = lambda x,y: x if x > y else y #lambda表达式也可以也判断,如果条件 x > y 就返回x,否则就返回y 
print(f(6,5))

一般匿名函数是和其他函数搭配使用

#例1:用max算字典key对应值最大的是多少
l=[3,2,100,999,213,1111,31121,333]
print(max(l))

dic={'k1':10,'k2':100,'k3':30}


print(max(dic))
print(dic[max(dic,key=lambda k:dic[k])])

结果:
31121
k3
100

#例2: 用map计算列表元素的幂次方
res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
    print(i)

输出
1
25
49
16
64

 

高阶函数

满足俩个特性任意一个即为高阶函数

1.函数的传入参数是一个函数名

2.函数的返回值是一个函数名

array=[1,3,4,71,2]

ret=[]
for i in array:
    ret.append(i**2)
print(ret)

#如果我们有一万个列表,那么你只能把上面的逻辑定义成函数
def map_test(array):
    ret=[]
    for i in array:
        ret.append(i**2)
    return ret

print(map_test(array))

#如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样

def map_test(array,func=lambda x: x**2):
    '''

    :param array:
    :param func: 处理函数,这里写了一个默认的匿名函数,返回一个数的平方
    :return:
    '''
    result = []
    for i in array:
        result.append(func(i))
    return result

a = [1,4,2,56,21,3,10]
print(map_test(a,lambda x:x+1))
print(map_test(a,lambda x:'偶数' if x % 2 else '奇数' ))

msg = 'sadnwqoiqwd'
print(map_test(msg,lambda x:x.upper()))
print(list(map(lambda x:x.upper(),msg))) #系统自带的map对象,作用跟map_test的作用一样,在python3中返回的是一个迭代器,所以说要list转换,在python2中返回的是一个list


输出的结果:
[2, 5, 3, 57, 22, 4, 11]
['偶数', '奇数', '奇数', '奇数', '偶数', '偶数', '奇数']
['S', 'A', 'D', 'N', 'W', 'Q', 'O', 'I', 'Q', 'W', 'D']
['S', 'A', 'D', 'N', 'W', 'Q', 'O', 'I', 'Q', 'W', 'D']
map
movie_people = ['sb_alex','sb_booble','sb_json','xieys','sb_qaz']

def filter_test(people_ls):
    '''
    过滤包含某个特性的值
    :param people_ls:
    :return:
    '''
    ret = []
    for i in people_ls:
        if not(i.startswith('sb')):
            ret.append(i)
    return ret

print(filter_test(movie_people))


movie_people = ['sb_alex','sb_booble','sb_json','xieys','sb_qaz']
movie_people1 = ['alex_sb','booble_sb','sb_json','xieys','sb_qaz']
def filter_test(func,array):
    ret = []
    for i in array:
        if not func(i):
            ret.append(i)
    return  ret

print(filter_test(lambda x:x.startswith('sb'),movie_people))
print(filter_test(lambda x:x.endswith('sb'),movie_people1))

print(list(filter(lambda x:not x.endswith('sb'),movie_people1))) #系统自带的filter功能,跟自己写的相反,如果不加not 这里取的就是结尾是sb的有哪些,
filter
num_l = [1,3,4,100]
def reduce_test(array):
    res = 0
    for num in array:
        res += num
    return res

print(reduce_test(num_l))

def reduce_test1(func,array,init=None):
    if init == None:
        res = array.pop(0)
    else:
        res = init
    for num in array:
        res = func(res,num)
    return res


print(reduce_test1(lambda x,y:x+y,num_l,10))
print(reduce_test1(lambda x,y:x+y,num_l))
print(reduce_test1(lambda x,y:x*y,num_l))

from functools import reduce
num_l = [1,3,4,100]
print(reduce(lambda x,y:x+y,num_l)) #系统自带的reduce函数
print(reduce(lambda x,y:x*y,num_l))
reduce
#当然了,map,filter,reduce,可以处理所有数据类型

name_dic=[
    {'name':'alex','age':1000},
    {'name':'wupeiqi','age':10000},
    {'name':'yuanhao','age':9000},
    {'name':'linhaifeng','age':18},
]
#利用filter过滤掉千年王八,万年龟,还有一个九千岁
def func(x):
    age_list=[1000,10000,9000]
    return x['age'] not in age_list


res=filter(func,name_dic)
for i in res:
    print(i)

res=filter(lambda x:x['age'] == 18,name_dic)
for i in res:
    print(i)


#reduce用来计算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))
print(reduce(lambda x,y:x+y,range(1,101)))

#用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb
name=['alex','wupeiqi','yuanhao']

res=map(lambda x:x+'_sb',name)
for i in res:
    print(i)
总结

 

内置函数

 

abs(-1)  -- > 结果为1

divmod(10,3)  --  >结果是(3,1)   把10除以3 得到的记过给一个元组,元组的第一个元素为商,第二个元素为余数

all([1,2,3,'']) -- > False,列表中所有的为True,返回值才为True

any([1,2,3,'']) -- > True,列表中只要有一个值为True,返回值就为True

bin(3) --- > 将3转换为二进制,结果为0b11
bool() --> 布尔值转换

bytes(‘你好’,encoding('utf-8')) -- > 把字符串按照指定的格式转换为字节码

dict() -- > 转换为字典

dif(object) --> 查看对象里的方法

enumerate(iter) --->用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
eval(str)  
  1、把字符串中的数据结构给提取出来
  2、将字符串中的表达式进行运算

filter() -- > 过滤某元素
float() --> 转换为浮点类型
format() --> 字符串格式化
frozenset() --> 不可变集合
globals --> 全局变量
#可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型
hash(str) -->传入 值计算出hash值返回
help(object) --> 查看对象的帮助文档
hex(x) -->  将十进制转换为16进制
oct(x) --> 将十进制转换为8进制
id(object)  -- > 打印对象的内存地址
input() -- > 等待用户输入
int() --> 转换为整型
isinstance(1,int) --> 判断1是不是int的实例,判断对象是那个类的实例
len() --> 对象的长度
list() --> 转换为列表
globals() --> 打印当前级别的所有全局变量
locals() --> 打印当前级别的所有局部变量
max(iter) ---> 取最大值,注意不同类型间不能比较,默认从第一个元素比较,第一个元素如果取出最大的,就不会比较后面的元素,如果第一个元素没有分出大小,继续往后比较,还是和之前一样,如果比较出大小就不再往后比较
l = [
    (5,'e'),
    (1,'a'),
    (3,'c')
]

print(max(l))
输出结果为 (5,'e')
也可以和zip结合使用比较字典value值,同时把key也打印出来
k = {
    'sda': 12,
    '23': 123
}
print(list(max(zip(k.values(),k.keys()))))
输出结果为 [123,'23']

更加高级的用法:
people = [
    {'name' : 'alex','age' : 10000},
    {'name' : 'qaz','age' : 9000},
    {'name' : 'qwe','age' : 10001},
    {'name' : 'asb','age' : 18},
]

print(max(people,key=lambda dic:dic['age']))

结果:
{'name': 'qwe', 'age': 10001}

min(iter) ---> 取最小值
zip(x,y) --->函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。 
chr() ---> 将asiic码转换为对应的字符
ord() ---> 将字符转换为对应的asiic码
pow(3,3) ---> 相当于3**3 ,如果有第三个参数如pow(3,3,2)相当于3**3%2
print() ---> 输出
range(100) --->可创建一个0-99整数列表,一般用在 for 循环中。
reversed() ---> 反转
set() ---> 转换为集合
slice() ---> 切片
sorted() ---> 排序,跟max,min的原理一样
例1
people = [
    {'name' : 'alex','age' : 10000},
    {'name' : 'qaz','age' : 9000},
    {'name' : 'qwe','age' : 10001},
    {'name' : 'asb','age' : 18},
]
print(sorted(people,key=lambda dic:dic['age']))
结果:
[{'name': 'asb', 'age': 18}, {'name': 'qaz', 'age': 9000}, {'name': 'alex', 'age': 10000}, {'name': 'qwe', 'age': 10001}]

例2
name_d = {
    'qaz':900,
    'qwda':300,
    'qwrewt':200
}
print(sorted(name_d.items(),key=lambda tup:tup[1]))
print(sorted(zip(name_d.values(),name_d.keys())))
结果:
[('qwrewt', 200), ('qwda', 300), ('qaz', 900)]
[(200, 'qwrewt'), (300, 'qwda'), (900, 'qaz')]

str() ---> 转换成字符串
sum() ---> 求和
tuple() ---> 转换为元组
type() --- > 查看数据类型
__import__() ---> 当导入文件为字符串时,用import不能直接导入,如要用__import__(字符串文件名)才能导入
import 调用sys操作系统,然后操作系统再调用__import__
解释

 

字典的运算:最小值,最大值,排序
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}

迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex'

可以取values,来比较
>>> max(salaries.values())
>>> min(salaries.values())
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao'



也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys()) 

先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, 'alex')


salaries_and_names是迭代器,因而只能访问一次
>>> min(salaries_and_names)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence



sorted(iterable,key=None,reverse=False)
View Code

 

posted @ 2019-09-04 16:38  Mr-谢  阅读(141)  评论(0)    收藏  举报