今天来学习函数的概念。不要惊慌,python中使用的函数和数学课上学的函数并不是同一个概念。
如果我们现在从程序员改行当了汽修工,日常工作是给各位顾客的汽车做保养维护、检修等等工作,我们不可避免地要使用各种各样的螺丝刀、扳手、老虎钳、千斤顶等等工具来作业。
但是,我们并不是每日上工前架好炼钢炉从熔炼铁矿开始从头锻造工具。而是一开始就去五金店或工厂购买一整套工具。这些工具都是耐用品,不至于用上一次就坏掉要买新的。
python中的函数也是一样。这里的函数就相当于我们从五金店买来的工具,事先定义好后续可以反复使用,这样就避免了代码冗余的情况,大大节省了程序员们的劳动量。
# 函数的语法结构 def 函数名(参数1,参数2): '''函数的注释''' 函数体代码 return 函数的返回值 eg: def print_sth(): '''随便打印些什么东西''' print('something') return '^_^'
接下来我们来详细说说函数语法的各个组成部分。
1.def:定义函数的关键字。
2.函数名:函数名的命名规则与变量名保持一致,见名知意。
3.参数:函数在使用之前还可以接收外部传入的参数(即限制条件)。
4.函数的注释:类似于产品说明书。
5.函数体代码:整个函数主要功能逻辑,是整个函数的核心。
6.return:执行完函数之后可以给调用者一个反馈结果。
注意:函数一定要先定义后使用!!!
定义函数需要使用关键字def,后面跟着函数名加括号(如果函数需要参数那么括号里额外传递参数)。
函数在定义阶段只检测函数体语法不执行函数体代码。如果函数体中有语法错误,定义阶段是不会报错的。
函数名加括号。调用函数的时候才会执行函数体代码。
什么是返回值?
答:返回值即执行完某个方法后,该方法反馈出来的结果。
如何获取返回值?
答:通过变量名与赋值符号即可。
变量名 = 方法/函数()
def index(): print('hello world') res = index() print(res) # None即空 表示没有
def index(): print('hello world') return 123 res = index() print(res) # 123
def index(): print('hello world') return 114, 514, 9527, 42, 666 res = index() print(res) # (114, 514, 9527, 42, 666)
def index(): print('hello world') return print('disco disco good good!') index()
函数中的return类似于循环中的break。
def 函数名(): 函数体代码 eg: def index(): print('hello world!') index()
def 函数名(参数): 函数体代码 eg: def welcome_word(x): print('欢迎使用windows', x) welcome_word('joe')
在使用有参函数时必须给一个参数,可以是任意数据,所以只要想一个打印标语的函数记忆就可以了。
一般用于前期的架构搭建。在没有想好具体的功能时先暂且记下,功能类似于占位符。
def run(): pass # 补全语法结构 本身没有任何含义 def fight(): pass def talk(): pass
函数在定义阶段括号内书写的变量名称之为函数的形式参数,简称为形参。函数的形参相当于变量名。
函数在调用阶段括号内书写的值称之为函数的实际参数,简称为实参。函数的实参相当于变量值。
两者在调用函数时临时绑定,函数运行结束分开。
def 函数名(形式参数): # 定义阶段 函数需要执行的代码 函数名(实际参数) # 调用阶段 eg: def index(name): # 括号内的是形参 print(name) index('joe') # 括号内是实参;相当于变量name = 'joe'
def 函数名(位置形参1, 位置形参2...) 函数需要执行的代码 函数名(位置实参1, 位置实参2) eg: def index(x, y): print(x, y) index() '报错'# 不传不可以 index(1) '报错'# 传少了也不行 index(1,2) # 个数正确可以 index(1,2,3,4,5,6,7) '报错'# 传多了也不行
def 函数名称(关键字形参1, 关键字形参2) 函数需要执行的代码 函数名(关键字实参1=xxx, 关键字实参2=xxx) eg: def index(x, y): print(x, y) index(x=111, y=222) # 按照参数顺序传值,可以 index(y=111, x=222) # 颠倒参数顺序传值,可以 index(111, y=222) # 先按照位置参数传值,后按照关键字,可以 index(111, x=222) '报错'# 位置参数必须和参数顺序一致 index(y=111,222) '报错'# 位置参数一定要在关键字参数的前面
def 函数名(参数1, 参数2, 默认参数1=xxx): 函数需要执行的代码 函数名(参数1, 参数2, 若数据不同于默认参数1时自行赋值) eg: def register(name, age, gender='male'): print(name, age, gender) '''默认参数不给值的情况下就使用默认的 给了就使用给了的''' register('joe', 18) register('simon', 20) register('frank', 22) register('diana', 17, 'female') # 这条登记的是女性,所以要把默认参数修改掉
现在甲方提出了一个需求:函数如何做到无论接收多少个位置参数都可以正常运行?
这里就需要用到可变长参数了。
def func(a, *b): print(a, b) func(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # 1 (2, 3, 4, 5, 6, 7, 8, 9, 10) func(1) # 1 ()
*在形参中使用时,会接收多余的位置参数组织成元组的形式赋值给后面的变量名。
好神奇哦,但是仅此而已吗?
需求2:函数如何做到无论接收多少个关键字参数都可以正常运行?
def func(a,**b): print(a,b) func(a=1, b=2, c=3, d=4 ,e=5) # 1 {'b': 2, 'c': 3, 'd': 4, 'e': 5} func(a=1) # 1 {}
**在形参中使用时,会接收多余的关键字参数组织成字典的形式赋值给后面的变量名。
星号这个符号可以稍微记一下,接下来会在各种场景中以不同的身份或用法出现,它会成为我们的老朋友。
小练习
定义一个函数,该函数无论接收多少个位置参数还是关键字参数都可以正常运行。
def func(*a, **b): print(a, b) func(1, 2, 3, a=1, b=2, c=3) # (1, 2, 3) {'a': 1, 'b': 2, 'c': 3} func(1, 2, 3, 4, 5, 6, 7) # (1, 2, 3, 4, 5, 6, 7) {} func(a=1, b=2, c=3, d=4, e=5) # () {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
约定俗成方式:针对形参中的可变长参数,变量名推荐使用:
*args # 位置参数 **kwargs # 关键字参数 eg: def sth(*args, **kwargs): print(args, kwargs) sth(1, 2, 3, a=1, b=2, c=3) # (1, 2, 3) {'a': 1, 'b': 2, 'c': 3} sth(1, 2, 3, 4, 5, 6, 7) # (1, 2, 3, 4, 5, 6, 7) {} sth(a=1, b=2, c=3) # () {'a': 1, 'b': 2, 'c': 3}
现在有一个列表l和一个字典d,另有一个展示任意参数的函数。现在需要将列表l中的元素取出挨个打印,该怎么做?
l = [11, 22, 33, 44, 55] d = {'username': 'joe', 'pwd': 123, 'hobby': 'read'} def func(*args, **kwargs): print(args, kwargs)
func(*l) # (11, 22, 33, 44, 55) {}
现在需要将字典d中的元素取出挨个打印,该怎么做?
func(**d) # () {'username': 'joe', 'pwd': 123, 'hobby': 'read'}
将面条版代码封装成函数版,遵循以下几条原则:
1.先写def和函数名
2.将代码缩进
3.查看内部需要哪些数据
4.在形参中定义出来即可
在实际封装代码时,尽量做到一个函数就是一个具体的功能。
def register(): username = input('username>>>:').strip() password = input('password>>>:').strip() # 校验用户名是否存在 with open(r'userinfo.txt', 'r', encoding='utf8') as f: for line in f: real_name = line.split('|')[0] if real_name == username: print('用户名已存在') return # 将用户名和密码写入文件 with open(r'userinfo.txt', 'a', encoding='utf8') as f: f.write('%s|%s\n' % (username, password)) print('%s注册成功' % username) def login(): username = input('username>>>:').strip() password = input('password>>>:').strip() with open(r'userinfo.txt', 'r', encoding='utf8') as f: for line in f: real_name, real_pwd = line.split('|') if real_name == username and password == real_pwd.strip('\n'): print('登录成功') return print('用户名或密码错误') func_dict = {'1': register, '2': login } while True: print(""" 1 注册 2 登录 """) choice = input('请输入执行功能编号>>>:').strip() if choice in func_dict: func_name = func_dict.get(choice) func_name() else: print('请输入正确的编号')View Code
def auth_username(username): # 校验用户名是否存在 with open(r'userinfo.txt', 'r', encoding='utf8') as f: for line in f: real_name = line.split('|')[0] if real_name == username: print('用户名已存在') return True return False def get_info(): username = input('username>>>:').strip() password = input('password>>>:').strip() return username, password def write_data(username, password): # 将用户名和密码写入文件 with open(r'userinfo.txt', 'a', encoding='utf8') as f: f.write('%s|%s\n' % (username, password)) print('%s注册成功' % username) def register(): username, password = get_info() # 调用校验用户名是否存在的函数 is_exist = auth_username(username) if is_exist: return write_data(username, password) def login(): username, password = get_info() with open(r'userinfo.txt', 'r', encoding='utf8') as f: for line in f: real_name, real_pwd = line.split('|') if real_name == username and password == real_pwd.strip('\n'): print('登录成功') return print('用户名或密码错误') func_dict = {'1': register, '2': login } while True: print(""" 1 注册 2 登录 """) choice = input('请输入执行功能编号>>>:').strip() if choice in func_dict: func_name = func_dict.get(choice) func_name() else: print('请输入正确的编号')View Code
abs() eg: print(abs(114)) # 114 print(abs(-514)) # 514 print(abs(95.27)) # 95.27
all() eg: print(all([1, 2, 3, 4, 5])) # True print(all([1, 2, 3, 4, False])) # False
用来判断列表中元素的布尔值是否是一致的,功效大致等同于逻辑判断中的and。
any() eg: print(any([1, 2, 3, 4, 5])) print(any([1, 2, 3, 4, False]))
与一致判断正相反,有一个为True即可。
print(bin(100)) print(oct(100)) print(hex(100))
这三个公式我们在讲解数据内置方法时就已经见到了。实际上有许多数据内置方法就是官方已经封装好的函数。按住Ctrl再点击这些语句,就可以打开解释这些语句的说明文档。
callable(变量名或函数名) eg: name = 'joe' def index(): pass print(callable(name)) # False print(callable(index)) # True
chr(ASCII码中的编号) eg: print(chr(65)) # A print(chr(122)) # z
在ASCII码中,大写字母A~Z对应的数字是65~90,小写字母a~z对应的数字式97~122。
之前格式化输出用的是占位符%s和%d,接下来又增加了一个更好用的函数版本。
.format(输出的字符串) eg: print('my name is {} and my age is {}.'.format('joe', 18)) # my name is joe and my age is 18. print('{0} {0} {1} {1}!'.format('disco', 'good')) # disco disco good good! print('{noun} {noun} {adj} {adj}!'.format(noun='disco', adj='good')) # disco disco good good!
enumerate(列表,起始位) eg: l = ['joe', 'simon', 'frank', 'jerry', 'eddie'] for i, name in enumerate(l, 10): print(i, name)
max(列表) # 求最大值 min(列表) # 求最小值 sum(列表) # 求和 eg: l = [11, 22, 33, 44, 55, 66, 77, 88, 99] print(max(l)) # 99 print(min(l)) # 11 print(sum(l)) # 495
这些功能也是excel里常见的公式,所以这里不多赘述了。
很多软件(包括编程语言)都是一通百通,触类旁通的。只要一项工具的使用方法熟练扎实的,那么其他的类似的软件也都是上手摸索几分钟就同样可以流畅使用了。