python函数

编程方法

面向对象               独门秘籍:类      class
面向过程               独门秘籍:过程    def
函数式编程             独门秘籍:函数    def

函数定义

1、数学函数:
x是自变量,y是因变量;自变量的函数x的取值范围叫做这个函数的定义域;x的变化会引起y的变动。

2、函数式编程:
函数是把逻辑结构化和过程化的一种编程方式。逻辑是指你写一个购物车作业,先画一个流程图,也就是在画逻辑。
函数式编程就是:先定义一个数学函数,然后按照这个数学模型用编程语言去实现它。
3、python中的函数定义方法:

    def test01(x):                             #def是定义函数的关键字;test是函数名;括号内是可定义形参;
            "the function definitions"  #""里边是描述
            x += 1                                  #泛指代码块或程序处理逻辑
            return x                              #定义返回值

4、面向过程和函数式编程的区别之处
定义函数

def test1():
    '''test1'''
    print("test1")
    return 0             #有返回值

定义过程

def test02():
    '''test02'''
    print("test02")             #没有返回值

函数调用

test1()    #()代表调用test1函数;括号内可以有参数 也可以没有。
x=test1()
print(x)
结果:
test1
0

过程调用

y=test02()
print(y)
结果:
test02
None

总结:面向过程和函数式编程的区别:
相同之处:都可以被调用
不通之处:过程没有返回值;函数有返回值。
python中的面向过程,系统会默认返回一个None。

函数的三个特点

为什么使用函数,没有函数的编程只是在写逻辑(功能),想脱离函数,重用逻辑,唯一的办法就是拷贝。
例1:

with open("test01","a") as f:
    f.write('this is a stop')

现在有三个函数,每个函数在处理完自己的逻辑后,都需要使用上面的逻辑,那么唯一的办法就是拷贝三次逻辑;

def test1():
    print("this is test1")
    with open("test01", "a") as f:
        f.write("stop stop")
def test02():
    print("this is test02")
    with open("test01", "a") as f:
        f.write("stop stop")
def test3():
    print("this is test3")
    with open("test01", "a") as f:
        f.write("stop stop")
执行:
test1()
test02()
test3()

例2:优化后的,重复利用逻辑

def logger():
    with open("test01","a") as f:
        f.write('this is a stop\n')
def test1():
    print("this is test1")
    logger()
def test02():
    print("this is test02")
    logger()
def test3():
    print("this is test3")
    logger()
执行:
test1()
test02()
test3()

例:3:打印的时候加上时间,可扩展

import time
time_format = "%Y-%m-%d %X"
time_now = time.strftime(time_format)
def logger():
    with open("test01","a") as f:
        f.write('\n%s this is a stop\n'%time_now)
def test1():
    print("this is test1")
    logger()
def test02():
    print("this is test02")
    logger()
def test3():
    print("this is test3")
    logger()
执行:
test1()
test02()
test3()

总结 函数的三个优点
1.代码重用
2.保持一致性
3.可扩展性

函数返回值

def abc1():
        print("aaaaaaa:")
        return 0                  #return 结束逻辑;后边的代码不执行;
        print("bbbbbbb:")
def abc2():
        print("aaaaaaa:")
def abc3():
        print("aaaaaaa:")
        return 1,"hello",["a","b","c"],{"aaa":111}

x = abc1()                   #x接收的是abc函数的返回值0;
y = abc2()
z = abc3()
print(x)                     #return 结束逻辑;后边的代码不执行;
print(y)
print(z)

'''
输出:
aaaaaaa:
aaaaaaa:
aaaaaaa:
0
None
(1, 'hello', ['a', 'b', 'c'], {'aaa': 111})
'''

函数返回值总结
1.没有return返回值:返回None
2.return返回一个值:返回object (object就是你定义的返回值;python中的所有数据类型都是对象)
3.return返回多个值:返回tuple (元组形式返回)
为什么要有返回值?
因为想知道这个函数的执行结果是否成功,然后再进行下一步操作。

函数参数

1、形参和实参
形参定义:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时候接收实参;
实参定义:实际参数,调用函数时传给函数的参数,可以是常量、变量、表达式、函数、传给形参;
2、位置参数和关键字参数
位置参数和形参要一一对应;
位置参数和关键数同时存在的时候,关键参数不能写在位置参数前面;

def test01(x,y):          #x和y是形参
    print(x)
    print(y)

test01(1,2)              #1和2是实参;位置参数和形参要一一对应;
test01(x=1,y=2)      #关键参数与形参顺序无关;
                               #位置参数和关键数同时存在的时候,关键参数不能写在位置参数前面;

3、默认参数
特点:调用函数的时候,默认参数可有可无;
用途:默认安装值(例如安装软件的时候,设置默认安装路径;默认数据库端口值)

def moren(x,y=6):       #y=6 是默认参数
    print(x)
    print(y)
moren(5)
输出:
5
6

4、参数组
当实参不固定的时候,形参如何定义;
参数组1: 多个实参对应形参

def canshuzu(*args):        # *代表接收的参数是不固定的;*args把实参变成了一个元组;
    print(args)
canshuzu(1,2,3,4,5)
'''
输出:(1, 2, 3, 4, 5)
'''

参数组2:形参和参数组结合

def canshuzu2(x,*args):
    print(x)
    print(args)
canshuzu2(1,2,3,4,5)
'''
输出:
1
(2, 3, 4, 5)
'''

参数组3:把关键字参数转换成字典格式输出
#*args:接收n个位置参数,转换成元组的形成
#**kwargs: 把n个关键字参数转换成字典方式

def canshuzu4(**kwargs):
    print(kwargs)
    print(kwargs['name'])
canshuzu4(name="aaa",age=111)
输出:
{'name': 'aaa', 'age': 111}
aaa
canshuzu4(**{"name":"aaa","age":222})
输出:
{'name': 'aaa', 'age': 222}
aaa

def canshuzu5(name,age=12,*args,**kwargs):
    print(name)
    print(age)
    print(*args)
    print(kwargs)
canshuzu5("aaa",age=22,job="it",)
输出:
aaa
22
               #空的元组
{'job': 'it'}

函数局部变量和全局变量

namename = "AABBCC"                 #全局变量
def jubu(name):
    namename = "aabbcc"               #局部变量
    print("before change",name,namename)
    name = "ABC"                    #这里的name是局部变量,这个函数就是这个变量的作用域;
    print("after change",name)

name = "abc"                        #全局变量

jubu(name)                           #执行函数后的结果
print(name)                          #此处没有执行函数,直接调用变量
print(namename)                      #此处没有执行函数,直接调用变量
'''
输出:
before change abc aabbcc
after change ABC
abc
AABBCC
'''

总结

局部变量:在子程序中(函数)定义的变量称为局部变量。
                    局部变量作用域是该变量的子程序;
全局变量:在程序的一开始定义的变量称为全局变量。
                    全局变量作用域是整个程序;
当全局变量和局部变量同名时:
        当定义局部变量的子程序内,局部变量起作用;其他地方全局变量起作用。
        字符串和整数 在局部变量情况下是不能修改全局变量的值;要想改变在局部变量前加global;
        除了字符串和整数、元组以外高级点的类型(列表、字典、集合、类),局部变量可以改变全局变量的值;
 例子:设置局部变量修改全局变量
namename = "AABBCC"
def jubu(name):
    global namename                 #设置局部变量修改全局变量
    namename = "aabbcc"
    print("before change",name,namename)
    name = "ABC"                    #这里的name是局部变量,这个函数就是这个变量的作用域;
    print("after change",name)
name = "abc"
jubu(name)
print(name)
print(namename)
输出:
before change abc aabbcc
after change ABC
abc
aabbcc

函数-递归

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

递归特性
1.必须有一个明确的结束条件;
2.每次进入更深一层递归时,问题规模相比上次递归都应有所减少;
3.递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
4.最大的递归层次是999层,超过 就报错;
简单的递归例子

def digui(n):
    print(n)
    return digui(n)
dict(0)                 #0是为了查看递归的次数,递归的次数最大为997次;然后就报错了

简单的递归例子2

def digui2(n):
    print(n)
    if int(n/2) >0:
        return digui2(int(n/2))
    print(n)
digui2(10)
输出:
10
5
2
1
1

高阶函数

定义
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这就叫做高阶函数。

例如:
def add(x,y,z):
    return z(x) + z(y)
result = add(3.3,-6,abs)     #abs()      查看绝对值,是一个内置函数。
print(result)
输出:
9.3

扩展:

装饰器:http://blog.51cto.com/506554897/1963710
生成器:http://blog.51cto.com/506554897/1963775
迭代器:http://blog.51cto.com/506554897/1963780





     本文转自506554897 51CTO博客,原文链接:http://blog.51cto.com/506554897/2070296,如需转载请自行联系原作者


上一篇:基于ECS快速搭建Docker环境


下一篇:如何本地安装ApiPost接口调试工具