python 基础篇 自定义函数
多态
我们可以看到,Python 不用考虑输入的数据类型,而是将其交给具体的代码去判断执行,同样的一个函数(比如这边的相加函数 my_sum()
),可以同时应用在整型、列表、字符串等等的操作中。
在编程语言中,我们把这种行为称为多态
。这也是 Python 和其他语言,比如 Java、C 等很大的一个不同点。当然,Python 这种方便的特性,在实际使用中也会带来诸多问题。因此,必要时请你在开头加上数据的类型检查。
def my_sum(a, b):
if type(a) == type(b):
if isinstance(a, (int, str, list)):
return a + b
else:
raise Exception("input is not int/str/list")
else:
raise Exception("input type is not same")
print(my_sum(3, 5))
# 输出
# 8
print(my_sum([1, 2], [3, 4]))
# 输出
# [1, 2, 3, 4]
print(my_sum('hello ', 'world'))
# 输出
# hello world
print(my_sum([1, 2], 'hello'))
# 输出
# input type is not same
函数嵌套
Python 函数的另一大特性,是 Python 支持函数的嵌套。所谓的函数嵌套,就是指函数里面又有函数,比如:
def f1():
print('hello')
def f2():
print('world')
f2()
f1()
# 输出
hello
world
嵌套带来的好处
函数的嵌套能够保证内部函数的隐私。
内部函数只能被外部函数所调用和访问,不会暴露在全局作用域,因此,如果你的函数内部有一些隐私数据(比如数据库的用户、密码等),不想暴露在外,那你就可以使用函数的的嵌套,将其封装在内部函数中,只通过外部函数来访问。比如:
def connect_DB():
def get_DB_configuration():
...
return host, username, password
conn = connector.connect(get_DB_configuration())
return conn
这里的函数
get_DB_configuration
是内部函数,它无法在 connect_DB() 函数以外被单独调用。也就是说,下面这样的外部直接调用是错误的:get_DB_configuration() # 输出
NameError: name 'get_DB_configuration' is not defined
合理的使用函数嵌套,能够提高程序的运行效率。
看下面这个例子:
def factorial(input):
# validation check
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(5))
这里,我们使用递归的方式计算一个数的阶乘。因为在计算之前,需要检查输入是否合法,所以写成了函数嵌套的形式,这样一来,输入是否合法就只用检查一次。而如果我们不使用函数嵌套,那么每调用一次递归便会检查一次,这是没有必要的,也会降低程序的运行效率。
实际工作中,如果你遇到相似的情况,输入检查不是很快,还会耗费一定的资源,那么运用函数的嵌套就十分必要。
函数变量作用域
局部变量优先级高于全局变量
如果遇到函数内部局部变量和全局变量同名的情况,那么在函数内部,局部变量会覆盖全局变量,比如下面这种:
MIN_VALUE = 1
MAX_VALUE = 10
def validation_check(value):
MIN_VALUE = 3
...
这里
MIN_VALUE=3
不能在函数内部随意改变全局变量的值
MIN_VALUE = 1
MAX_VALUE = 10
def validation_check(value):
...
MIN_VALUE += 1
...
validation_check(5)
如果运行这段代码,程序便会报错:
UnboundLocalError: local variable 'MIN_VALUE' referenced before assignment
这是因为,Python 的解释器会默认函数内部的变量为局部变量,但是又发现局部变量
MIN_VALUE
并没有声明,因此就无法执行相关操作。所以,如果我们一定要在函数内部改变全局变量的值,就必须加上global
这个声明:MIN_VALUE = 1
MAX_VALUE = 10
def validation_check(value):
global MIN_VALUE
...
MIN_VALUE += 1
...
validation_check(5)
这里的
global
关键字,并不表示重新创建了一个全局变量MIN_VALUE
,而是告诉 Python 解释器,函数内部的变量MIN_VALUE
,就是之前定义的全局变量,并不是新的全局变量,也不是局部变量。这样,程序就可以在函数内部访问全局变量,并修改它的值了.对于嵌套函数来说,内部函数可以访问外部函数定义的变量,但是无法修改,若要修改,必须加上 nonlocal 这个关键字:
def outer():
x = "local"
def inner():
nonlocal x # nonlocal关键字表示这里的x就是外部函数outer定义的变量x
x = 'nonlocal'
print("inner:", x)
inner()
print("outer:", x)
outer()
# 输出
inner: nonlocal
outer: nonlocal
闭包
闭包(closure)其实和刚刚讲的嵌套函数类似,不同的是:
- 在嵌套函数中外部函数返回的是一个具体的值
- 闭包中外部函数返回的是一个函数,返回的函数通常赋于一个变量,这个变量可以在后面被继续执行调用。
比如,我们想计算一个数的 n 次幂,用闭包可以写成下面的代码
def nth_power(exponent):
def exponent_of(base):
return base ** exponent
return exponent_of # 返回值是exponent_of函数
square = nth_power(2) # 计算一个数的平方
cube = nth_power(3) # 计算一个数的立方
square
# 输出
<function __main__.nth_power.<locals>.exponent(base)>
cube
# 输出
<function __main__.nth_power.<locals>.exponent(base)>
print(square(2)) # 计算2的平方
print(cube(2)) # 计算2的立方
# 输出
4 # 2^2
8 # 2^3
需要注意的是,在执行完square = nth_power(2)
和cube = nth_power(3)
后,外部函数 nth_power()
的参数 exponent
,仍然会被内部函数 exponent_of()
记住。这样,之后我们调用 square(2)
或者 cube(2)
时,程序就能顺利地输出结果,而不会报错说参数 exponent 没有定义。
闭包解决了函数运行基础变量问题,尤其这个函数需要被多次调用的时候。
补充:UnboundLocalError
函数虽然在不被调用的情况下不会执行,但是python解释器会做一些变量检测、或者类型检测,比如是不是有yield,如果有那么就会被标记为生成器,这个在编译成字节码的时候就已经确定了。
import dis
x = 1
y = 2
def foo():
print(x)
x = 2
print(y)
dis.dis(foo)
# 直接调用 foo() 会报错
# UnboundLocalError: local variable 'x' referenced before assignment
# 输出
7 0 LOAD_GLOBAL 0 (print)
2 LOAD_FAST 0 (x)
4 CALL_FUNCTION 1
6 POP_TOP
8 8 LOAD_CONST 1 (2)
10 STORE_FAST 0 (x)
9 12 LOAD_GLOBAL 0 (print)
14 LOAD_GLOBAL 1 (y)
16 CALL_FUNCTION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
因为python寻找变量的时候,会按照本地作用域、闭包、全局、内置这种顺序去查找,当看到x=2
的时候,python解释器就知道函数体内部声明了局部变量x
,这是在编译的时候就已经确定,于是在print的时候也会从本地查找,但是print(x)语句在x=2
的上面,这是在执行的时候才发现的,于是报了个错:提示局部变量x在赋值之前就已经被引用了。
python 基础篇 自定义函数的更多相关文章
- python 基础篇 11 函数进阶----装饰器
11. 前⽅⾼能-装饰器初识本节主要内容:1. 函数名的运⽤, 第⼀类对象2. 闭包3. 装饰器初识 一:函数名的运用: 函数名是一个变量,但他是一个特殊变量,加上括号可以执行函数. ⼆. 闭包什么是 ...
- Python基础篇(初始函数)
Python初始函数: 一.什么是函数 1.我们到目前为止, 已经可以完成一些软件的基础功能了. 那么我们来完成这样一个功 能: 约x: print("拿出手机") print(& ...
- python 基础篇 匿名函数
匿名函数基础 首先,什么是匿名函数呢?以下是匿名函数的格式: lambda argument1, argument2,... argumentN : expression 我们可以看到,匿名函数的关键 ...
- python基础篇_003_函数
python中的函数 1.函数的目的 .避免代码冗余 .增强可读性 2.函数的定义与调用 # 定义函数 使用关键字def """ 1.定义函数: def 函数名(): 函 ...
- Python基础(二)自定义函数
1.判断字符串,内容是否为数字 我们用python:xlrd读Excel内容时,本来只是输入的整数字,经常读出来的是float类型 我们需要自动转成整型,意思就是说,读出来的和我们输入的一样,但是,我 ...
- python 基础篇 10 函数进阶
本节主要内容:1. 函数参数--动态传参2. 名称空间, 局部名称空间, 全局名称空间, 作⽤域, 加载顺序.3. 函数的嵌套4. gloabal, nonlocal关键字 ⼀. 函数参数--动态传参 ...
- python 基础篇 09 函数初识
<<<<<<<<<<<<<<<------------------------------函 ...
- Python基础篇(三)_函数及代码复用
Python基础篇_函数及代码复用 函数的定义.使用: 函数的定义:通过保留字def实现. 定义形式:def <函数名>(<参数列表>): <函数体> return ...
- python基础篇(六)
PYTHON基础篇(六) 正则模块re A:正则表达式和re模块案例 B:re模块的内置方法 时间模块time A:时间模块的三种表示方式 B:时间模块的相互转换 随机数模块random A:随机数模 ...
随机推荐
- 移动深度学习 Mobile-deep-learning(MDL)
Free and open source mobile deep learning framework, deploying by Baidu. This research aims at simpl ...
- nginx代理图片访问
nginx代理图片访问 首先配置nginx的代理物理路径 我的是在E盘下面的image 1 #图片的代理 2 server { 3 listen 80; 4 #配置访问的域名 5 server_nam ...
- Python Tkinter Grid布局管理器详解
Grid(网格)布局管理器会将控件放置到一个二维的表格里.主控件被分割成一系列的行和列,表格中的每个单元(cell)都可以放置一个控件. 注意:不要试图在一个主窗口中混合使用pack和grid (1) ...
- Bootstrap 的基本实现
bootstrap: UI插件 YUI, ElementUI Bootstrap 是最受欢迎的 HTML.CSS 和 JS 框架,用于开发响应式布局.移动设备优先的 WEB 项目. 响应式布局 ...
- Windows 7集成IE11(离线安装包、补丁)
当Win7系统需要集成IE11时,我们需要提前打入6个补丁 KB2731771.KB2786081.KB2834140.KB2670838.KB2729094.KB2533623 32位 ★百度网盘 ...
- Python数据库MySQL之数据备份、pymysql模块
一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具 下载链接:https://pan.baidu.com/s/1bpo5mqj 掌握: #1. 测试+链接 ...
- A 工艺
时间限制 : - MS 空间限制 : - KB 评测说明 : 1s,128m 问题描述 小敏和小燕是一对好朋友. 他们正在玩一种神奇的游戏,叫Minecraft. 他们现在要做一个由方块构成的长 ...
- 老技术新谈,Java应用监控利器JMX(3)
各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 上期我们深入的聊了聊 JMX,把 JMX 的架构了解了七七八八,最后通过代码实战,解决系列疑问,实现远程动态修改应用参 ...
- ansible--ansible基础
配置文件 ansible的配置文件只有一个,即ansible.cfg,它可以存在于多个地方,ansible读取配置文件的顺序依次是当前命令执行目录->用户家目录下的.ansible.cfg-&g ...
- escape和unescape知识点
decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码. encodeURI() 函数可把字符串作为 URI 进行编码 <script> var uri= ...