python之函数

def get_host():
    创建数据库连接
    通过cursor方法获取游标
    通过execute对sql进行操作
    关闭游标

def get_item():
    创建数据库连接
    通过cursor方法获取游标
    通过execute对sql进行操作
    关闭游标

def get_tirggers():
    创建数据库连接
    通过cursor方法获取游标
    通过execute对sql进行操作
    关闭游标
复制代码

完全可以按照上面的方式操作数据库,但是这样写存在两个问题:

  1.代码重复过多

  2.如果日后要更改操作数据库,比较麻烦

复制代码
def con_sql(sql):
    创建数据库连接
    通过cursor方法获取游标
    通过execute对sql进行操作
    关闭游标

def get_host(host):
    conn_sql(host)

def get_item(item):
    conn_sql(item)

def get_tirggers(triggers):
    conn_sql(triggers)
复制代码

这样写可以体现出函数的好处:

  1.解决了代码重用的问题

  2.保持代码一致性,易维护

  3.容易扩展

在此处提下函数式编程和面向过程编程的区别:

  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”

函数的定义及各部分详解:

复制代码
def test(x):
    '''
    :param x:传入参数是干啥的呀
    :return: 返回的是啥呀
    '''
    x+=1
    return x

test(4)

def:定义函数的关键字
test:函数名
():括号内可以定义形参
""" """:函数描述(建议写上)
x+=1:函数的逻辑程序
return : 定义返回值
test(4) : 函数名(参数): 调用运行,这里的x可以带参数,也可以不带的
复制代码

第二:函数的三种定义方式

无参函数定义:

复制代码
def hello():
    print("hello world")

#调用也不需要传参
hello()

#输出结果:
hello world
复制代码

有参函数定义:

复制代码
def hello(x,y):
    print("hello world",x,y)

#调用也不需要传参
hello("zzl","cyy")

#输出结果:
hello world zzl cyy
复制代码

空函数定义:

复制代码
def foo():
    '''
    :return: 
    '''
    pass

foo()
复制代码

空函数写不写参数是无所谓的,空函数主要用于开发大的程序的时候定义

空函数的好处是:

1.理清逻辑

2.哪一个模块有灵感就写哪一个模块

3.当你与你同事共同开发的该程序,你同事没有完成,你可以做一个判断,不影响你的工作

第三:函数的返回值

返回0个值---》None

复制代码
def foo():
    return
    
print(foo())

返回结果:
None
复制代码

返回一个值---》返回的是return后定义的哪一个值

def foo():
    return "hello world"

print(foo())
返回结果:
hello world

返回多个值---》返回的是一个元组

def foo():
    return 1,2

print(foo())
返回结果:
(1, 2)

返回值可以是任何类型

def foo():
    return 1,2,[3,4]

print(foo())
返回结果:
(1, 2, [3, 4])

第四:函数三种调用方式

作为语句形式的调用

def my_max(x,y):
    return x if x > y else y
#语句形式:用于没有返回值的形式

my_max(1,2)

作为表达式形式的调用

复制代码
def my_max(x,y):
    return x if x > y else y
#表达式形式
res=my_max(1,2)
print(res)

结果:
2
复制代码

作为参数形式的调用

复制代码
def my_max(x,y):
    return x if x > y else y

res=my_max(20,my_max(11,18))
print(res)

结果:
20
复制代码

第五:函数的形参与实参

复制代码
#形式参数:x,y,形式参数不占用内存空间,只有真正传值得时候才占用内存空间
def foo(x,y):
    print(x)
    print(y)

#实际参数1,2,实际参数是真正占用内存空间的
foo(1,2)

#注:在python中,名字没有任何储值的功能,任何的储值都是绑定一个名字到一个值
复制代码
复制代码
def foo(x,y):
    return x+y

#实际参数1,2,实际参数是真正占用内存空间的
foo(1,2)

#注:在python中,名字没有任何储值的功能,任何的储值都是绑定一个名字到一个值

#参数的动态性:
print(foo(1,2))
#结果:3
print(foo('a','b'))
#结果:ab
print(foo(1,'a'))
#报错了
TypeError: unsupported operand type(s) for +: 'int' and 'str'
复制代码

怎么解决这样的问题?

有一下三种方式:

复制代码
第一种:加上帮助信息,这样其他人用函数的时候,就知道怎么去调用了,但是不能真正的对函数做到限定作用

def foo(x,y):
    '''
    :param x:int
    :param y:int
    :return:int
    '''
    return x+y

print(help(foo))

foo(x, y)
    :param x:int
    :param y:int
    :return:int

第二种:
def foo(x,y):
    if type(x) is int and type(y) is int: #给核心功能附加程序
        return x+y

print(foo(1,2))

第三种:更加妖娆:
def foo(x:int,y:int)->int:
    return x+y
print(foo.__annotations__)
print(foo(1,2))

结果:
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
3

综合以上三种方式:用第一种方式,最后在加上异常处理为标志用法,其他两种也可以用,凭自己个人感觉哈
复制代码

参数的具体使用:

实参应用:

按位置传值:

复制代码
# 实参:
def foo(x,y):
    print(x)
    print(y)
# 按位置传值
foo(4,5)

结果:
4
5
复制代码

按关键字传值:

复制代码
def foo(x,y):
    print(x)
    print(y)
# 按关键字传值
foo(y=8,x=6)

结果
6
8
复制代码

注意问题:

1.针对同一个形参,你可以按照位置或者按照关键字传值,但是只能用一种方式,不能给同一个形式参数传值

2.按关键字传值,必须在按位置传值右边

形参具体使用:

位置参数:

复制代码
def foo(x,y,z):
    print(x)
    print(y)
    print(z)
#位置参数:必须传值
foo(1,2,3)

输出结果:
1
2
3
复制代码

默认参数:

复制代码
#默认参数
def foo(x,y=6):
    print(x)
    print(y)
foo(1)
foo(1,8)
foo(x=1,y=10)

结果:
1
6

1
8

1
10

注意:默认参数可以不传值,但是也可以传值,传值得话,会覆盖默认参数的值,也可以按照关键字的方式传值。

默认参数的用途:

比如:我们部门男人很多
1.变化比较小的定义为默认参数
2.默认参数必须在位置参数和的右边
3.默认参数一定要定义成一个不可变的类型
4.默认参数在定义的时候已经被赋予了一个明确的值了,后期变化对其无效
验证1,2
def registor(user,age,gender='male'):
    print(user)
    print(age)
    print(gender)

registor('zzl',18)

结果:
zzl
18
male

验证3:
def foo(x,l=[]):
    l.append(x)
    return l

print(foo(1))
print(foo(2))
print(foo(3))

结果:
[1]
[1, 2]
[1, 2, 3]
他们每一次调用都指向同一块内存地址

验证4:
name='lxh'
def foo(x,y=name):
    print(x)
    print(y)
name='xhb'
print(foo(1))
复制代码

默认参数的好处:

1.降低了函数调用的复杂度

2.可用来扩展函数功能

*args可变参数

  •  *的作用是‘监听’位置参数,*args等待接收的参数必须是安位置来的
  •  凡是遇到带*的参数,那么我们就把它看作是位置参数,把它打散了来看
复制代码
基本形式:
def func(name,age,*args):
    print(name)
    print(age)
    print(args)

func('cy',18,'student')

输出结果:
cy
18
('student',)

如果要求传入的参数为列表的情况
def func(name,age,*args):
    print(name)
    print(age)
    print(args)

func('cy','18',*['student','lawyer'])
结果输出:
cy
18
('student', 'lawyer')
复制代码

**kwargs关键字参数

复制代码
基本形式
def foo(x,y,**kwargs):
    print(x)
    print(y)
    print(kwargs)

foo(1,l=2,y=3,z=1,c=2)

结果输出:
1
3
{'l': 2, 'z': 1, 'c': 2}

传入的参数为字典
def foo(x,y,z):
    print(x)
    print(y)
    print(z)

foo(**{'x':1,'z':3,'y':2}) # foo(x=1,z=3,y=2)

结果输出:
1
2
3

结合*args
def foo(x,y,*args,**kwargs):
    print(x)
    print(y)
    print(args)
    print(kwargs)

foo(1,3,*[6,8,9],c=10,l=12)

#输出结果:
1
3
(6, 8, 9)
{'c': 10, 'l': 12}
复制代码

总结:以上四种参数的顺序:位置参数,*args,默认参数,**kwargs

第六:局部变量与全局变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量重名时:在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
复制代码
 1 全局变量
 2 msg='hello world'
 3 
 4 def foo():
 5     print(msg)
 6 
 7 foo()
 8 
 9 输出结果:
10 hello world
11 
12 局部变量
13 def foo():
14     msg='hello world'
15     print(msg)
16 foo()
17 
18 输出结果:
19 hello world
20 
21 msg='hello msg'
22 def foo():
23     msg='hello world'
24     print(msg)
25 foo()
26 print(msg)
27 
28 输出结果:
29 hello world
30 hello msg
31 
32 msg='hello msg'
33 def foo():
34     global msg #定义的是全局变量
35     msg='hello world'
36     print(msg)
37 foo()
38 print(msg)
39 
40 #输出结果:
41 hello world
42 hello world
复制代码

第七:函数的递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自己本省,这个函数就叫递归函数。

列举两个递归查询的例子

复制代码
 1 def foo(n):
 2     print(n)
 3     if int(n/2) == 0:
 4         return n
 5     return foo(int(n/2))
 6 
 7 foo(20)
 8 
 9 输出结果:
10 20
11 10
12 5
13 2
14 1
15 
16 def fact(n):
17     print(n)
18     if n == 1:
19         return 1
20     return n * fact(n - 1)
21 
22 fact(6)
23 输出结果:
24 6
25 5
26 4
27 3
28 2
29 1
复制代码

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

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

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

栈溢出示例:

 View Code

怎样解决这样的问题?

解决递归调用栈溢出的方法是通过尾递归优化,尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的

尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况 ,后续详解,尾调用与尾递归

第八:嵌套函数

函数的嵌套通俗的理解为函数套函数就ok了

函数嵌套的定义:

复制代码
1 def func1():
2     def func2():
3         print("my name is func2")
4     func2()
5 func1()
6 
7 #输出结果:
8 my name is func2
复制代码

函数嵌套的调用:

复制代码
def my_max1(x,y):
    return x if x > y else y

def my_max2(a, b, c, d):
    return my_max1(my_max1(my_max1(a,b),c),d)

print(my_max2(100,200,80,120))

输出结果:
200
复制代码
复制代码
#结合嵌套函数再看全局变量,与局部变量
msg='zzl'
def func1():
    msg='cyy'
    def func2():
        msg='cy'
        def func3():
            print(msg)
        return func3
    return func2

func1()()()

输出结果:
cy
复制代码

第九:函数是第一类对象

在python中所有的名字都没有储值功能

函数是第一类对象指的是:函数可以被当做数据来处理

被引用

def foo():
    print("cyy")
f1=foo
f1()
# 输出结果:
cyy

可以当做参数

复制代码
def foo():
    print("cyy")

def func(msg):
    print(msg)
    msg()

func(foo)
输出结果:
<function foo at 0x00000000020D3E18>
cyy
复制代码

可以当做返回值

复制代码
def foo():
    print("cyy")

def func(msg):
    return msg

f=func(foo)
print(f)
f()
输出结果:
<function foo at 0x0000000002423E18>
cyy
复制代码

可以当做容器类型的一个元素

复制代码
def foo():
    print("cyy")

func_dic={
    'foo':foo
}
num=func_dic['foo']
num()
输出结果: cyy
复制代码

第十:匿名函数

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

1.lambda

复制代码
def calc(n):
    return n**n
print(calc(10))

#换成匿名函数
calc = lambda n:n**n
print(calc(10))

# 输出结果:
# 10000000000
# 10000000000
复制代码

2.map结合lambda

复制代码
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
复制代码

 总结:

复制代码
#当然了,map,filter,reduce,可以处理所有数据类型

name_dic=[
    {'name':'zzl','age':1000},
    {'name':'cyy','age':10000},
    {'name':'zl','age':9000},
    {'name':'cy','age':18},
]
#利用filter过滤掉1000,10000,9000
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来处理字符串列表啊,把列表中所有人都变成success,比方zzl_success
name=['zzl','cyy','zl']

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

输出结果:

{'age': 18, 'name': 'cy'}
{'age': 18, 'name': 'cy'}
5050
5050
zzl_success
cyy_success
zl_success

复制代码

第十一:高阶函数

满足一下一个特性都可称为高阶函数

  把一个函数的内存地址当做一个参数传到另一个函数

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

def add(x,y,f):
   print(f(x)+f(y))

add(-5,9,abs)
输出结果:
14

第十二:内置函数介绍

posted @ 2021-04-21 09:17  qwett1  阅读(119)  评论(0)    收藏  举报