1.6 函数设计
函数的概念
函数可以用来定义可重用代码、组织和简化代码
# 计算1~10的和
sum = 0
for i in range(1, 11):
sum += i
print(sum)
# 计算2~22的和
sum = 0
for i in range(2, 23):
sum += i
print(sum)
# 计算9~101的和
sum = 0
for i in range(9, 102):
sum += i
print(sum)
# 封装——本不需要向外界提供的内容隐藏起来
def getSum(a, b):
result = 0
for i in range(a, b + 1):
result += i
return result
sum = getSum(1,10)
print(sum)
sum = getSum(2,22)
print(sum)
sum = getSum(9,101)
print(sum)
函数是为实现一个操作而集合在一起的语句集
函数有什么好处:
- 函数的使用可以重用代码,省去重复性代码的编写,提高代码的重复利用率
- 函数能封装内部实现,保护内部数据,实现对用户的透明
- 函数使得程序变得模块化,分工明确,利于阅读、调试和修改。
函数的定义
函数的组成部分主要有:函数名称,参数,函数体和返回值
def 函数名称(参数):
函数体
return 返回值
参数被称为形式参数或者叫形参,当外界调用函数时,将会传一些数据,这些数据就会被形参所接收。被传进来的数据叫做实际参数或实参。参数是可选的,有的函数不需要传参。
num1 = 30;
num2 = 40;
sum = getSum(num1,num2)
print(sum)
某些函数有返回值,而有一些函数没有返回值的。没有返回值就没有return吗?如果没有返回值,return就被隐藏了。
def getSumPrint(a,b):
result = 0
for i in range(a, b + 1):
result += i
print(result)#内部就将数据输出了并不需要返回值,注意理解该输出结果本质上并不等同于return
# return
getSumPrint(10,20)
函数体包含一个定义函数做什么的语句集。
return仅仅表示函数运行结束,一旦函数执行过程遇到return语句,那么函数之后所有的代码都被忽略,直接跳出函数体,函数立即结束,哪怕在一个循环中。并且函数没有返回值的话默认返回None(空类型);如果有返回值的话,写在return之后即可,结束函数并将结果返回个调用者。
def func01(a):
if a == 10:
print("哈哈")
return
print("嘻嘻")
return
func01(11)
res = func01(10)
print(type(res))
def func02(a):
for i in range(1,11):
if i == a:
print(i)
# break 跳出循环 接着向下运行(落入if会打印啦啦)
return # 直接结束函数(落入if不会打印啦啦)
print(i)
print("啦啦")
return
func02(11)
func02(4)
return都可以返回什么?
- 什么都不返回:
return
- 任意数据类型:
return 'hello'
- 一个表达式:
return 1 + 2
#会先运算再返回 - 一个判断语句:
return 3 > 2
#返回布尔类型 - 一个变量:
return a
- 一个函数的调用:
return func()
- 多个返回值,以逗号分隔:
return a,1+2,'hello'
#python特点 - 甚至返回自己:
return self
#面向对象中使用
函数可以return几乎所有的Python数据对象。
参数的传递
函数通常都有参数,用于将外部的实际数据传入函数内部进行处理。但是,在处理不同数据类型的参数时,会发生以下两种情况:
- Python的函数传递参数时,传递的是实际对象的内存地址
- Python的数据类型,主要分为可变对象,不可变对象(目前所学常数、布尔类型等都是不可变对象)
def func(a): # 局部变量
print("函数内部没有修改前",id(a)) # 712
a = 2
print("函数内部修改后",id(a)) # 744
print("函数内部修改后a=",a) # 2
return
a = 1 # 全局变量
print("调用函数之前",id(a)) # 712
func(a)
print("调用函数之后",id(a)) # 712
print(a)
注意理解这里,没调用前a的内存地址,和调用函数是时第一步打印的地址其实做的是一样的事情,只是一个在外面单独做一个在函数体里做。最后一步函数执行完a的地址和最开始的一样,因为这个a 是全局变量,变量没有改变,分配的内存空间也不会变,函数结束后,对于全局变量的值a并没有改变。(不改变是因为返回值没有改变!“你只是短暂的爱了一下,而我却像过完了余生”)
实参和形参传递的是地址
def test(lst) :
lst.append(4)表后面加个4
print(id(lst))
print(lst)
lst = [1,2,3] # 列表
print(id(lst))
test(lst)
print(id(lst))
print(lst)
并不是重新产生一个列表而是在原先的列表上进行更改,但凡能在原先的数据上进行更改的都视为可变对象,不能在原数据上进行更改的叫不可变对象。
*/关于参数的传递,由于Python是动态语言,变量没有数据类型区分,所以函数是不会检测实参的数据类型,但会是检测个数;数据类型的检测只有在函数内部运行时才会被检测出来。
*/
def add(a, b):
return a + b
add(1, 2)
add(1, 2, 3)
Traceback (most recent call last):
File "C:/Users/HENG/Desktop/PythonCode/Day04/FunctionTest05.py", line 5, in <module>
add(1, 2, 3)
TypeError: add() takes 2 positional arguments but 3 were given
add(1, "hello")
Traceback (most recent call last):
File "C:/Users/HENG/Desktop/PythonCode/Day04/FunctionTest05.py", line 6, in <module>
add(1, "hello")
File "C:/Users/HENG/Desktop/PythonCode/Day04/FunctionTest05.py", line 2, in add
return a + b
TypeError: unsupported operand type(s) for +: 'int' and 'str'
函数的运行机制
栈是一种先进后出的容器。
函数是基于栈运行的。每次调用一个函数时,系统会自动创建一个关于该函数的内存空间,也称为栈帧,存的它的参数和变量以及执行语句,然后将该栈帧进栈开始运行。当一个函数调用另一个新的函数时,接着系统创建一个新的栈帧,将该栈帧进栈开始运行,那么第一个函数就暂停,直到其上的所有函数执行完毕后,第一个函数接着继续执行。
def multi(a, b, c):
return a ** 2, b ** 2, c ** 2
def add(a, b, c):
return a + b + c
def out(s):
print(s)
def test(a, b):
num1, num2, num3 = multi(a, b, a + b)
out('hello')
return add(num1, num2, num3)
num = test(2, 3)
print(num)
理清以上函数调用顺序流程!!!
变量的作用域
在函数内部定义的变量称之为局部变量。局部变量只能在函数内部访问。局部变量的作用域所在函数进栈开始执行,直到该函数结束出栈。
同样可以定义全局变量,在所有函数之外定义,可以被所有的函数访问。
示例1:
globalVar = 1
num1 = 3
num2 = 10
def f1():
localVar = 2 # 局部变量 在该函数内创建
print(globalVar) # 全局变量
print(localVar) # 局部变量
print(num1 + 3) # num1 全局变量
num2 = 20 # 局部变量 在该函数内创建
print(num2)
# 如果直接将全局变量,参与运算num1+3,直接打印 调用的就是全局变量
# 如果是对全局变量进行修改num2=20,则为创建一个同名的局部变量
f1()
print(globalVar)
print(num2)
# NameError: name 'localVar' is not defined
# print(localVar)不注释掉的话会报错,因为局部定义的变量不能用于全局
示例2:
#错误示例
#x = 1
#def f2():
#print(x)此时会报错,底下有x 局部变量的定义会认为没有定义就调用,如果地下没有x的定义就会默认是全局变量,要改成下面的正确程序示例才可以
#x = 2
#f2()
#print(x)
x = 1
def f2():
global x # 在函数内部将x标记为全局变量,如果存在则复用,不存在则创建全局变量(外面没有x=1)
x = 2
print(x)
f2()
print(x)
注意这里与上面讲诉可变对象和不可变对象的不同在于在函数中声明了x为全局变量,接下来在函数中对x的修改都是对全局变量的修改,所以函数调用完之后x是2不是1.
示例3:
x = int(input("Enter a number:"))
if x > 0:
y = 4 # 全局变量 只有在x>0的条件下创建
print(y)
Enter a number:-10
Traceback (most recent call last):
File "C:/Users/HENG/Desktop/PythonCode/Day04/FunctionTest05.py", line 52, in <module>
print(y)
NameError: name 'y' is not defined
示例4:
sum = 0
for i in range(5): # i 全局变量
sum += i
print(i) # --> 4
1.7 序列结构
可变对象和与可变对象
Python中内置数据类型主要有三大类:
- 数字:整型、浮点型
- 序列:字符串、列表、元组、集合
- 映射:字典
按照是否可以原地修改分为两大类:
-
不可变对象(数字,字符串,元组,不可变集合)
不可变的分类中没有哪个对象类型支持原地修改,但可以创建新的对象并将结果赋予变量
-
可变对象(列表,字典,可变集合)
相反,可变的类型总是可以通过相关的操作进行原处修改,而不需要创建新的数据对象
序列的通用操作
索引,切片,相加,相乘,迭代和成员资格检查
索引操作
索引中的所有元素都有编号(角标),角标从0开始计数,当然在Python当中,也可以使用负角标来访问元素,所有最后一个元素的角标-1(倒数第一个)
>>> word = "hello"
>>> word[0]
'h'
>>> word[2]
'l'
>>> word[-1]
'o'
>>> word[-5]
'h'
>>> word[10]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
对于序列的字面量,可以直接用角标操作,而不需要变量
>>> "hello"[3]
'l'
>>> "hello"[-1]
'o'
切片操作
索引是一次去一个数据,切片是一次取一片数据,要定开始和结尾,包括步长(默认为1)
和range一样取左不取右
>>> word = "12345678"
>>> word[0:3]
'123'
>>> word[-3:-1]
'67'
不管是正索引,还是负索引,必须要保证顺序
>>> word[1:8:2]#取的是角标1357位的
'2468'
>>> word[-6:-2:3]
'36'
>>> word[7:1:-2]
'864'
>>> word[-1:-5:-1]
'8765'
>>> word[-1:-5:1]
''
>>> word[:]
'12345678'
>>> word[2:]
'345678'
>>> word[:5]
'12345'
>>> word[-5:]
'45678'
>>> word[-3::-1]
'654321'
步长是正数,开始~结尾 递增
步长是负数,开始~结尾 递减
>>> text = "我爱你"
>>> text = text[::-1]#字符串反置
>>> text
'你爱我'
>>> text = text[-1:-4:-1]
>>> text
'我爱你'
相加操作
指的是两个序列合并,会产生新的序列对象,不会改变原先序列的值
>>> s1 = "abc"
>>> s2 = "ABC"
>>> s1 + s2
'abcABC'
>>> s1
'abc'
>>> s2
'ABC'
相加只能是在同类型序列之间进行
相乘操作
将序列与数字x相乘,将重复这个序列x次创建一个新的序列
>>> s1
'abc'
>>> s3 = s1 * 3
>>> s3
'abcabcabc'
迭代操作
可以在for循环中迭代序列中的每一元素,或者迭代角标来获取元素
>>> s1
'abc'
>>> for i in s1:
... print(i)
...
a
b
c#迭代元素,不能修改,只能访问
>>> for i in range(len(s1)):
... print(s1[i])
...
a
b
c#迭代角标打印角标对应的元素,可以遍历元素也可以修改
>>> word[0] = '9'#word='12345678',此时不可这样修改,因为字符串是不可变对象,但是列表可以,因为列表是可变对象
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
字符串是不可变对象
成员资格检查操作
就是验证一个数据元素是否存在于当前序列当中
word='12345678'
>>> '8' in word
True
>>> 8 in word#字符不等同于数值
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'in <string>' requires string as left operand, not int
>>> '10' not in word
True
>>> '10' in word
False
>>> 5 in range(0,10)
True
字符串
不可变对象,一个有序的字符集合,用于存储和表现基本文本信息
字符串不允许原地修改值,字符串的长度大小一旦定义则不能修改
如果真想去修改字符串的话,只能创建一个该字符串的副本,副本的内容就是修改过后的内容
测试字符串方法
- isalnum():验证是否只包含数字和字母
- isalpha():验证是否只包含字母
- isdigit():验证是否只包含数字
- isidentifier():验证是否是合法的标识符#标准自定义名称
- islower():验证内容当中字母是否全小写
- isupper():验证内容当中字母是否全大写
- isspace():验证是否只包含空格
搜索字符串方法
- endswith(str):验证是否已str后缀结尾
- startswith(str):验证是否已str前缀开始
- find(str):返回str从左到右第一次出现的角标,如果不存在返回-1。rfind()相反
- index(str):功能和find一样,如果不存在则有异常
- count(str):记录str出现的次数,不带覆盖
转换字符串
- capitalize():将字符串复制并大写第一个字母
- lower():将所有字母转小写
- upper():将所有字母转大写
- title():将字符串复制并将每个单词的首字母大写
- swapcase():将字符串复制,将小写转大写,将大写转小写
- replace(a,b):将原先字符串中a替换为b,产生新字符串
- split(str):将str为分隔符,将字符串分割,结果是一个字符列表
- partition(str):以str为中心部分,将字符串分为左右两部分
删除字符串空格
- lstrip():删除字符串左边的空格
- rstrip()
- strip():删字符串两边的空格
格式化字符串
- center(w):以w为宽度,让内容居中显示
- ljust()
- rjust()
>>> "123abc".isalnum()
True
>>> "我爱你123abc*!&@%#^&%&".isalnum()
False
>>> "abc".isalpha()
True
>>> "123".isalpha()
False
>>> "123abc".isalpha()
False
>>> "123".isdigit()
True
>>> "abc".isdigit()
False
>>> "sum".isidentifier()
True
>>> "123abc".isidentifier()#合法标识符不能以数字开头
False
>>> "abc".islower()
True
>>> "ABC".islower()
False
>>> "123abc".islower()
True
>>> " ".isspace()
True
>>> " ad asd asd".isspace()
False
>>> "大桥.avi".endswith(".avi")
True
>>> "宇智波早乙女".startswith("宇智波")
True
>>> "宇智波早乙女".startswith("波波")
False
>>> "123,456,789".find("456")
4
>>> "123,456,789".rfind("456")
4
>>> word = "123456789456"
>>> word.find("456")
3
>>> word.rfind("456")
9
>>> word
'123456789456'
>>> word.index("123")
0
>>> word.index("456")
3
>>> word.find("666")
-1
>>> word.index("666")#不存在就出错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> "121212121".count("121")
2
>>> name = "anglababy"
>>> name.capitalize()
'Anglababy'
>>> name
'anglababy'
>>> "Andy Mimi Lala".lower()
'andy mimi lala'
>>> "Andy Mimi Lala".lower().upper()
'ANDY MIMI LALA'
>>> "mynameishaha".title()
'Mynameishaha'
>>> "my name is haha".title()
'My Name Is Haha'
>>> s= "my name is haha".title()
>>> s
'My Name Is Haha'
>>> s.swapcase()
'mY nAME iS hAHA'
>>> s = "宇智波萨斯尅,宇智波马达啦,宇智波一大气,宇智波欧鼻头"
>>> s.replace("宇智波","千手")
'千手萨斯尅,千手马达啦,千手一大气,千手欧鼻头'
>>> s
'宇智波萨斯尅,宇智波马达啦,宇智波一大气,宇智波欧鼻头'
>>> s.split(",")#分割成一个列表
['宇智波萨斯尅', '宇智波马达啦', '宇智波一大气', '宇智波欧鼻头']
>>> l = s.split(",")
>>> l[1]
'宇智波马达啦'
>>> "莫西莫西海雅库摩多摩多".partition("雅")
('莫西莫西海', '雅', '库摩多摩多')
>>> "123456789".partition("456")
('123', '456', '789')
>>> " 123".lstrip()
'123'
>>> "123 ".rstrip()
'123'
>>> " 8798 ".strip()
'8798'
>>> "I Love You".center(16)
' I Love You '
>>> s = "abc"
>>> s.center(10)
' abc '
>>> s.ljust(10)
'abc '
>>> s.rjust(10)
' abc'
emm,声明:以上示例都是老师上课举的例子,我只是copy过来整理补充了点东西