我们前面用的代码都是比较简单的脚本,而实际工作中是没有人把整个一个功能从头写到尾按顺序堆到一块的。一个规范的值得借鉴的Python程序,除非代码量很少(10行20行左右)应该由多个函数组成,这样的代码才更加的模块化、规范化

  函数的基础知识这里就不详细说明了,这里讲一些其他的内容!

一.多态

  我们先看一个这样的函数

def fun(a,b):
return a+b
print(fun(1,2))
print(fun('',''))

  运行后会发现效果是不一样的。Python不用考虑输入数据的类型,而是将其交给具体的代码去判断执行,同样一个函数可以同时用在int、str等数据类型的操作中。这种行为就称为多态。这也是Python和Java,C等很大的一个不同点。注意这是一个中性的特点,无所谓优略,但在必要时需要在开头加上数据的类型检查。

二.嵌套

  Python函数的另一大特性就是支持函数的嵌套

def fun1():
print('in fun1')
def fun2(): #fun2是嵌套在fun1内部的
print('in fun2')
fun2() fun1()

  这里再fun1内部定义了fun2,在调用fun1时,先打印‘in fun1’,然后fun1内部调用fun2,在打印‘in fun2’。这样做有什么好处呢?

  嵌套的优点

    1.函数的嵌套可以保证内部函数的隐私。内部函数只能被外部函数调用或访问,不会被暴露在全局作用域。如果函数内部有一些隐私数据(数据库的用户、密码等)不想被暴露在外部,就可以使用函数的嵌套。将其封装在函数内部,只通过外部函数来访问

def connect_DB():
def get_DB_configuration():
host = ''
username = ''
password = ''
return host,username,password
conn = connertor.connect(get_DB_configuration()) #这里所有的用户信息是不会被暴露出来的
return conn #函数只返回连接状态

  这里的get_DB_configuration()只能在connect_DB函数内部被调用,在全局内部是无法调用的。

    2.合理的使用函数的嵌套,能够提高程序的运行效率。比如我们想算一个数的阶乘,在计算前需要判定传递的参数是否合法

def factorial(input):
if not isinstance(input,int):
raise Exception('input must be an integer.')
if input < 0:
raise Exception('input must be greater or equal to 0') def inner_factorial(input):
if input <=1:
return 1
return input*inner_factorial(input-1)
return inner_factorial(input) print(factorial(3))

  这样通过函数的嵌套我们在检查数据的合法性时只执行了一次,而如果我们不用嵌套的化每次递归都要进行一次判定,会降低程序的运行效率。在工作中会经常遇到这种情况,那么运用嵌套就是非常必要的了。

三.函数变量作用域

  函数的变量作用域和其他语言类似,如果变量在函数内部,就是局部变量,只在函数内部有效,一旦函数执行完毕,局部变量就会被回收,无法访问。

  相对应的,全局变量则是定义在整个文件层次上的,例如这样

MAX = 10
MIN = 1
def fun():
if MAX > MIN:
print(MAX)
fun()

  但是我们不能随意改变变量的值,例如函数里出现这样就会报错

MAX = 10
MIN = 1
def fun():
MAX+=1
fun()
UnboundLocalError: local variable 'MAX' referenced before assignment

因为Python解释器会默认函数内部的变量为局部变量,调用时发现MAX并没有被声明,就会抛出异常。那如果我们在函数中定义了个变量名称和全局变量名字一样会怎么样呢?

A = 123
def fun():
A = 456
print('in fun A:{}'.format(A))
print('before call fun A:{}'.format(A))
fun()
print('after call fun A:{}'.format(A))
before call fun A:123
in fun A:456
after call fun A:123

结论

但还是要注意,在函数内如果先调用了全局变量是不能重新声明一个和它名字相同的变量的,也不能重新改变它的值。而假如需要对这个变量进行改变时,就需要加上关键字Global。

A = 123
def fun():
global A
print(A)
A = 456
print('in fun A:{}'.format(A))
print('before call fun A:{}'.format(A))
fun()
print('after call fun A:{}'.format(A))
before call fun A:123
123
in fun A:456
after call fun A:456

结论

  切记切记,这个方法一定要慎用。因为一旦函数被调用变量的值就会被更改。如果哪次在哪次调用中被修改成不需要的值,要追溯起来时相当麻烦的。

  还有就是嵌套函数,内部函数可以访问外部的变量而不能改变其值。要想改变值的话在内部函数用关键字nonlocal声明变量

def fun1():
x = 'local'
def fun2():
nonlocal x #一定要在一开始声明
print('before change x:{}'.format(x))
x = 'inside'
print('after change x:{}'.format(x))
fun2()
print('after call fun2 x:{}'.format(x))
fun1()
before change x:local
after change x:inside
after call fun2 x:inside

结论

四.闭包、闭包、闭包

  闭包(closure)是这节课里最重要却右不好理解的内容。闭包和嵌套类似,不过这里的外部函数返回的是一个函数而不是具体的值,返回的函数通常赋予一个变量,这个变量可以在后面被继续执行调用。

  举个例子,我们想计算一个数的n次幂,用闭包可以这么写

def nth_power(exponent):
def exponnet_of(base):
return base**exponent
return exponnet_of #返回值是一个函数
square = nth_power(2) #计算一个数的平方
cube = nth_power(3) #计算一个数的立方
print(square(3))
print(cube(3))

  这里的外部函数nth_power()的返回值是函数exponnet_of(),在执行完

square = nth_power(2)
cube = nth_power(3)

  以后外部函数的参数exponent是会被内部函数exponnet_of()记住的,之后我们调用时程序就能顺利的输出结果。

  这么看起来,我们也可以把程序写成这样的

def nth_power_rewrite(base,exponnet):
return base**exponnet

  其实也是可以的,但是使用了闭包可以使程序变得更简洁易读。比如我们需要算很多个数的平方,就成这样的了

不用闭包
res1 = nth_power_rewrite(1,2)
res2 = nth_power_rewrite(2,2)
res3 = nth_power_rewrite(3,2)
res4 = nth_power_rewrite(4,2)
#使用闭包
squre = nth_power(2)
res1 = square(1)
res2 = square(2)
res3 = square(3)
res4 = square(4)

  首先看来,闭包在每次调用函数时都少数如一个参数,更加简洁。

  其次,和前面的嵌套类似,函数开开始需要做一些额外的工作,而需要多次调用这个函数时,就可以把这些额外的工作放在外部函数中,可以减少多次调用导致的不必要的开销。

  另外一点以后会讲,闭包常常和装饰器(decorator)一起使用。

Python核心技术与实战——七|自定义函数的更多相关文章

  1. Python核心技术与实战——八|匿名函数

    今天我们来学习一下匿名函数.在学习了上一节的自定义函数后,是时候了解一下匿名函数了.他们往往非常简短,就一行,而且有个关键字:lambda.这就是弥明函数. 一.匿名函数基础 匿名函数的基本格式是这样 ...

  2. Python核心技术与实战 笔记

    基础篇 Jupyter Notebook 优点 整合所有的资源 交互性编程体验 零成本重现结果 实践站点 Jupyter 官方 Google Research 提供的 Colab 环境 安装 运行 列 ...

  3. Python核心技术与实战——十九|一起看看Python全局解释器锁GIL

    我们在前面的几节课里讲了Python的并发编程的特性,也了解了多线程编程.事实上,Python的多线程有一个非常重要的话题——GIL(Global Interpreter Lock).我们今天就来讲一 ...

  4. Python核心技术与实战——六|异常处理

    和其他语言一样,Python中的异常处理是很重要的机制和代码规范. 一.错误与异常 通常来说程序中的错误分为两种,一种是语法错误,另一种是异常.首先要了解错误和异常的区别和联系. 语法错误比较容易理解 ...

  5. python教程(三)·自定义函数

    前面介绍了如何使用函数,这一节我们就来学习怎么创建自己的函数! 自定义函数 创建函数非常简单,它使用关键字 "def",下面的代码创建了一个带有一个参数的函数,并使用不同的参数调用 ...

  6. Python核心技术与实战——二一|巧用上下文管理器和with语句精简代码

    我们在Python中对于with的语句应该是不陌生的,特别是在文件的输入输出操作中,那在具体的使用过程中,是有什么引伸的含义呢?与之密切相关的上下文管理器(context manager)又是什么呢? ...

  7. Python核心技术与实战——十六|Python协程

    我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多 ...

  8. Python核心技术与实战——十四|Python中装饰器的使用

    我在以前的帖子里讲了装饰器的用法,这里我们来具体讲一讲Python中的装饰器,这里,我们从前面讲的函数,闭包为切入点,引出装饰器的概念.表达和基本使用方法.其次,我们结合一些实际工程中的例子,以便能再 ...

  9. Python学习笔记(七)函数的使用

    python中的函数使用较简单,这里列出值得注意的几点:   内嵌函数   例如: # coding: utf-8 def foo(): def bar(): print 'bar() called. ...

随机推荐

  1. EDM邮件营销真的落伍了吗?

    很多朋友都觉得EDM邮件营销已经日暮西山了.难道EDM邮件营销真的落伍过时了吗?小编本文为大家讲解一下. 一.有数据为证:目前电子邮件仍然比较活跃,九成以上的用户每天至少查看一封邮件,并且6成以上的人 ...

  2. 关于db4o的透明激活与激活声明

    关于db4o的透明激活与激活声明 有关于透明激活,其介绍可以参看这里:http://www.cnblogs.com/redmoon/archive/2008/02/23/1078619.html 文中 ...

  3. 初识Nginx及其LNMP搭建

    Nginx介绍 nginx www服务软件 俄罗斯人开发 开源 性能很高 web产品 大小780k c语言开发 本身是一款静态www软件,不能解析php jsp .do 最大特点 静态小文件(1m), ...

  4. Jmeter之循环控制器

    在使用Jmeter测试时,部分接口需要循环执行多次,这时候就可以使用循环控制器去控制执行. 循环控制器如下图: 说明 : (1.名称:标识,建议明确此循环控制器的使用的作用是什么(如:登录循环控制) ...

  5. Selenium学习之==>Xpath使用方法

    一.什么是Xpath XPath是XML的路径语言,通俗一点讲就是通过元素的路径来查找到这个标签元素. 工具 Xpath的练习建议大家安装火狐浏览器后,下载插件,FireBug.由于最新版火狐不再支持 ...

  6. golang 千位分隔符

    项目需求将统计出的数字以千位分隔符分隔的形式展示(如将 1234567.89 格式化为 1,234,567.89),而 golang 的标准库中并无这样的函数. 万能的 google 找到解决办法,可 ...

  7. 几家大的券商的PB系统以及算法交易概况大致是怎样的?

    PB的定位是托管-清算-交易.目前的PB系统方面的竞争点主要放在了交易环节(毕竟托管和清算没有多大的差异).目前的pb交易环节的技术提供有恒生.讯投.金证.同花顺等,以满足私募及高净值个人多样化交易和 ...

  8. http层负载均衡之 haproxy实践篇

    方案 上篇文章讲到了负载均衡的相关理论知识,这篇文章我打算讲讲实践方法以及实践中遇到的问题 方案:haproxy http层负载均衡 安装一个haproxy服务,两个web服务 haproxy:192 ...

  9. awk结合数组统计

    1.统计用户登录类型 #!/bin/bashdeclare -A  shells (定义关联数组shells)while read ll   (读取/etc/passwd,ll为变量) dotype= ...

  10. maven spark Scala idea搭建maven项目的 pom.xml文件配置

    1.pom.xml文件配置,直接上代码. <?xml version="1.0" encoding="UTF-8"?> <project xm ...