内容目录:

1. 函数基本语法及特性

2. 参数与局部变量

3. 返回值

4.嵌套函数

5.递归

6.匿名函数

7.函数式编程介绍

8.高阶函数

9.内置函数

1.函数基本语法及特性

背景提要

现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你写出了以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while True
    if cpu利用率 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
     
    if 硬盘使用空间 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
     
    if 内存占用 > 80%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接

上面的代码实现了功能,但是这个重复代码太多了,每次报警都要重写一段发邮件的代码,太low了,这样干存在2个问题:

  1. 代码重复过多
  2. 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍

如何改动:其实很简单,只需要把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def 发送邮件(内容)
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接
     
while True
     
    if cpu利用率 > 90%:
        发送邮件('CPU报警')
     
    if 硬盘使用空间 > 90%:
        发送邮件('硬盘报警')
     
    if 内存占用 > 80%:
        发送邮件('内存报警')

函数是什么?

函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。

定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

特性:

  1. 减少重复代码
  2. 使程序变的可扩展
  3. 使程序变得易维护

语法定义

1
2
3
4
def sayhi():#函数名
    print("Hello, I'm nobody!")
 
sayhi() #调用函数

可以带参数

1
2
3
4
5
6
7
8
9
10
11
12
13
#下面这段代码
a,b = 5,8
= a**b
print(c)
 
 
#改成用函数写
def calc(x,y):
    res = x**y
    return res #返回函数执行结果
 
= calc(a,b) #结果赋值给c变量
print(c)

2.函数参数与局部变量  

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

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

默认参数

看下面代码

1
2
3
4
5
6
7
8
9
10
def stu_register(name,age,country,course):
    print("----注册学生信息------")
    print("姓名:",name)
    print("age:",age)
    print("国籍:",country)
    print("课程:",course)
 
stu_register("王山炮",22,"CN","python_devops")
stu_register("张叫春",21,"CN","linux")
stu_register("刘老根",25,"CN","linux")

发现 country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是 中国, 这就是通过默认参数实现的,把country变成默认参数非常简单

1
def stu_register(name,age,course,country="CN"):

这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。

另外,你可能注意到了,在把country变成默认参数后,我同时把它的位置移到了最后面,为什么呢?  

关键参数

正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可,但记住一个要求就是,关键参数必须放在位置参数之后。

1
stu_register(age=22,name='Yang',course="python",)

  

非固定参数

若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数

1
2
3
4
5
6
7
8
9
10
def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式
    print(name,age,args)
 
stu_register("Yang",22)
#输出
#Yang 22 () #后面这个()就是args,只是因为没传值,所以为空
 
stu_register("Jack",32,"CN","Python")
#输出
# Jack 32 ('CN', 'Python')

还可以有一个**kwargs

1
2
3
4
5
6
7
8
9
10
def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
    print(name,age,args,kwargs)
 
stu_register("Yang",22)
#输出
#Yang 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
 
stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#输出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

局部变量  

1
2
3
4
5
6
7
8
9
10
11
name = "Yang "
 
def change_name(name):
    print("before change:",name)
    name = "杨"
    print("after change", name)
 
 
change_name(name)
 
print("在外面看看name改了么?",name)

输出

1
2
3
before change: Yang 
after change 杨
在外面看看name改了么? Yang 

全局与局部变量

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

3.返回值  

要想获取函数的执行结果,就可以用return语句把结果返回

注意:

  1. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
  2. 如果未在函数中指定return,那这个函数的返回值为None

总结:

1、一旦你的函数经过调用并开始执行,那你的函数外部的程序,就没有办法再控制函数的执行过程了、 此时外部程序只能安静的等待函数的执行结果,为啥要等待函数结果,因为外部程序要根据函数的执行结果来决定下一步怎么走。这个执行结果就是以return的形式返回给外部程序。
2、return代表着一个函数的结束。
3、return可以返回任意数据类型。
4、对于用户角度,函数可以返回任意数量的值,但对于python本身来讲函数只能返回一个值(元组的形式)。

4.嵌套函数  

看上面的标题的意思是,函数还能套函数?of course

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
name = "Yang"
 
def change_name():
    name = "Yang2"
 
    def change_name2():
        name = "Yang3"
        print("第3层打印",name)
 
    change_name2() #调用内层函数
    print("第2层打印",name)
 
 
change_name()
print("最外层打印",name)

此时,在最外层调用change_name2()会出现什么效果?

没错, 出错了.

  

5. 递归

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

1
2
3
4
5
6
7
8
9
10
11
12
13
def calc(n):
    print(n)
    if int(n/2==0:
        return n
    return calc(int(n/2))
 
calc(10)
 
输出:
10
5
2
1

递归特性:

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

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

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

堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html 

递归函数实际应用案例,二分查找

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,66)

6. 匿名函数

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

1
2
3
4
5
6
7
8
#这段代码
def calc(n):
    return n**n
print(calc(10))
 
#换成匿名函数
calc = lambda n:n**n
print(calc(10))

你也许会说,用上这个东西没感觉有毛方便呀, 。。。。呵呵,如果是这么用,确实没毛线改进,不过匿名函数主要是和其它函数搭配使用的呢,如下

1
2
3
res = map(lambda x:x**2,[1,5,7,4,8])
for in res:
    print(i)

输出

1
25
49
16
64

7.函数式编程介绍  

 

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。

Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

一、定义

简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。

主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式:

  (1 + 2) * 3 - 4

传统的过程式编程,可能这样写:

  var a = 1 + 2;

  var b = a * 3;

  var c = b - 4;

函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:

  var result = subtract(multiply(add(1,2), 3), 4);

这段代码再演进以下,可以变成这样

add(1,2).multiply(3).subtract(4)

这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:

merge([1,2],[3,4]).sort().search("2")

因此,函数式编程的代码更容易理解。

要想学好函数式编程,不要玩py,玩Erlang,Haskell, 好了,我只会这么多了。。。

8.高阶函数

变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

1
2
3
4
5
6
def add(x,y,f):
    return f(x) + f(y)
 
 
res = add(3,-6,abs)
print(res)

9. 内置参数  

python 自动化之路 day 04的更多相关文章

  1. python 自动化之路 day 04.1 python内置函数

    总结一下内置函数,Build-in Function. 一.数学运算类 abs(x) 求绝对值 complex([real[, imag]]) 创建一个复数 divmod(a, b) 分别取商和余数注 ...

  2. python 自动化之路 day 05

    内容目录: 列表生成式.迭代器&生成器 装饰器 软件目录结构规范 模块初始 常用模块 1.列表生成式,迭代器&生成器 列表生成式 需求:列表[0, 1, 2, 3, 4, 5, 6, ...

  3. python 自动化之路 day 09 进程、线程、协程篇

    本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者 ...

  4. python 自动化之路 day 08 面向对象进阶

    面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 面向对象高级语法部分 经典类vs新式类 把下面代码用python2 和python3都执行一下 1 2 ...

  5. python 自动化之路 logging日志模块

    logging 日志模块 http://python.usyiyi.cn/python_278/library/logging.html 中文官方http://blog.csdn.net/zyz511 ...

  6. PYTHON 自动化之路 (二)

    一.python 模块的使用 模块的使用: import os #调用 os 模块 cmd_s = os.popen("dir").read() #打开路径为结果保存为cmd_sp ...

  7. python 自动化之路 day 00 目录

    目录 初识Python Python基本数据类型 Python基础之函数 Python基础之杂货铺 模块 面向对象 网络编程 HTML CSS JavaScript DOM jQuery Web框架本 ...

  8. python 自动化之路 day 10 协程、异步IO、队列、缓存

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 RabbitMQ队列 Redis\Memcached缓存 Paramiko SSH Twsited网络框架 引子 到目 ...

  9. python 自动化之路 day 01 人生若只如初见

    本节内容 Python介绍 发展史 Python 2 or 3? 安装 Hello World程序 Python 注释 变量 用户输入 模块初识 .pyc是个什么鬼? 数据类型初识 数据运算 表达式i ...

随机推荐

  1. XMPP——Smack[2]会话、消息监听、字体表情和聊天窗口控制

    连接之后,拿到了connection,通过它可以搞定会话 建立一个会话 MessageListener msgListener = new MessageListener() { public voi ...

  2. 安装Intel HAXM为Android 模拟器加速,30秒内启动完成

    要求 必备知识 windows 7 基本操作. 运行环境 windows 7(64位); Android Studio 1.1.0;JDK 1.7.0_75(64位);android-sdk_r24 ...

  3. SQL索引详解

    转自:http://www.cnblogs.com/AK2012/archive/2013/01/04/2844283.html SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可 ...

  4. 匿名内部类new Runnable()

    匿名内部类(Anonymous Inner Class),在创建实例的同时给出类的定义,所有这些在一个表达式中完成. Java code? 1 2 3 4 Runnable rn = new Runn ...

  5. [Practical Git] Compare file changes with git diff

    It can be helpful to see the changes between two sets of code; git diff lets us do this by comparing ...

  6. NSURLSession、NSURLConnection

    NSURLSesstion GET方法 block回调方法NSString * urlStr = @"http://192.168.1.247:8100/stream?cname=cha_2 ...

  7. 谈谈MVVM和链式网络请求架构

    前言 前一段时间一直在学习iOS的架构.为什么呢? 公司的架构一直是MVC,当我们正式上线的时候,项目已经有了超十万行代码.主要的VC一般都有2000行代码以上. 关键是,目前版本我们只做了三分之一的 ...

  8. fedora 23中配置nfs-server

    fedora 23中配置nfs-server */--> fedora 23中配置nfs-server Table of Contents 1. 产考资料 2. NFS配置文件 2.1. /et ...

  9. 输入参数varargin

    一种特别的输入参数varargin 可以在自定义函数中得到,这种函数支持输入参数的变量的个数.这个参数显在输入参数列表的最后一项,它返回一个单元阵列,所以一个输入实参可以包括任意数目的实参.每一个实参 ...

  10. dig命令浅析

    dig命令,功能更强大的命令. man dig dig [@server] [-b address] [-c class] [-f filename] [-k filename] [-m] \ [-p ...