Python—第12天—函数模块
导入模块
如果要使用其他文件(模块)中定义的函数:
- 方法一:面以通过import导入模块,然后通过"模块名.函数名"的方式调用函数;
- 方法二:直接从模块中导入函数—>"from 模块 import 函数 ”—>直接通过函数名调用函数
import导入函数、模块时,可以使用as关键字(alias)进行别名
Python中的from、import、as关键字就是专门用来处理包和模块导入的操作
做工程化项目开发时,如果项目中的代码文件非常多,我们可以使用"包"(package)来管理"模块"
再通过模块来管理函数,包其实就是一个文件夹,而模块就是一个Python文件。通过这种方式就可以
大型项目团队开发中经常遇到的命名冲突的问题。
创建一个"包"(package)
练习1:
获取A班和B班的考试成绩的描述性统计信息,比较A班和B班哪个班的学习效果更理想。
我们先在“包”里创建一个文件用来定义我们需要的函数
import math
import random
def ptp(data):
"""求极差(全距)"""
return max(data) - min(data)
def average(data):
"""求均值"""
return sum(data) / len(data)
def variance(data):
"""求方差"""
x_bar = average(data)
temp = [(num - x_bar) ** 2 for num in data]
return sum(temp) / (len(temp) - 1)
def standard_deviation(data):
"""求标准差"""
return math.sqrt(variance(data))
def median(data):
"""找中位数"""
temp, size = sorted(data), len(data)
if size % 2 != 0:
return temp[size // 2]
else:
return average(temp[size // 2 - 1: size // 2 + 1])
if __name__ == '__main__':
nums = [random.randrange(1, 100) for _ in range(8)]
print(nums)
print(f'均值: {average(nums)}')
print(f'中位数: {median(nums)}')
print(f'极差: {ptp(nums)}')
print(f'方差: {variance(nums)}')
print(f'标准差: {standard_deviation(nums)}')
__name__是一个隐藏变量,它代表了当前模块(文件)的名字
如果直接运行 文件名.py 这个文件,name__的值是__main
如果是在其他的模块(文件)中导入 文件名.py,那么此时__name__的值就是 文件名.py
我们在主文件夹下创建一个文件来完成我们的练习题
import random
from demo.state import average as avg, median, variance, standard_deviation as std
# 从demo的包下的state文件里导入各类需要的函数,用as作别名
class_a_scores = [random.randrange(50, 101) for _ in range(50)]
class_b_scores = [random.randrange(50, 101) for _ in range(50)]
print('A班考试成绩描述统计信息')
print(f'A班平均分为:{avg(class_a_scores)}')
print(f'A班中位数为:{median(class_a_scores)}')
print(f'A班方差为:{variance(class_a_scores)}')
print(f'A班标准差为:{std(class_a_scores)}')
print('B班考试成绩描述统计信息')
print(f'B班平均分为:{avg(class_b_scores)}')
print(f'B班中位数为:{median(class_b_scores)}')
print(f'B班方差为:{variance(class_b_scores)}')
print(f'B班标准差为:{std(class_b_scores)}')
练习2:
设计一个函数,检查字符串(算术表达式)中的括号是否完全匹配。
例如:(2 + 3) * 5 * [80 - 20] —> True
例如:([{2 + 3} - (1)] * 10 —> False
例如:[{2 + 3} - (1)] * 10) —> False
例如:[{2 + 3} - (1] * 10) —> False
算法:循环遍历字符串的每个字符,如果遇到左括号,将元素添加到栈中;如果遇到右括号,就从栈中取出一个左括号,如果取不出左括号,直接返回False;如果能够取出左括号,检查二者是否匹配;如果不匹配,直接返回False;如果匹配,继续检查。循环遍历结束以后,检查栈是否为空,如果不为空,返回False
def check(expression: str) -> bool:
"""检查表达式中的括号是否匹配
:param expression: 表达式
:return: 如果括号匹配返回True,否则返回False
"""
stack = []
bdict = {'(': ')', '[': ']', '{': '}'}
# 循环变量字符串中的每个字符
for ch in expression:
# 如果遇到左括号就入栈
if ch in ('(', '[', '{'):
stack.append(ch)
# 如果遇到右括号
elif ch in (')', ']', '}'):
# 如果栈为空(有右括号,但是没有与之匹配的左括号),直接返回False
if len(stack) == 0:
return False
# 将左括号出栈,检查与当前的右括号是否匹配
left = stack.pop()
if bdict[left] != ch:
return False
# 检查栈是否为空(如果栈不为空,说明有左括号但是没有与之匹配的右括号)
return len(stack) == 0
if __name__ == '__main__':
print(check('(2 + 3) * 5 * [80 - 20]'))
print(check('([{2 + 3} - (1)] * 10'))
print(check('[{2 + 3} - (1)] * 10)'))
print(check('[{2 + 3} - (1] * 10)'))
列表(list)—> 可以模拟出 stack 和 queue 的效果
栈(stack)—> FILO —> 有一个列表,如果我们将添加和删除元素都限制在列表的末尾
~ 添加元素:append() —> 入栈(push)
~ 删除元素:pop() —> 出栈(pop)
队列(queue)—> FIFO —> 有一个列表,如果我们限制它只能在尾部添加元素,只能在头部删除元素
~ 添加元素:append() —> 入队(enqueue)
~ 删除元素:pop(0) —> 出队(dequeue)
命名冲突
先建立两个"包"(package)
在utils包下创建bar.py和foo.py文件
# bar.py
def say_hello():
print('goodbye world')
# foo.py
def say_hello():
print('hello world')
我们可以发现不同文件夹下的函数名字命名相同,那么这种情况下改如何调用呢?
# 方法一:
from utils.foo import say_hello as s1
from utils.bar import say_hello as s2
s1()
s2()
# 方法二:
import utils.foo
import utils.bar
utils.foo.say_hello()
utils.bar.say_hello()
方法三:
from utils import foo
from utils import bar
foo.say_hello()
bar.say_hello()
当我们创建一个"包"(package)时会自动创建一个叫__init__.py的文件
init.py — 包的初始化文件(导入一个包的时候会自动执行)
任务:
写一个函数,传入一个文件名,返回这个文件的后缀名
hello.py —> py / .py
hello.py.txt —> txt / .txt
.abc —>没有后缀名(返回空字符串)
abc. —>没有后缀名返回空字符串)
# 定义函数时,写在*前面的参数称为位置参数,调用函数传递参数时,只需要对号入座
# 写在*后面的参数称为命名关键字参数,调用函数传递参数时,必须要写成"参数名=参数值"的形式
def get_suffix(filename, *, has_dot=False):
position = filename.rfind('.')
if position <= 0:
return ''
if not has_dot:
position += 1
return filename[position:]
import utils
print(utils.get_suffix('hello world.py', has_dot=True))
print(utils.get_suffix(filename='hello.py.txt', has_dot=True))
print(utils.get_suffix('.abc', has_dot=True))
print(utils.get_suffix('abc.', has_dot=True))
print(utils.get_suffix('hello', has_dot=True))
print(utils.get_suffix('hello.', has_dot=True))
print(utils.get_suffix('.hello', has_dot=True))
练习1:
编写一个函数判断一个正整数是不是“快乐数”。
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程,如果数字变成了1,这个数就是快乐数,如果无限循环始终变不到1,这个数就不是快乐数。
28 --> 4 + 64 = 68 --> 36 + 64 = 100 —> 1
def is_happy(num):
occured_nums = set()
while num not in occured_nums:
occured_nums.add(num)
total = 0
while num > 0:
total += (num % 10) ** 2
num //= 10
if total == 1:
return True
num = total
return False
if __name__ == '__main__':
m = int(input('m = '))
print(is_happy(m))
练习2:整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
输入:x = 123
输出:321
输入:x = -123
输出:-321
输入:x = 120
输出:21
输入:x = 0
输出:0
def reverse(x):
y = abs(x)
b = 0
if x > 0:
value = 2 ** 31 - 1
else:
value = 2 ** 31
while y != 0:
b = b * 10 + y % 10
if b > value:
return 0
y //= 10
if x > 0:
return b
return -b
m = int(input('m = '))
print(reverse(m))