函数
- 函数是完成特定功能的一个语句组,这组语句可以作为一个单位使用,并且给它取一个名字,之后即可通过函数名执行。
- 使用def定义函数,函数名后的圆括号用来放置传递给函数的参数。
- 有返回值的函数,用return进行返回最终值。函数遇到return语句就会终止当前函数的执行,return之后的语句都会被忽略。
- 在python中,函数的参数可以有默认值,也支持使用可变参数,因而不需要支持函数重载,而是在定义函数时让它有多种不同的适用方式。
- 函数重载是一种特殊情况,有些语言允许在同一作用域中声明几个类似的同名函数,这些同名函数的形参列表(参数个数,类型,顺序)必须不同,常用来处理实现功能类似数据类型不同的问题,如不同数据类型的数值交换。
- python可以给函数参数设定默认值(缺省参数),意味着在没有对应位置参数传入时,将使用默认值,即可以通过不同的方式调用函数,这与函数重载效果一致。
- 在不确定参数个数时,可以使用可变参数,即在括号中参数名的前面添加*,表示它是一个可变参数。
- 局部变量只能在特定部分使用,全局变量整个程序都能使用。如果局部变量与全局变量名称相同,在局部变量作用的范围内是局部变量在起作用。如果想在函数内部对全局变量进行修改,需要使用global关键字。
- 函数优点:代码可重用,提高开发效率;代码更简洁,可读性好;编程更容易把握;封装和信息隐藏。使用函数进行程序设计,被称为结构化程序设计方法。
- 当两个不同.py文件(即模块,每个.py文件都是一个模块)中含有同样的函数名时,为防止函数覆盖,如module1.py和module.py两个模块都包含foo函数,有以下解决方式。除此之外,其他错误的导入调用方式,都会造成函数覆盖,后导入的会覆盖先导入的。
- a.调用谁导入谁
from module1 import foo
foo()
from module2 import foo
foo()
- b.将导入模块重新命名
import module1 as m1
import module2 as m2
m1.foo()
m2.foo()
- 如果导入的模块除了定义函数还含有可执行代码,那在导入模块的过程中会执行这些代码。因而,如果在模块中编写了执行代码,应当将代码放入
if _name_ == '_main_':
的条件中,_name_
是python中一个隐含的变量,代表了模块名,而只有被解释器直接执行的模块名才是_main_
。 - 在这种情况下,该模块被别的模块导入,由于导入名使用的是该模块名而非
_main_
,在if条件下的代码就不会被执行。 - python中可以在函数内部再定义函数,可以使用global关键字在函数内定义或使用全局变量,nonlocal关键字可以在函数内使用外层变量。
- 在实际开发中,应减少对全局变量的定义。全局变量作用于和影响过于广泛,可能会发生意料之外的修改和使用,此外比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被回收,同时也可以降低代码耦合度。
- 今后,就可以对代码的书写进行改进,书写成一下形式:
def main():
pass
if __name__ == '__main__':
main()
- 函数练习:给定年和月份,获得当月第一天是周几(从1800年1月1号开始计算,当天是周三),代码如下:
def is_leap_year(year):
if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
return True
else:
return False
def get_num_of_days_in_month(year, month):
if month in (1, 3, 5, 7, 8, 10, 12):
return 31
elif month in (4, 6, 9, 11):
return 30
elif is_leap_year(year):
return 29
else:
return 28
def get_total_num_of_day(year, month):
days = 0
for y in range(1800, year):
if is_leap_year(y):
days += 366
else:
days += 365
for m in range(1, month):
days += get_num_of_days_in_month(year, m)
return days
def get_start_day(year, month):
return (3 + get_total_num_of_day(year, month)) % 7
print(get_start_day(2033, 12))
递归函数
- 递归表现形式:在函数定义时有直接或者间接调用自身。
- 递归解决问题的基本思想:if问题足够简单则直接求解,else将问题分解成与原问题同构的一个或多个更小的问题逐个解决,将结果组合成为最终解返回。
- 汉诺塔问题解决思想:1、将前n-1个盘子通过c,从a移动到b;2、从a到c移动第n个盘子;3、将前n-1个盘子通过a,从b移动到c。定义函数hanoi(n,a,b,c)表示把a上的n个盘子移动到c上,其中可以遇到b,代码如下:
count = 0
def hanoi(n, a, b, c):
global count
if n == 1:
print('Move', n, 'from', a, 'to', c)
count += 1
else:
hanoi(n - 1, a, c, b)
print('Move', n, 'from', a, 'to', c)
count += 1
hanoi(n - 1, b, a, c)
print('')
hanoi(3, 'left', 'mid', 'right')
print('steps is', count)
- 递归方法的时间开销是比较大的,一般要比循环的方式慢得多。
- 递归优势:能使一个蕴含递归关系且结构复杂的程序简洁精炼,增加可读性;特别是在难于找到从边界到解的全过程的情况下,如果把问题推进一步,其结果仍维持原问题的关系。
- 递归劣势:嵌套层次深,函数调用开销大;重复计算。
字符串
- 所谓字符串,就是由零个或多个字符组成的有限序列,一般记为s=a1a2…an(0<=n<=无穷),下列代码可以了解字符串的基本使用。
def main():
str1 = 'hello, world!'
# 通过len函数计算字符串的长度
print(len(str1)) # 13
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Hello, world!
# 获得字符串变大写后的拷贝
print(str1.upper()) # HELLO, WORLD!
# 从字符串中查找子串所在位置
print(str1.find('or')) # 8
print(str1.find('shit')) # -1
# 与find类似但找不到子串时会引发异常
# print(str1.index('or'))
# print(str1.index('shit'))
# 检查字符串是否以指定的字符串开头
print(str1.startswith('He')) # False
print(str1.startswith('hel')) # True
# 检查字符串是否以指定的字符串结尾
print(str1.endswith('!')) # True
# 将字符串以指定的宽度居中并在两侧填充指定的字符
print(str1.center(50, '*'))
# 将字符串以指定的宽度靠右放置左侧填充指定的字符
print(str1.rjust(50, ' '))
str2 = 'abc123456'
# 从字符串中取出指定位置的字符(下标运算)
print(str2[2]) # c
# 字符串切片(从指定的开始索引到指定的结束索引)
print(str2[2:5]) # c12
print(str2[2:]) # c123456
print(str2[2::2]) # c246
print(str2[::2]) # ac246
print(str2[::-1]) # 654321cba
print(str2[-3:-1]) # 45
# 检查字符串是否由数字构成
print(str2.isdigit()) # False
# 检查字符串是否以字母构成
print(str2.isalpha()) # False
# 检查字符串是否以数字和字母构成
print(str2.isalnum()) # True
str3 = ' jackfrued@126.com '
print(str3)
# 获得字符串修剪左右两侧空格的拷贝
print(str3.strip())
if __name__ == '__main__':
main()
- 字符串(String)是一个字符的序列,表示时需要使用成对的单引号或双引号括起来。也可以使用成对的三引号,这种情况下会保留字符串中的所有格式信息。想要在字符串中输入引号的话,需要在引号前加入转义字符“\”。
- 拼接:”+“,将两个字符串拼接起来,但不能拼接整数,除非也用引号括起来。
重复:“*”,字符串乘以整数(位置可以互换),表示重复整数次。 - 成员运算符in:判断一个字符串是否为另一个字符串的子串,返回值为Ture或False,示例如下,x的值即为False。
name = 'hello world'
x = 'a' in name
print(x)
- for语句:枚举字符串的每个字符,示例如下,结果就会每个字符包括空格在内各占一行,顺序打印出来。
name = 'hello world'
for x in name:
print(x)
- for与in的练习:输入一串字母,将其中为元音的字母打印出来,实现代码如下,输入若为abcde,则打印结果即为ae。
def vowles_count(s):
for c in s:
if c in 'aeiouAEIOU':
print(c, end="")
a = input()
vowles_count(a)
- 字符串索引:字符串中每个字符都有一个索引值(下标),索引从0、1…(前向后)或-1、-2…(后向前)开始。
索引运算符[]:[]中的数字代表获得字符串中第几个字符,要注意索引的开始值。 - 切片:用来选择字符串的子序列,语法为[start:finish],其中start为子序列开始位置的索引值,finish为子序列结束位置的下一个字符的索引值。如果不提供start或finish,默认start为第一个字符开始,finish为最后一个字符。finish可以超出字符串的范围,也表示到字符串的尾部。
- []中还可以写入第三个参数,为计数参数,即[start:finish:countBy],默认countBy为1,即获得连续的子字符串,如果提高countBy的值到2,则会每次跳过一个字符,以此类推。countBy也可以为负数,则获得逆字符串,但此时要注意两个参数的取值,可以两个都不填,意味着从尾到头获得该字符串。
- 字符串一旦生成是不可变的,如果想要改变字符串中的某一个内容,则需通过切片等操作获得一个新的字符串,可以选择将新字符串赋值给原字符串,也可以使用字符串方法。
- 字符串方法:即对象提供的函数,如变量名.replace(old,new)方法,即生成一个新的字符串,使用new替换old子串,示例如下,这样s中所有的e都变成了a。
s = 'hello world'
s = s.replace('e', 'a')
print(s)
- 更多字符串方法:find(‘字符’)方法,即找到第一次出现该字符的下标;split()函数,括号中若无参数,则是在字符串空格的位置对原始字符串进行切分。关于字符串的方法,可以使用dir(str)函数来浏览。
- 文件操作:
打开文件:f = open(filename,mode),其中mode有r(读,默认),w(写)等。
按行读取文件内容:for line in f:pass。
关闭文件:f.close()。
写文件:f.write(str)。 - 练习:读取人名列表文件names.txt,将每个人名转换为首字母大写,其他字母小写的格式,实现代码如下,其中人名文件与代码文件注意放在同一存储空间。
strip()函数可以用来去掉一个字符串开头结尾的空格回车等。
title()函数可以将字符串转化为首字母大写,其他字母小写的格式。
f = open('names.txt', 'r')
for line in f:
line = line.strip()
print(line.title())
f.close()
- 字符串大小用字典序来表示:
首先比较两个字符串的第一个字符。
如果相同则比较下一个,如果不同则由第一个字符决定大小关系。
如果其中一个字符为空(较短),则其更小。 - 字符串格式化使用format()方法:
format()中的参数都用来替换{}的内容,{}的格式为{field name:align width.precision type},比如{:9.4f},即占据9个字符,并以4位的小数精度输出{}中的值,示例如下。
如需调用math包中的pi,则需先声明math包,即import math。
>>>print('PI is {:9.4f}'.format(3.1415926))
PI is 3.1416
- 判断一个人名是否满足下列模式:
判断其是否为Michael,则有Michale : name == ‘Michael’。
是否以Mi开始:name[:2] == ‘Mi’。
是否包含cha子串:‘cha’ in name。
但如需判断以下情况:是否包含c?a子串(即c与a中间隔字符不确定),是否包含c*e子串(即表示任意多个字符),则需要用到正则表达式。 - 正则表达式用来描述字符串的模式:
.表示任意字符。
\d+表示一系列数字。
[a-z]表示一个小写字母。
正则表达式还包含很多内容,不再赘述。 - 练习:判断一个人名是否含有C.A模式,即C与A之间相隔任意字符,代码如下。
import re
f = open('names.txt')
for line in f:
line = line.strip()
pattern = 'C.A'
result = re.search(pattern, line)
if result:
print('Name is {}'.format(line))
f.close()