广告在线设计网站,天津做网站建设的公司,医疗网站专题模板,wordpress本地安装教程Python 基础入门前三篇#xff1a;
Python 基础入门–简介和环境配置Python基础入门_2基础语法和变量类型Python基础入门_3条件语句和迭代循环
第四篇内容#xff0c;这次介绍下函数的基本用法#xff0c;包括函数的定义、参数的类型、匿名函数、变量作用域以及从模块导入…Python 基础入门前三篇
Python 基础入门–简介和环境配置Python基础入门_2基础语法和变量类型Python基础入门_3条件语句和迭代循环
第四篇内容这次介绍下函数的基本用法包括函数的定义、参数的类型、匿名函数、变量作用域以及从模块导入函数的方法目录如下所示 4. 函数
定义函数是组织好的可重复使用用于实现单一或者相关联功能的代码段。
在 Python 中既有内建函数比如 print()、sum() 也可以用户自定义函数。
4.1 定义函数
自定义一个函数需要遵守一些规则
函数代码块必须以 def 关键词开头然后是函数标识符名称(函数名)和圆括号 ()圆括号内部用于定义参数并且传入参数和自变量也是存放在圆括号内函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。函数内容以冒号起始并且缩进。return [表达式] 结束函数选择性地返回一个值给调用方。不带表达式的 return 语句相当于返回 None。
一个函数的一般格式如下
def 函数名(参数列表):函数体默认情况下参数值和参数名称是按照函数声明中定义的顺序匹配的。
简单的定义和调用函数的例子如下所示
def hello():print(Hello, world!)
# 计算面积的函数
def area(width, height):return width * heighthello()
width 2
height 3
print(width{}, height{}, area{}.format(width, height, area(width, height)))输出结果
Hello, world!
width2, height3, area6上述例子定义了两个函数第一个是没有参数的 hello(), 而第二个函数定义了两个参数。
4.2 参数传递
在 python 中类型属于对象变量是没有类型的
a [1, 2, 3]
a abc上述代码中[1,2,3] 是 List 类型abc 是 String 类型但变量 a 是没有类型的它仅仅是一个对象的引用一个指针可以指向 List 类型也可以指向 String 类型。
可更改(mutable)与不可更改(immutable)对象
python 中strings, tuples, numbers 是不可更改对象而 list, dict 是可修改的对象。
不可变类型上述例子中 a 先赋值为 5然后赋值为 10实际上是生成一个新对象赋值为 10然后让 a 指向它并且抛弃了 5并非改变了 a 的数值可变类型对于 list 类型变量 la[1,2,3]然后令 la[2]5 此时并没有改变变量 la仅仅改变了其内部的数值。
在之前的第二节介绍变量类型中介绍了如何判断数据类型是否可变介绍了两种方法
id()hash()
这里用 id() 的方法来做一个简单的例子代码如下
# 判断类型是否可变
a 5
print(a id:{}, val{}.format(id(a), a))
a 3
print(a id:{}, val{}.format(id(a), a))la [1, 2, 3]
print(la id:{}, val{}.format(id(la), la))
la[2] 5
print(la id:{}, val{}.format(id(la), la))输出结果可以发现变量 a 的 id 是发生了变化而列表变量 la 的 id 没有变化这证明了 a 的类型 int 是不可变的而 list 是可变类型。
a id:1831338608, val5
a id:1831338544, val3la id:1805167229448, val[1, 2, 3]
la id:1805167229448, val[1, 2, 5]然后在 Python 中进行函数参数传递的时候根据传递的变量是否可变也需要分开讨论
不可变类型类似 c 的值传递如 整数、字符串、元组。如 fun(a)传递的只是 a 的值没有影响 a 对象本身。比如在 fun(a)内部修改 a 的值只是修改另一个复制的对象不会影响 a 本身。可变类型类似 c 的**引用传递**如 列表字典。如 fun(la)则是将 la 真正的传过去修改后 fun 外部的 la 也会受影响。
当然了Python 中一切都是对象这里应该说是传递可变对象和不可变对象而不是引用传递和值传递但必须注意应该慎重选择传递可变对象的参数下面会分别给出传递两种对象的例子。
首先是传递不可变对象的实例
# 传递不可变对象的实例
def change_int(a):a 10b 2
print(origin b, b)
change_int(b)
print(after call function change_int(), b, b)输出结果传递的变量 b 并没有发生改变。
origin b 2
after call function change_int(), b 2接着传递可变对象的例子
# 传递可变对象的实例
def chang_list(la):修改传入的列表参数:param la::return:la.append([2, 3])print(函数内部: , la)returnla [10, 30]
print(调用函数前, la, la)
chang_list(la)
print(函数外取值, la, la)输出结果可以看到在函数内部修改列表后也会影响在函数外部的变量的数值。
调用函数前, la [10, 30]
函数内部: [10, 30, [2, 3]]
函数外取值, la [10, 30, [2, 3]]当然这里如果依然希望传递列表给函数但又不希望修改列表本来的数值可以采用传递列表的副本给函数这样函数的修改只会影响副本而不会影响原件最简单实现就是切片 [:] 例子如下
# 不修改 lb 数值的办法传递副本
lb [13, 21]
print(调用函数前, lb, lb)
chang_list(lb[:])
print(传递 la 的副本给函数 change_list, lb, lb)输出结果
调用函数前, lb [13, 21]
函数内部: [13, 21, [2, 3]]
传递 lb 的副本给函数 change_list, lb [13, 21]4.3 参数
参数的类型主要分为以下四种类型
位置参数默认参数可变参数关键字参数命名关键字参数
位置参数
**位置参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。**其定义如下arg 就是位置参数docstring 是函数的说明一般说明函数作用每个参数的含义和类型返回类型等statement 表示函数内容。
def function_name(arg):docstringstatement下面是一个例子包括一个正确调用例子和两个错误示例
# 位置参数
def print_str(str1, n):打印输入的字符串 n 次:param str1: 打印的字符串内容:param n: 打印的次数:return:for i in range(n):print(str1)strs python
n 3
# 正确调用
print_str(strs, n)
# 错误例子1
print_str()
# 错误例子2
print_str(n, strs)对于正确例子输出
python python python 错误例子1–print_str()也就是没有传入任何参数返回错误:
TypeError: print_str() missing 2 required positional arguments: str1 and n错误例子1–print_str(n, strs)也就是传递参数顺序错误返回错误:
TypeError: str object cannot be interpreted as an integer默认参数
默认参数定义如下其中 arg2 就是表示默认参数它是在定义函数的时候事先赋予一个默认数值调用函数的时候可以不需要传值给默认参数。
def function_name(arg1, arg2v):docstringstatement代码例子如下
# 默认参数
def print_info(name, age18):打印信息:param name::param age::return:print(name: , name)print(age: , age)print_info(jack)
print_info(robin, age30)输出结果
name: jack
age: 18
name: robin
age: 30注意默认参数必须放在位置参数的后面否则程序会报错。
可变参数
可变参数定义如下其中 arg3 就是表示可变参数顾名思义就是输入参数的数量可以是从 0 到任意多个它们会自动组装为元组。
def function_name(arg1, arg2v, *arg3):docstringstatement这里是一个使用可变参数的实例代码如下
# 可变参数
def print_info2(name, age18, height178, *args):打印信息函数2:param name::param age::param args::return:print(name: , name)print(age: , age)print(height: , height)print(args)for language in args:print(language: , language)print_info2(robin, 20, 180, c, javascript)
languages (python, java, c, go, php)
print_info2(jack, 30, 175, *languages)输出结果
name: robin
age: 20
height: 180
(c, javascript)
language: c
language: javascriptname: jack
age: 30
height: 175
(python, java, c, go, php)
language: python
language: java
language: c
language: go
language: php这里需要注意几点
首先如果要使用可变参数那么传递参数的时候默认参数应该如上述例子传递不能如print_info2(robin, age20, height180, c, javascript)这种带有参数名字的传递是会出错的可变参数有两种形式传递
直接传入函数如上述例子第一种形式即 print_info2(robin, 20, 180, c, javascript);先组装为列表或者元组再传入并且必须带有 * 即类似 func(*[1, 2,3]) 或者 func(*(1,2,3))之所以必须带 * 是因为如果没有带这个传入的可变参数会多嵌套一层元组即 (1,2,3) 变为 ((1,2,3))
关键字参数
关键字参数定义如下其中 arg4 就是表示关键字参数关键字参数其实和可变参数类似也是可以传入 0 个到任意多个不同的是会自动组装为一个字典并且是参数前 ** 符号。
def function_name(arg1, arg2v, *arg3, **arg4):docstringstatement一个实例如下
def print_info3(name, age18, height178, *args, **kwargs):打印信息函数3带有关键字参数:param name::param age::param height::param args::param kwargs::return:print(name: , name)print(age: , age)print(height: , height)for language in args:print(language: , language)print(keyword: , kwargs)# 不传入关键字参数的情况
print_info3(robin, 20, 180, c, javascript)输出结果如下
name: robin
age: 20
height: 180
language: c
language: javascript
keyword: {}传入任意数量关键字参数的情况
# 传入任意关键字参数
print_info3(robin, 20, 180, c, javascript, birth2000/02/02)
print_info3(robin, 20, 180, c, javascript, birth2000/02/02, weight125)结果如下
name: robin
age: 20
height: 180
language: c
language: javascript
keyword: {birth: 2000/02/02}name: robin
age: 20
height: 180
language: c
language: javascript
keyword: {birth: 2000/02/02, weight: 125}第二种传递关键字参数方法–字典
# 用字典传入关键字参数
keys {birth: 2000/02/02, weight: 125, province: Beijing}
print_info3(robin, 20, 180, c, javascript, **keys)输出结果
name: robin
age: 20
height: 180
language: c
language: javascript
keyword: {birth: 2000/02/02, province: Beijing, weight: 125}所以同样和可变参数相似也是两种传递方式
直接传入例如 func(birth2012)先将参数组装为一个字典再传入函数中如 func(**{birth: 2000/02/02, weight: 125, province: Beijing})
命名关键字参数
命名关键字参数定义如下其中 *, nkw 表示的就是命名关键字参数它是用户想要输入的关键字参数名称定义方式就是在 nkw 前面添加 *, 这个参数的作用主要是限制调用者可以传递的参数名。
def function_name(arg1, arg2v, *arg3, *,nkw, **arg4):docstringstatement一个实例如下
# 命名关键字参数
def print_info4(name, age18, height178, *, weight, **kwargs):打印信息函数4加入命名关键字参数:param name::param age::param height::param weight::param kwargs::return:print(name: , name)print(age: , age)print(height: , height)print(keyword: , kwargs)print(weight: , weight)print_info4(robin, 20, 180, birth2000/02/02, weight125)输出结果如下
name: robin
age: 20
height: 180
keyword: {birth: 2000/02/02}
weight: 125这里需要注意
加入命名关键字参数后就不能加入可变参数了对于命名关键字参数传递时候必须指明该关键字参数名字否则可能就被当做其他的参数。
参数组合
通过上述的介绍Python 的函数参数分为 5 种位置参数、默认参数、可变参数、关键字参数以及命名关键字参数而介绍命名关键字参数的时候可以知道它和可变参数是互斥的是不能同时出现的因此这些参数可以支持以下两种组合及其子集组合
位置参数、默认参数、可变参数和关键字参数位置参数、默认参数、关键字参数以及命名关键字参数
一般情况下其实只需要位置参数和默认参数即可通常并不需要过多的组合参数否则函数会很难懂。
4.4 匿名函数
上述介绍的函数都属于同一种函数即用 def 关键字开头的正规函数Python 还有另一种类型的函数用 lambda 关键字开头的匿名函数。
它的定义如下首先是关键字 lambda 接着是函数参数 argument_list其参数类型和正规函数可用的一样位置参数、默认参数、关键字参数等然后是冒号 :最后是函数表达式 expression 也就是函数实现的功能部分。
lambda argument_list: expression一个实例如下
# 匿名函数
sum lambda x, y: x yprint(sum(1,3), sum(1, 3))输出结果
sum(1,3) 44.5 变量作用域
Python 中变量是有作用域的它决定了哪部分程序可以访问哪个特定的变量作用域也相当于是变量的访问权限一共有四种作用域分别是
L(Local)局部作用域E(Enclosing)闭包函数外的函数中G(Global)全局作用域B(Built-in)内置作用域(内置函数所在模块的范围)
寻找的规则是 L-E-G-B 也就是优先在局部寻找然后是局部外的局部(比如闭包)接着再去全局最后才是内置中寻找。
下面是简单介绍这几个作用域的例子除内置作用域
g_count 0 # 全局作用域
def outer():o_count 1 # 闭包函数外的函数中# 闭包函数 inner()def inner():i_count 2 # 局部作用域内置作用域是通过一个名为 builtin 的标准模块来实现的但这个变量名本身没有放入内置作用域需要导入这个文件才可以使用它使用代码如下可以查看预定义了哪些变量
import builtins
print(dir(builtins))输出的预定义变量如下
[ArithmeticError, AssertionError, AttributeError, BaseException, BlockingIOError, BrokenPipeError, BufferError, BytesWarning, ChildProcessError, ConnectionAbortedError, ConnectionError, ConnectionRefusedError, ConnectionResetError, DeprecationWarning, EOFError, Ellipsis, EnvironmentError, Exception, False, FileExistsError, FileNotFoundError, FloatingPointError, FutureWarning, GeneratorExit, IOError, ImportError, ImportWarning, IndentationError, IndexError, InterruptedError, IsADirectoryError, KeyError, KeyboardInterrupt, LookupError, MemoryError, NameError, None, NotADirectoryError, NotImplemented, NotImplementedError, OSError, OverflowError, PendingDeprecationWarning, PermissionError, ProcessLookupError, RecursionError, ReferenceError, ResourceWarning, RuntimeError, RuntimeWarning, StopAsyncIteration, StopIteration, SyntaxError, SyntaxWarning, SystemError, SystemExit, TabError, TimeoutError, True, TypeError, UnboundLocalError, UnicodeDecodeError, UnicodeEncodeError, UnicodeError, UnicodeTranslateError, UnicodeWarning, UserWarning, ValueError, Warning, WindowsError, ZeroDivisionError, __build_class__, __debug__, __doc__, __import__, __loader__, __name__, __package__, __spec__, abs, all, any, ascii, bin, bool, bytearray, bytes, callable, chr, classmethod, compile, complex, copyright, credits, delattr, dict, dir, divmod, enumerate, eval, exec, exit, filter, float, format, frozenset, getattr, globals, hasattr, hash, help, hex, id, input, int, isinstance, issubclass, iter, len, license, list, locals, map, max, memoryview, min, next, object, oct, open, ord, pow, print, property, quit, range, repr, reversed, round, set, setattr, slice, sorted, staticmethod, str, sum, super, tuple, type, vars, zip]注意只有模块(module)类(class)以及函数(def, lambda)才会引入新的作用域其他代码块(比如 if/elif/else、try/except、for/while)是不会引入新的作用域在这些代码块内定义的变量外部也可以使用。
下面是两个例子一个在函数中新定义变量另一个在 if 语句定义的变量在外部分别调用的结果
g_count 0 # 全局作用域
def outer():o_count 1 # 闭包函数外的函数中# 闭包函数 inner()def inner():i_count 2 # 局部作用域if 1:sa 2
else:sa 3
print(sa, sa)
print(o_count, o_count)输出结果对于在 if 语句定义的变量 sa 是可以正常访问的但是函数中定义的变量 o_count 会报命名错误 NameError 提示该变量没有定义。
sa 2
NameError: name o_count is not defined全局变量和局部变量
全局变量和局部变量的区别主要在于定义的位置是在函数内部还是外部也就是在函数内部定义的是局部变量在函数外部定义的是全局变量。
局部变量只能在其被声明的函数内部访问而全局变量可以在整个程序范围内访问。调用函数时所有在函数内声明的变量名称都将被加入到作用域中。如下实例
# 局部变量和全局变量
total 3 # 全局变量def sum_nums(arg1, arg2):total arg1 arg2 # total在这里是局部变量.print(函数内是局部变量 : , total)return total# 调用 sum_nums 函数
sum_nums(10, 20)
print(函数外是全局变量 : , total)输出结果
函数内是局部变量 : 30
函数外是全局变量 : 3global 和 nonlocal 关键字
如果在内部作用域想修改外部作用域的变量比如函数内部修改一个全局变量那就需要用到关键字 global 和 nonlocal 。
这是一个修改全局变量的例子
# 函数内部修改全局变量
a 1def print_a():global aprint(全局变量 a, a)a 3print(修改全局变量 a, a)print_a()
print(调用函数 print_a() 后, a, a)输出结果
全局变量 a 1
修改全局变量 a 3
调用函数 print_a() 后, a 3而如果需要修改嵌套作用域也就是闭包作用域外部并非全局作用域则需要用关键字 nonlocal 例子如下
# 修改闭包作用域中的变量
def outer():num 10def inner():nonlocal num # nonlocal关键字声明num 100print(闭包函数中 num, num)inner()print(调用函数 inner() 后, num,num)outer()输出结果
闭包函数中 num 100
调用函数 inner() 后, num 1004.6 从模块中导入函数
一般我们会需要导入一些标准库的函数比如 os、sys 也有时候是自己写好的一个代码文件需要在另一个代码文件中导入使用导入的方式有以下几种形式
# 导入整个模块
import module_name
# 然后调用特定函数
module_name.func1()# 导入特定函数
from module_name import func1, func2# 采用 as 给函数或者模块指定别名
import module_name as mn
from module_name import func1 as f1# * 表示导入模块中所有函数
from module_name import *上述几种形式都是按照实际需求来使用但最后一种方式并不推荐原因主要是 Python 中可能存在很多相同名称的变量和函数这种方式可能会覆盖相同名称的变量和函数。最好的导入方式还是导入特定的函数或者就是导入整个模块然后用句点表示法调用函数即 module_name.func1() 。 参考
《Python 编程从入门到实践》Python3 函数 | 菜鸟教程超易懂的Python入门级教程(下)绝对干货 小结
本文主要是简单介绍了 Python 函数的基础内容正规函数和匿名函数的定义和用法参数的5种类型和使用当然函数还有更多内容比如高阶函数 map, filter, reduce还有本文中间提过的闭包函数等这部分计划放到后续进阶中介绍。
此外本文的代码都上传到我的 github 上了
https://github.com/ccc013/Python_Notes/blob/master/Practise/function_example.py 欢迎关注我的微信公众号–算法猿的成长或者扫描下方的二维码大家一起交流学习和进步
往期精彩推荐
机器学习系列
初学者的机器学习入门实战教程模型评估、过拟合欠拟合以及超参数调优方法常用机器学习算法汇总比较(完常用机器学习算法汇总比较(上机器学习入门系列(2)–如何构建一个完整的机器学习项目(一)特征工程之数据预处理上
Github项目 资源教程推荐
[Github 项目推荐] 一个更好阅读和查找论文的网站[资源分享] TensorFlow 官方中文版教程来了必读的AI和深度学习博客[教程]一份简单易懂的 TensorFlow 教程[资源]推荐一些Python书籍和教程入门和进阶的都有[Github项目推荐] 机器学习 Python 知识点速查表[Github项目推荐] 推荐三个助你更好利用Github的工具