Python笔记_第二篇_面向过程_第二部分_1.函数
函数:这个词属于一个数学概念,在编程语言借鉴了这个概念,表现形式是一段程序代码的组合,也叫“程序集”。有过编程基础的人很容易理解这个概念,当我们编写程序越来越多的时候,程序设计大师们会把散乱的程序进行高度的抽象化的概念。可能有:程序-函数-模块-包-库,这样一个路径。
怎么认识函数?
函数是在一个完整的项目中,某些功能会返回使用,那么我们会讲功能进行“封装”,当我们要使用功能的时候直接调用函数即可。
本质:函数就是对功能的封装
优点:
1. 简化了代码结构,增加了代码的复用度(重复使用的程度)
2. 如果想修改某些功能或者修改某个BUG,修改对应的函数即可。
1. 定义函数:
格式:
def 函数名(参数列表):
语句
return表达式
解释:
* def:函数代码块以def关键字开始
* 函数名:遵循标识符规则
* 参数列表:任何传入函数的参数和变量必须放在圆括号之间,用逗号分隔。参数列表从函数的调用者哪里获取信息。
* ( ) :是参数列表的开始和结束
* ::冒号是函数内容(封装功能)以冒号开始并缩进
* 语句:函数封装的功能,也可以说是函数体
* return:一般用于语句结束函数,并返回给信息调用者。
* 表达式:即为要返回给函数的调用者的信息。
注意:最后的return表达式,可以不写,相当于返回一个None,return none
举例1:定义一个最简单的函数——无参数无返回值。
def myprint():
print("Thomas is a good man!")
return # 或者不写,就是不需要返回值的话
2. 函数的调用:
格式1:
函数名(参数列表)
格式2:
变量名 = 函数名(函数列表)
解释:格式2就是拿一个变量名去接收这个函数
# 调用一个最简单的函数
# 格式1:
myPrint()
# 返回值:Thomas is a good man! # 格式2:
ret = myPrint()
print(ret)
# 返回值:Thomas is a good man!
3. 函数的返回值:
举例2:定义一个带返回值的函数:
# 定义一个带返回值的函数
def mysum(num1,num2):
# 将结构返回给函数的调用者
return num1 + num2
# 执行完return语句,该函数就结束了,return后面的代码不执行了 # 输入实参并获得返回值
result = mysum(,)
print(result)
# 返回值:
#
4. 函数的格式的解释:
4.1 函数的参数
函数的参数分形参和实参
实参:调用函数时给函数传递的数据,本质就是值
形参:定义函数时小括号中的变量,本质是变量
参数必须按照顺序传递,个数目录要对应(不一定这个事儿)
举例2:定义一个带参数的函数并返回这个函数
# 定义一个带参数的函数
# 定义一个形参
def myprint2(str,age):
print(str,age) # 输入一个实参:
myprint2("Thomas is a good man",)
4.2 函数参数的传递:
值传递:传递的不可变类型(string,tuple,number等不可变的类型)
引用传递:传递的可变类型(list,dict,set等可变的类型)
举例3:值传递,我们通过观察内存地址来证明这个现象
# 值传递:
def func1(num):
print(id(num))
num =
print(id(num)) temp =
print(id(temp))
func1(temp)
print(temp)
# 返回值:
#
#
#
举例4:引用传递,我们通过输入一个列表,发现原先列表的第一个值已经发生变化了
# 引用传递
def func2(list):
list[] = list1 = [,,,,]
func2(list1)
print(list1)
# 返回值:
# [, , , , ]
4.3. 函数参数的其他形式:
关键字参数:运行函数调用时参数的顺序与定义不一致。(在C#当中叫做命名参数)
默认参数:调用函数时,如果没有传递参数,则默认参数。
不定长参数:
* :加星号的变量存放所有未命名的变量参数,如果在函数调用时没有指定参数,那么他就是一个空元祖。
*args:表示传入参数值(比较规范的写法)
*Kwargs:key-value形式,表示键值对的参数传入形式,这个键值对是字典形式(比较规范的写法)
备注:一般这两个位置全部写上形参可接受任意参数的形式。
偏函数的使用:所谓偏函数其实是起到默认参数的作用,通过模块导入functools工具包,在不改变原函数的前提下进行偏函数的锁定
举例5:我们使用关键字参数(其实这种形式 = *Kwargs,键值对的输入方式)
# 使用关键字参数
def func3(str, age):
print(str,age) func3(age = ,str = "Thomas")
举例6:使用默认参数。就是规定好了参数的值无需再输入了。
# 使用默认参数
# 要以默认参数,最好将默认参数放到最后
def func4(str, age = ):
print(str,age) func4("Thomas")
举例7:不定长参数——值参数
# 不定长参数
def func5(name,*args):
print(name)
for x in args:
print(x)
func5("Thomas","Jessie","China")
# *args表示值参数
def func6(*args):
sum = 0
for i in args:
sum += i
return sum
print(func6(1,2,3,4,5,6,7))
举例8:不定长参数——键值对参数
# **kwargs表示键值对的参数
def func7(**kwargs):
print(kwargs)
print(type(kwargs)) func7(x=,y=,z=)
举例9:表示可以接受任意的参数
# 表示可以接收任意的参数
def func8(*args,**kwargs):
print(args,kwargs) """
举例10:偏函数的使用
例子1:将字符串当做10进制来算
# 将字符串当作10进制来算
print(int("",base=))
# 将字符串当作2进制来算
print(int("",base=))
例子2:对函数返回值进行限制。
# 偏函数就是在返回值的位置进行添加其他的返回限制 def int2(str):
return int(str,base = ) print(int2(""))
例子3:偏函数functool工具去调用偏函数
# 偏函数理论上不需要自己去定义
import functools
# 把一个参数固定住,形成一个新函数
int3 = functools.partial(int,base = )
print(int3(""))
如下为函数的进阶内容:
5. 匿名函数____lambda表达式:
匿名函数:不使用def关键字这样的语句定义,类似于函数的一种简写形式。使用Lambda表达式进行创建匿名函数。在其他语言中还可以通过@函数句柄形式创建(matlab),还有其他语言有内联函数的创建,内联函数主要是为了加快函数的运算,类似于用fevel函数,还有inline的方式进行。Python没看到内联函数的这种形式
格式:
lambda 参数1,参数2,... ,参数n : 表达式(expression)
举例11:
sum = lambda num1,num2:num1 + num2
print(sum(,))
6. 递归
我们上面对函数有了基本的概念之后,另外思考一下:在一个函数代码当中,如果我们还想处理更多的内容,是不是可以在函数当中再写一个函数,还可不可以在函数当中去调用自身等方式进行函数和函数之间的一种组合呢?当然可以,实际过程当中也是这么用的。在Python当中常用的两种形式就是递归和装饰器,下面对递归进行讲解。
递归:一个函数调用自身成为了递归的调用。一会儿调用自身的函数成为递归函数。凡是循环能干的事儿,都能干。
递归常见于return返回值的后面和函数体内。
方式:
1. 写出临界条件。
2. 找这一次和上一次的关系。
3. 假设当前函数已经能用,调用自身计算上一次的记过,在去求本次的结果。
举例12:我们用一个最简单的循环写这么一个过程:
# 输入一个数,大于等于1,求1+++---+n的和。
# 如果用循环写
# def sum(n):
# sum =
# for x in range(,n+):
# sum += x
# return sum
# result = sum()
# print("result = ",result)
举例13:比如我们有一个1到5的累加
数学过程:1+2+3+4+5,假设这个函数叫sum2
我们有如下的表达式:
sum2(1) + 0 = sum2(1)
sum2(1) + 2 = sum2(2)
sum2(2) + 3 = sum2(3)
sum2(3) + 4 = sum2(4)
sum2(4) + 5 = sum2(5)
在这个过程中我们发现sum2( )这个函数被不断的调用,得到的结果带入到函数进行循环计算。
因此这个计算过程如下(反向)
5 + sum2(4)
5 + 4 + sum2(3)
5 + 4 + 3 + sum2(2)
5 + 4 + 3 + 2 + sum2(1)
5 + 4 + 3 + 2 + 1 # return 1
我们用递归来写这个函数
# def sum2(n):
# if n == :
# return
# else:
# return n + sum2(n-)
#
# result2 = sum2()
# print("result2 = ", result2)
7. 装饰器:
7.1 装饰器的解释:
装饰器:是一个闭包,在Python当中叫做装饰器,把一个函数当做参数返回一个替代版的函数,本质上就是一个返回函数的函数,因此装饰器叫做函数的函数。
我们先来看一个最简单的装饰器
举例14:一个简单的装饰器
# 简单的装饰器
def func1():
print("Thomas is a good man!") # 制作一个装饰叫做outer
def outer(func):
def inner():
print("**********************")
func()
return inner
# 通过装饰器outer把原函数func1带入到里面,形成一个新函数f
f = outer(func1)
f()
# 运行结果:
# ****************
# Thomas is a good man
我们把这个而过程图示一下:
注意:我们这里发现这个装饰器的调用稍微复杂了一点儿,通过一个函数句柄返回一个新的函数。在Python2.4之前只能这样操作,在Python2.4之后的版本我们可以通过@这个符号来简化这个调用操作
格式:
@装饰器名
要装饰的函数代码
@装饰器名
要装饰的函数代码
在这里要有一个就近原则,比如说
@装饰器名
函数代码A
函数代码B
这总形式:@装饰器只装饰函数代码B
图示:
这样是不能装饰后面那个,如果要装饰后面那个要一个装饰器名对应一个要装饰的代码。
举例15:我们在写一个复杂一点儿的装饰器
# 复杂一点儿的装饰器
def outer(func):
def inner(age):
if age < :
age =
func(age)
return inner
# 使用@符号将装饰器用用到函数
# @python2.4出现支持@符号
# 其实这里的@outer1 = say = outer(say)
@outer #
def say(age):
print("Thomas is %d years old" %age)
def say1(age):
print("Thomas is %d years old" %age) say(-) # Thomas is years old # @ = 下面句柄形式的调用
# say1 = outer(say)
#say1(-)
7.2 换个角度再来理解装饰器:
1. 我们知道一个函数写完了,里面的东西可以通过修改函数的内容进行修改。还有一种方式不动原函数进行修改(前面说过偏函数也是一种不动原函数的方式进行内容修改),这种方式就是装饰器。
2. 装饰器我们可以抽象的理解把原函数的函数名和函数参数拆分成两个部分形成一个嵌套函数来组成这个装饰器。
根据这个理解我们再举几个例子:
举例16:
# 我们一个简单的装饰器
# 正如前面说的在不动原函数的基础上进行修改
# 写装饰
def outer(func): # 把函数名传进来
def inner(): # 让函数再键入什么内容
print("Hello World")
return func() # 返回上一层
return inner # 返回最外层 def sayHello():
print("Say Hello") s = outer(sayHello) # 做好了装饰器,然后去装饰谁
s()
举例17:
# 根据类似于上面的句柄函数的概念,我们可以把装饰器的调用用@进行简写
def outer(func): # 把函数名传进来
def inner(): # 让函数再键入什么内容
print("Hello World")
return func() # 返回上一层
return inner # 返回最外层
@outer
def sayHello():
print("Say Hello") # 这里空缺@outer这个装饰器调用,因此不再调用
def sayHello2():
print("Say Thomas") sayHello()
sayHello2()
# 注意:装饰器只是对就近的函数进行装饰调用,再往下就不再调用,想要再调用再写
# 一个@调用。
# 输出:
# Hello World 增加@outer,进行装饰
# Say Hello # Say Thomas 缺少@outer,不用装饰
举例18:
# 有参数的装饰器
# 装饰器还可以增加参数
def sayName(func):
def inner(name):
print("I am shi")
func(name)
return inner @sayName
def sayHi(name):
print("Hi " + name) sayHi("Thomas")
举例19:我们可以搞两个装饰器共同修饰一个函数
# 我们还可以搞两个装饰器
def sayName(func):
print("name")
def inner(*args,**kwargs):
print("I am Thomas")
func(*args,**kwargs)
return inner def sayAge(func):
print("age")
def inner(*args,**kwargs):
print("I am 18")
func(*args,**kwargs)
return inner @sayName
@sayAge
def sayHi(name,age):
print("Output:" + name , age) sayHi("Thomas",)
# 输出内容:
# age
# name
# I am Thomas
# I am
7.3 通用装饰器:
我们前面学过*args和*Kwargs这种不定长的参数表示形式,因此我们可以制作一个通用装饰器。
举例20:
def outer(func):
def inner(*args,**kwargs):
# 添加修改的功能的位置
print("################")
func(*args,**kwargs)
return inner
@outer
def say(name,age):
# 函数的参数理论上是无限的,但是实际上最好不要超过6-7个
print("My name is %s, I am %d year old" % (name,age)) say("Thomas",) # 返回结果:
# ################
# My name is Thomas, I am year old # # 因此我们可以改写成一个通用装饰器
def sayName(func):
def inner(*args,**kwargs):
print("I am shi")
func(*args,**kwargs)
return inner @sayName
def sayHi(name):
print("Hi " + name) sayHi("Thomas")
# 备注:一般来说,我们用一个通用装饰器就可以,这种方式用的最多
Python笔记_第二篇_面向过程_第二部分_1.函数的更多相关文章
- Python笔记_第一篇_面向过程_第一部分_2.内存详解
Python的很多教材中并没有讲内存方面的知识,但是内存的知识非常重要,对于计算机工作原理和方便理解编程语言是非常重要的,尤其是小白,因此需要把这一方面加上,能够更加深入的理解编程语言.这里引用了C语 ...
- 四、java基础-面向过程_对象_类中可出现的因素
1.面向过程和面向对象区别: 1)面向过程:开发一个应用程序.一个项目,必须先了解整个过程,了解各个步骤.模块间的因果关系,使的面向过程方式去开发程序时,代码和代码之间的关联程度是非常强.所以其中任何 ...
- python自动化开发-[第五天]-面向过程、模块、包
今日概要: 1.内置模块 2.协程函数 3.递归 4.面向过程编程与函数编程 5.模块 6.包 7.re正则 一.内置模块 1.匿名函数lambda 定义:匿名函数通常是创建了可以被调用的函数,它返回 ...
- python第四周迭代器生成器序列化面向过程递归
第一节装饰器复习和知识储备------------ 第一节装饰器复习和知识储备------------ def wrapper(*args,**kwargs): index(*args,**kwa ...
- [Python笔记]第八篇:模块
本篇主要内容:python常用模块用法介绍 什么是模块 模块,用一大段代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性 ...
- [Python笔记]第三篇:深浅拷贝、函数
本篇主要内容:深浅拷贝,自定义函数,三目运算,lambda表达式, 深浅拷贝 一.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. import ...
- python之迭代器、生成器、面向过程编程
一 迭代器 一 迭代的概念 #迭代器即迭代的工具,那什么是迭代呢?#迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True: #只是单纯地重复,因而不 ...
- python怎么写可读性好的面向过程的长篇代码?
最近接受老代码,mmp的,说是重新运行运行起来,那还不如重写呢,因为有很多毛病,不能直接运行,pep8就不用妄想奢望了,还有包括语法错误问题和内存严重泄露的问题(运行几分钟后python.exe进程达 ...
- [Python笔记]第十一篇:面向对象
以上就是本节对于面向对象初级知识的介绍,总结如下: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用 对象,根据模板创建的实例(即 ...
- python之迭代器、生成器与面向过程编程
目录 一 迭代器 二 生成器 三 面向过程编程 一.迭代器 1.迭代器的概念理解 ''' 迭代器从字面上理解就是迭代的工具.而迭代是每次的开始都是基于上一次的结果,不是周而复始的,而是不断发展的. ' ...
随机推荐
- Day 22:网络编程(3)
TCP通讯协议特点: 1. tcp是基于IO流进行数据 的传输的,面向连接. 2. tcp进行数据传输的时候是没有大小限制的. 3. tcp是面向连接,通过三次握手的机制保证数据的完整性.可靠协 ...
- 漏洞复现 - ActiveMQ反序列化漏洞(CVE-2015-5254)
基础知识 MQ(Message Queue):消息队列/消息中间件.消息服务将消息放在队列/主题中,在合适时候发给接收者.发送和接收是异步的(发送者和接收者的生命周期没有必然关系). 队列:消息存在队 ...
- 自学Java第五章——《面向对象的基本特征》
面向对象的基本特征: 1.封装 2.继承 3.多态 6.1 封装 1.好处: (1)隐藏实现细节,方便使用者使用 (2)安全,可以控制可见范围 2.如何实现封装? 通过权限修饰符 面试题:请按照可见范 ...
- equals与hashcode分析
我们经常在面经中看到这样的问题,为什么重写equals方法就一定要重写hashcode方法.本文就是分析这个问题. <!--more--> 在阿里巴巴java开发手册中就给出了这样的规则. ...
- 图像算法五:【图像小波变换】多分辨率重构、Gabor滤波器、Haar小波
原 https://blog.csdn.net/alwaystry/article/details/52756051 图像算法五:[图像小波变换]多分辨率重构.Gabor滤波器.Haar小波 2018 ...
- caffe中运行mnist
mnist样本字库嘚图片转换:# coding=utf-8import numpy as npimport struct import matplotlib.pyplot as plt from PI ...
- IDEA--安装
1:下载IDEA 官网:http://www.jetbrains.com/idea/download/#section=windows(选择下载.zip) 2:解压 3:破解: 1)在C:\Windo ...
- python 符号小技巧
1 用于解释 对于不想放入程序中执行的句子 用来解释的 在Python中 单行注释用 # 多行注释用 """ 这个句子不会在Python中表达出来 " ...
- (day 1)创建项目--3【创建应用】
创建步骤 1.打开命令行,进入项目中manage.py的同级目录 2.在命令行输入 python manage.py startapp blog 3.添加应用名到settings.py的INSTALL ...
- 步进电机加减速S曲线算法
一.Sigmoid 函数 1.1 Sigmoid函数原型 1.2 sigmoid函数波形: 由图形可看出在-10时已经接近于0,一般取值区间在[-5,5]. 1.3 sigmoid函数的导数 转载CS ...