python-函数

函数的基本概念

写一段代码实现某个小功能, 将代码集中在一起,做一个命名,下次直接根据命名名称使用这个代码块,这就是函数

作用
  1. 方便代码重用
  2. 分解任务,简化程序逻辑
  3. 使代码更加模块化
函数分类
  1. 内建函数: python中已经存在的函数
  2. 三方函数: 其他人写的函数,我们可以直接调用
  3. 自定义函数:自己根据需求编写的函数

函数的定义和调用

定义函数的语法:

def  函数名 ([参数列表]) :
    '''文档字符串'''
    函数体/若干语句

简述:

  1. 使用def来定义函数,然后就是一个空格和函数名称,python执行def时,会创建一个函数对象,并绑到函数名变量上
  2. 括号内的参数有多个时用逗号隔开,调用时参数必须和参数列表一一对应、
  3. 如果函数需要返回数据,可以使用return语句返回值,不包含return语句则返回None

调用函数:
先定义函数,也就是先使用def创建函数对象,当然内置函数对象是会自动创建的
创建完函数对象,可以直接使用函数名称进行调用

参数

形参和实参

形参分为: 位置参数,默认参数,可变参数,关键字参数
形参是在定义函数时给出的变量,实参是调用函数时传递的真实数据

位置参数

形参和实参必须保持一致,最好按位置传参,如果位置不对应需要指定说明

def register(name, age):
    print(name, age)

# 正确传参方法
register('zhangsan', '18')
register(age='18', name='zhangsan')
# 错误传参方法
register('18', 'zhangsan')
默认参数

形参和实参可以不一致,如果不想使用默认的参数,在调用函数的时候可以指定
调用函数的时候,如果默认参数的值没有传入,则直接使用默认值

def register(name, age=18):
    print(name, age)

register('zhangsan')
register('zhangsan', age=20)
可变参数

形参参数名前面加*,可变参数可允许传入0个或者任意个参数,这些可变参数在函数调用时,自动组装成一个元组

def register(*name):
    print(name)
    
register('zhangsan', 'lisi', 'wangwu')
关键字参数

**kwargs代表关键字参数,可以传入任意多个key-value,是一个字典

def register(name, age, **kwargs):
    print(name, age, kwargs)

register('zhangsan', 18, a=1, b=2)

c = dict(a=1, b=2)
register('zhangsan', 18, **c)

变量的作用域

局部变量

函数内使用的变量,只能在函数内使用

  1. 调用函数时,函数作用域创建,函数执行完毕,作用域销毁
  2. 每次调用函数都会创建一个新的函数作用域
  3. 函数作用域内可以访问到全局作用域的变量,但是函数外无法访问函数内的变量
  4. 函数作用域内访问变量或者函数,会从内到外逐层寻找,一直到全局作用域
  5. 函数作用域内也有声明提前的特性,对变量和函数都适用,此时函数作用域相当
全局变量

函数外定义的变量,可以在不同函数内使用

  1. 在页面打开时创建,页面关闭时销毁
  2. 编写在script标签中的变量和函数,作用域作为全局,在页面的任意位置都可以访问到
  3. 在全局作用域中有全局对象window,代表一个浏览器窗口,由浏览器创建,可以直接调用
  4. 全局作用域中声明的变量和函数会作为window对象的属性和方法保存
全局变量和局部变量效率测试

局部变量的查询和访问速度比全局变量快,优先考虑使用,尤其是在循环的时候
在特别强调效率的地方或者循环次数较多的地方,可以通过将全局变量转为局部变量提高运行速度

import math
import time

def test1():
    start = time.time()
    for i in range(10000000):
        math.sqrt(30)
    end = time.time()
    print("耗时{0}".format((end - start)))

def test2():
    b = math.sqrt
    start = time.time()
    for i in range(10000000):
        b(30)
    end = time.time()
    print("耗时{0}".format((end - start)))

test1()
test2()
----------------------------------
耗时0.847449541091919
耗时0.6533384323120117

深拷贝和浅拷贝

浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用

浅拷贝的方法
  1. 通过数据类型本身的构造器,例如 list set dict
  2. 对于可变序列,可以使用切片操作完成浅拷贝
  3. 使用copy.copy()函数完成,适用于任何数据类型
特征
  1. 构造器完成的浅拷贝,因为实际上是新分配了一块内存,所以和原来的变量内存不一样,直接==判断为false,但是两个变量的元素值是一样的
  2. 元组使用切片操作或者tuple()不会创建一份浅拷贝,因为它开辟新的内存存储的是原对象的引用,而没有创建新的对象来存储原对象的子对象的引用,所以不是浅拷贝。相反它会返回一个指向相同元组的引用。对字符串使用 str() 或者切片操作符 ‘:’,原理和 元组相同

深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联
以 copy.deepcopy() 来实现对象的深度拷贝

递归函数

什么是递归

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

  1. 递归函数必须有一个明确的结束条件
  2. 每进入更深一层的递归时,问题规模相对于上一次递归都应减少
  3. 相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)
  4. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

看个例子,比如我们用循环来实现叠加:

def sum1(n):
    sum = 0
    for i in range(1,n + 1):
        sum += i
    return sum

如果用递归来实现的话

def sum2(n):
    if n > 0:
        return n + sum2(n - 1)
    else:
        return 0

看这个例子大概能理解递归函数是什么,怎么写了,那递归函数有什么有缺点呢

递归函数的优缺点

首先,优点:定义简单,逻辑清晰
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
缺点: 使用时需要注意防止栈溢出
在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

Lambda函数

lambda函数也叫匿名函数,即,函数没有具体的名称

def f(x):
    return x ** 2
print(f(4))

g = lambda x: x ** 2
print(g(4))

lambda函数和普通的函数相比,其实就是省去了函数名称,同时这样的匿名函数,又不能共享在别的地方调用

Lambda的作用
  1. 使用Python写一些执行脚本时,使用lambda可以省去定义函数的过程,让代码更加精简
  2. 对于一些抽象的,不会别的地方再复用的函数,有时候给函数起个名字也是个难题,使用lambda不需要考虑命名的问题
  3. 使用lambda在某些时候让代码更容易理解
Lambda基础

lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值

from functools import reduce

foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
print(filter(lambda x: x % 3 == 0, foo))
print(map(lambda x: x * 2 + 10, foo))
print(reduce(lambda x, y: x + y, foo))
----------------------------------
<filter object at 0x0000025F8F43FFA0>
<map object at 0x0000025F8F43FFD0>
139

在对象遍历处理方面,其实Python的for…in…if语法已经很强大,并且在易读上胜过了lambda。
defaultdict是字典类型,可以为defaultdict设置默认值,可以通过lambda设置默认值

from collections import *
x = defaultdict(lambda:0)
print(x[0])
y =defaultdict(lambda:defaultdict(lambda:0))
print(y[0])
z = defaultdict(lambda:[0,0,0])
print(z[0])
----------------------------------
0
defaultdict(<function <lambda>.<locals>.<lambda> at 0x000001BC7C427DC0>, {})
[0, 0, 0]

eval() 函数

eval() 函数用来执行一个字符串表达式,并返回表达式的值

语法

eval(expression[, globals[, locals]])

expression – 表达式。
globals – 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
locals–变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
返回值:返回表达式计算结果。

举例
n = input()
m = eval(input())
print(type(n))
print(type(m))
print(type(eval(n)))

在这里插入图片描述
使用eval()函数,将字符串还原为数字类型,和int()函数的作用类似

m = input()
n = eval(input())
print(type(m))
print(type(n))
print(type(n[0]))

在这里插入图片描述
将输入的字符串转为对应的数据类型,列表、元组等数据类型都可以使用这种方式输入

s1 = '3*7'
s2 = 'pow(2,3)'
n = eval(s1)
m = eval(s2)
print(n, m)

在这里插入图片描述
对表达式的结果进行计算,返回计算后的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值