函数
组织好的、可重复使用的、用户实现单一或者关联功能的代码段。函数能够提高应用的模块性和代码的重复利用率。Python提供了很多内置的函数,比如len等等,另外也可以根据自己的业务需求进行用户自定义函数的创建。
- 定义函数:
- 定义函数的语法格式 def 函数名称 def表示的是函数的关键字
- 操作函数 例如:给函数赋值,给函数定义变量,常亮等
- 调用函数,可以将代码进行重复使用必须很大大量的中间重复代码的实现,并且利用函数代码容易维护可以降低软件间的耦合度
def Num():
print('hello world')
#调用函数
Num()
- 函数的定义规则
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
def Num1(a,b):#给函数num1里面传递两个参数,可以传递多个参数
print(a)
print(b)
#调用函数
Num1(100,300)#通过函数赋值
#函数可以为变量赋值,这样操作效率高
#给函数起别名
def Num2(a):
pri = Num2(a)#将函数num2给一个变量pri
print(pri)
Num2(100)
- 函数的参数类型: 实参 和 形参
有形参,必须有实参,如果只有形参,没有实参,就会报空指针异常
def PName(username): #username是形参(一个不确定的参数)
print(username)
PName('milno') #实参,给形参赋值
- 函数参数分类
-
必备参数
-
关键字参数
-
默认参数
pet1='dog’不建议使用:在Python计数器解释的时候会将实参和形参混淆
-
不定长参数
问:为什么要用不定长参数?
注意:加了星号(*)的变量名会存放所有未命名的变量参数。加了(**)会存放所有命名的变量参数 -
def getUsername(name,address,*tup, **dict):
# * 表示的是一个通配符,表示的是韩式里面可以有多个不确定个数的形式参数
# *其实就是表示内存--内存由元组开辟(存放数据的集合)
print(name)
print(address)
print(tup)
print(dict)
#** 表示的是可以直接在函数调用处给函数直接复制,并且直接定义实参,不需要在函数名称里面定义实参
getUserName('milong','china',zhangtao,age=43)
#milong
#china
#('zhangtao')
#{'age':43}
- 可变对象与不可变对象的传递
-在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict,set等则是可以修改的对象。
-不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
-可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了
区别:
不可变对象,传递的是对象的值,不是对象本身,如果修改值,修改的是另一个复制的对象,不会影响原来对象的本身
可变对象,传递对象自己。函数内部如果修改值会影响对象本身。
a = 10
# 改为 a=5 10在内存中被抛弃
def fun(args):
args[0]='hello'
print(ags)
list01=['liu','huang']
fun(list01)
print(list01)
#传递的是对象本身,函数里面被修改了值,原对象跟着修改
- 函数返回值
函数并非总是将结果直接输出,相反,函数的调用者需要函数提供一些通过函数处理过后的一个或者一组数据,只有调用者拥有了这个数据,才能够做一些其他的操作。那么这个时候,就需要函数返回给调用者数据,这个就被称之为返回值,想要在函数中把结果返回给调用者,需要在函数中使用return。
问:return 和 print() 的区别?
- return 表示的是返回客户端浏览器的一行数据
- print() 表示的是只给客户端控制台打印输出结果,并非’数据’
- return 返回的永远是一个程序所控制的一个数据结果集
- print() 没有什么程序价值
- return 以后的代码不再执行
def sum1(a,b):
print(sum1())
return a+b
sum(10,20)
#在Python里面返回值的ID地址可以是同一个(变量的值相同,变量名称可以不相同)
#这样的目的是节省内存空间,Python里面的return可以返回海量数据,但是Java不行
#return一次性可以返回多个值,保存到元组里面,但是不建议使用
def returnmany(sum1,sum2,sum3):
return sum1,sum2,sum3
sum1,sum2,sum3 = returnmany(12,23,34)
print(sum1)
print(sum2)
print(sum3)
#以上操作针对于数据量少的时候,建议使用,因为他满足未知参数的原理,数据是一一对应关系mimi
yield
yield 的作用就是把一个函数变成一个generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个生成器,如调用Xun函数,不会执行该函数,而是返回一个iterable迭代对象!
区别:与return类似,都可以返回值,但不一样的地方,yield可以返回多次值,而return只能返回一次。
def getNum(n):
i=0 #循环
while i<n:
print('i的值为:',i)
# return i #i执行完之后,结束程序不在执行
yield i #表示的是将 i 或者是一个变量看做一个生成器generator -- 一个生成器的地址
#调用函数给n进行赋值,进行i>n的操作
i+=1
print(getNum(5))#打印输出
a = getNum(5) #将一个函数赋值给一个变量a, 其实此处的a也是一个生成器
#调用next()方法将生成器里面的值按照游标的原理"一行一行的读取"
print(next(a))
#yield的核心就是利用next方法和iter() --此方法不建议使用,没有next方法效率高
#因为不管是next还是iter(),他们最后都是返回一个'迭代器'对象,next方法更加接近迭代器的迭代原理
yield的生成器的next方法可以返回多个值,在Python语言里此方法返回多个值是独一无二的
yield生成器和for while 循环结合使用
getNum(5)
a1=(1,2,3,4,5)
it = iter(a1)
print(next(it))
print(next(it))
迭代器
迭代器:迭代是Python最强大的功能之一,是访问集合元素的一种方式。。
迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
迭代器只能往前不会后退。 迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组,集合对象都可用于创建迭代器:
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
print (next(it)) # 输出迭代器的下一个元素 1
print (next(it)) #2
- 迭代器的作用和特性
- 通过iter()方法将数据从内存中获取到–获取数据后交给next方法去执行结果集
结果:先有iter()方法,再有next方法,iter()方法和内存数据有关系,next方法和内存没有关系 - 迭代器由start开始----由end结束(中途不能中断,传递的是数据)
- 生成器----send方法表示的是当前的yield的值返回,不在执行next方法,但是next本身可以执行到最后,自动结束程序,这样操作是安全的
- 通过iter()方法将数据从内存中获取到–获取数据后交给next方法去执行结果集
生成器(generator)
使用了 yield 的函数被称为生成器。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次从当前位置继续运行。
注意:可以通过for循环或者手动调用 Xun(5) 的 next() 方法
def f():
print('start')
a = yield 1
print(a)
print('middle....')
b = yield 2 # 2这个值只是迭代值,调用next时候返回的值
print(b)
print('next')
c = yield 3
print(c)
a = f()
# print(next(a))
# print(next(a))
# print(next(a))
print(next(a))
print(a.send('msg'))
print(a.send('msg1'))
print(next(a))
- 生成器-send
a = yield 1 这个表达式,如果这个表达式只是x = 1,相信每个人都能理解是把1的值赋值给了x,
而现在等号右边是一个yield 1,所以先要执行yield 1,然后才是赋值.
yield把1值返回到了调用者那里,因为执行等号右边的yield就是暂停,所以不会对a赋值
那这个表达式的下一步操作:赋值,却换句话说a = yield 1 只执行了一半
send()里面的值的作用是把值传进当前的yield.
变量的作用域
一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。两种最基本的变量作用域如下:
- 全局变量
- 局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域
问:Java语言的的访问权限是什么?
答:print protected public default
问:python呢?
答:Python没有以上权限关键字的操作
def test01():
a=100
print(a)
print(id(a))
def test02():
#可以访问test01里面的常量a吗?----不可以
print('调用的a',a)#报错:a未定义,无法访问
test01()
test02()
局部变量只能在自己所定义的函数体里面访问,不能直接通过其他函数直接访问,
以上变量名称名称不一样----地址一样
-
可变类型的全局变量
对于不可变类型的全局变量来说,要在函数中修改需要global声明
对于可变类型的全局变量来说,要在函数中修改可以不使用global声明 -
局部变量
局部变量,就是在函数内部定义的变量
不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响 -
全局变量
全局变量是声明在函数外部的变量,定义在函数外的拥有全局作用域 -
修改全局变量
global关键字:要想在函数内部修改全局变量需要使用grobal关键字声明。
a = 100
print('打印全局变量%d'%a)
print(id(a))
def test1():
global a
a = 200
print('在test1函数内部使用修改全局变量a:%d'%a)
print(id(a))
def test2():
print('在test2函数内部使用全局变量a:%d'%a)
print(id(a))
test1()
test2()
print('打印全局变量a:%d'%a)
print(id(a))
#输出结果:
...
打印全局变量100
4401947136
在test1函数内部使用修改全局变量a:200
4401950336
在test2函数内部使用全局变量a:200
4401950336
打印全局变量a:200
4401950336
...