第三周总结
一丶函数
1.函数的基本结构,用函数替代反复使用的语句。
def roll():
roll=random.randrange(1,7)
return roll
2.如何调用全局变量或者嵌套作用域的变量以及优先度
Local(局部作用域) ---> Embeded(嵌套作用域) ---> Global(全局作用域)
---> Built-in(内置作用域) ---> NameError: name ... not defined
global ---> 声明使用全局变量或者定义一个局部变量将其放到全局作用域
nonlocal ---> 声明使用嵌套作用域的变量(不使用局部变量)
3.使用函数(实例,双色球,大乐透选码)
思路:构建一个选球的函数,变量为球最大值,和球数
再根据彩票类型,进行编写单独的函数
homework02 - 双色球随机选号(实现机选N注) 红色球01-33,选择不重复的6个球,按从小到大排列 蓝色球01-16,选择一个球,跟在红色球的后面 Date: 2021/8/2 """ import random def generate(ball_max, ball_num): """选择一组随机的球 :param ball_max: 球的最大值 :param ball_num: 球的数量 :return: 保存一组球的列表 """ balls = [i for i in range(1, ball_max + 1)] selected_balls = random.sample(balls, ball_num) selected_balls.sort() return selected_balls def make_big_lottery(): """生成大乐透的号码""" return generate(35, 5) + generate(12, 2) def make_two_colors(): """生成双色球的号码""" return generate(33, 6) + generate(16, 1) def display(balls): """ 显示一组彩票号码 :param balls: 装彩票号码对应的球的列表 """ for ball in balls: print(f'{ball:0>2d}', end=' ') print() n = int(input('机选几注: ')) print('双色球: ') for _ in range(n): display(make_two_colors()) print('大乐透: ') for _ in range(n): display(make_big_lottery())
4.函数的调用,调用的函数进行别名,处理包和模块导入。
- 函数包
import random
a = [i for i in range(100)]
list_1 = list(random.choices(a, k=10))
print(list_1)
def ptp(list_1):
list_x = max(list_1)
list_y = min(list_1)
cha = list_x - list_y
return cha
def average(list_1):
return sum(list_1) / len(list_1)
def variance(list_1):
x_bar = average(list_1)
total = 0
for num in list_1:
total += (num - x_bar) ** 2
return total / (len(list_1) - 1)
def standard(list_1):
return variance(list_1) ** 0.5
- 函数包的调用
如果要使用其他文件(模块)中定义的函数
方法一:可以通过import导入模块,然后通过"模块名.函数名"的方式调用函数;
方法二:直接从模块中导入函数 ---> "from 模块 import 函数" ---> 直接通过函数名调用函数
import导入函数、模块时,可以使用as关键字(alias)进行别名
做工程化项目开发时,如果项目中的代码文件非常多,我们可以使用"包"(package)来管理"模块"(module),
再通过模块来管理函数,包其实就是一个文件夹,而模块就是一个Python文件,通过这种方式就可以很好的解决
大型项目团队开发中经常遇到的命名冲突的问题。
Python中的from、import、as关键字就是专门用来处理包和模块导入的操作的。
Date: 2021/8/3
"""
from random import randrange
from homework04 import average as avg, ptp, variance, standard as std
class_a_scores = [randrange(50, 101) for _ in range(50)]
class_b_scores = [randrange(50, 101) for _ in range(50)]
print('A班考试成绩描述性统计信息')
print(f'平均分: {avg(class_a_scores)}')
print(f'中位数: {ptp(class_a_scores)}')
print(f'方差: {variance(class_a_scores)}')
print(f'标准差: {std(class_a_scores)}')
print('B班考试成绩描述性统计信息')
print(f'平均分: {avg(class_b_scores)}')
print(f'中位数: {ptp(class_b_scores)}')
print(f'方差: {variance(class_b_scores)}')
print(f'标准差: {std(class_b_scores)}')
5.设计一个函数,检查字符串(算术表达式)中的括号是否完全匹配。
------重点:栈和队列的概念,如何出栈和队列,入栈和队列,
"""
example02 - 设计一个函数,检查字符串(算术表达式)中的括号是否完全匹配。
例如:(2 + 3) * 5 * [80 - 20] ---> True
例如:([{2 + 3} - (1)] * 10 ---> False
例如:[{2 + 3} - (1)] * 10) ---> False
例如:[{2 + 3} - (1] * 10) ---> False
算法:循环遍历字符串的每个字符,如果遇到左括号,将左括号添加到栈中;
如果遇到右括号,就从栈中取出一个左括号,如果取不出左括号,直接返回False;
如果能够取出左括号,检查二者是否匹配;如果不匹配,直接返回False;
如果匹配,继续检查。循环遍历结束以后,检查栈是否为空,如果不为空,返回False。
列表(list)---> 可以模拟出 stack 和 queue 的效果
栈(stack)---> FILO ---> 有一个列表,如果我们将添加和删除元素都限制在列表的末尾
~ 添加元素:append() ---> 入栈(push)
~ 删除元素:pop() ---> 出栈(pop)
队列(queue)---> FIFO ---> 有一个列表,如果我们限制它只能在尾部添加元素,只能在头部删除元素
~ 添加元素:append() ---> 入队(enqueue)
~ 删除元素:pop(0) ---> 出队(dequeue)
Date: 2021/8/3
"""
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)'))
6.写一个函数,传入一个文件名(字符串),返回这个文件的后缀名
------重点:(位置参数,*,关键字参数)关键字参数,在输入参数时需要带上关键字(know04)22
# 定义函数时,写在*前面的参数称为位置参数,调用函数传递参数时,只需要对号入座
# 写在*后面的参数称为命名关键字参数,调用函数传递参数时,必须要写成"参数名=参数值"的形式
def get_suffix(filename, *, has_dot=False) -> str:
"""获取文件的后缀名
:param filename: 文件名
:param has_dot: 后缀名是否包含.
:return: 后缀名
"""
position = filename.rfind('.')
if position <= 0:
return ''
if not has_dot:
position = position + 1
return filename[position:]
def main():
print(get_suffix(filename='hello.py'))
# 调用函数传递参数时,可以给参数带上名字,这种参数称为关键字参数
print(get_suffix('hello.py', has_dot=True))
print(get_suffix('hello.py.txt'))
print(get_suffix('hello.py.txt', has_dot=True))
print(get_suffix('hello'))
print(get_suffix('hello.'))
print(get_suffix('.hello'))
if __name__ == '__main__':
main()
补充
*args —> 可变参数 —> 可以接收零个或任意多个位置参数 —> 将所有的位置参数打包成一个元组
**kwargs —> 可以接收零个或任意多个关键字参数 —> 将所有的关键字参数打包成一个字典
# *args ---> 可变参数 ---> 可以接收零个或任意多个位置参数 ---> 将所有的位置参数打包成一个元组
# **kwargs ---> 可以接收零个或任意多个关键字参数 ---> 将所有的关键字参数打包成一个字典
def add(*args, **kwargs):
# print(args, type(args))
# print(kwargs, type(kwargs))
total = 0
for arg in args:
if type(arg) in (int, float):
total += arg
for value in kwargs.values():
if type(value) in (int, float):
total += value
return total
def sub(init_value, *args, **kwargs):
total = init_value
for arg in args:
if type(arg) in (int, float):
total -= arg
for value in kwargs.values():
if type(value) in (int, float):
total -= value
return total
def mul(*args, **kwargs):
total = 1
for arg in args:
if type(arg) in (int, float):
total *= arg
for value in kwargs.values():
if type(value) in (int, float):
total *= value
return total
print(add(11, 22, 33, 44))
print(mul(11, 22, 33, 44))
fn = mul
print(fn(1, 2, 3, 4, 5))
7.递归 栈的深度设置
import sys
sys.setrecursionlimit(10)
# 递归栈的深度设置
8.Lambda函数 —> 没有名字而且一句话就能写完的函数,唯一的表达式就是函数的返回值
op=lambda x, y: x * y
9.函数例题,冒泡排序******值得反复推敲
"""
example03 - 编写实现对列表元素进行冒泡排序的函数
设计函数的时候,一定要注意函数的无副作用性(调用函数不影响调用者)
Date: 2021/8/4
"""
def bubble_sort(items, ascending=True, gt=lambda x, y: x > y):
"""冒泡排序
:param items: 待排序的列表
:param ascending: 是否使用升序
:param gt: 比较两个元素大小的函数
:return: 排序后的列表
"""
items = items[:]
for i in range(1, len(items)):
swapped = False
for j in range(0, len(items) - i):
if gt(items[j], items[j + 1]):
items[j], items[j + 1] = items[j + 1], items[j]
swapped = True
if not swapped:
break
if not ascending:
items = items[::-1]
return items
if __name__ == '__main__':
# nums = [35, 96, 12, 78, 56, 64, 39, 80]
# print(bubble_sort(nums, ascending=False))
# print(nums)
words = ['apple', 'watermelon', 'hello', 'zoo', 'internationalization']
print(bubble_sort(words, gt=lambda x, y: len(x) > len(y), ascending=False))
10.顺序查找,和二分查找
~ 列表元素无序 ---> 顺序查找
~ 列表元素有序(升序) ---> 二分查找(折半查找)
Date: 2021/8/4
"""
def seq_search(items: list, key) -> int:
"""顺序查找(渐近时间复杂度O(n))
:param items: 待查找的列表
:param key: 要找的元素
:return: 找到了返回元素的索引,找不到返回-1
"""
for index, item in enumerate(items):
if item == key:
return index
return -1
def bin_search(items: list, key, *, cmp=lambda x, y: x - y) -> int:
"""二分查找(渐近时间复杂度O(log2 n))
:param items: 待查找的列表(元素有序)
:param key: 要找的元素
:param cmp: 比较两个元素的函数(返回0表示两个元素相等,返回大于0的值,表示x>y)
:return: 找到了返回元素的索引,找不到返回-1
"""
start, end = 0, len(items) - 1
while start <= end:
mid = (start + end) // 2
if cmp(key, items[mid]) > 0:
start = mid + 1
elif cmp(key, items[mid]) < 0:
end = mid - 1
else:
return mid
return -1
def compare(s1, s2):
if s1 == s2:
return 0
for ch1, ch2 in zip(s1, s2):
if ch1 != ch2:
return ord(ch1) - ord(ch2)
11.汉诺塔******值得反复推敲
def hannoi(num, src, dst, temp=None): #递归算法
if num < 1:
return
global times #声明用来记录移动次数的变量为全局变量
#递归调用函数自身,先把除最后一个盘子之外的所有盘子移动到临时柱子上
hannoi(num-1, src, temp, dst)
# 移动最后一个盘子
print('The {0} Times move:{1}==>{2}'.format(times, src, dst))
towers[dst].append(towers[src].pop())
for tower in 'ABC': #输出 3 根柱子上的盘子
print(tower, ':', towers[tower])
times += 1
#把除最后一个盘子之外的其他盘子从临时柱子上移动到目标柱子上
hannoi(num-1, temp, dst, src)
times = 1 #用来记录移动次数的变量
n = int(input('输入盘子的数量')) #盘子数量
towers = {'A':list(range(n, 0, -1)), #初始状态,所有盘子都在 A 柱上
'B':[],
'C':[]
}
#A 表示最初放置盘子的柱子,C 是目标柱子,B 是临时柱子
hannoi(n, 'A', 'C', 'B')
二、面对对象
1.三步骤
"""
编程范式(程序设计的方法论):
1.定义类
——数据抽象:找到和对象相关的静态特征(属性)---》找名词
——行为抽象,找到和对象相关的动态特征(方法)---》找动词
2造对象
3.发消息
"""
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# 第一步1.数据抽象
def eat(self):
print(f'{self.name}正在吃饭')
def study(self,course_name):
print(f'{self.name}正在学习{course_name}')
def play(self,game_name):
print(f"{self.name}正在玩{game_name}")
def watch_av(self):
if self.age<18:
print(f'{self.name}未满18,只能看熊出没')
else:
print(f'{self.name}可以看岛国电影')
# 第一步2.行为抽象(方法)
if __name__ == '__main__':
stu1=Student('王大锤',15)
stu2=Student('游端炜',22)
# 第二步:创建对象-->构造器语法-->类名
stu1.study('python程序设计')
stu1.eat()
stu1.watch_av()
stu2.play('斗地主')
stu2.watch_av()
# 第三步:给对象发消息
stu1.age=55
stu1.watch_av()
# 可以修改对象数据
2.静态方法和类(test3)34
"""
example05 - 定义描述三角形的类,提供计算周长和面积的方法
我们在类里面写的函数,通常称之为方法,它们基本上都是发给对象的消息。
但是有的时候,我们的消息并不想发给对象,而是希望发给这个类(类本身也是一个对象),
这个时候,我们可以使用静态方法或类方法。
静态方法 - 发给类的消息 ---> @staticmethod ---> 装饰器
类方法 - 发给类的消息 ---> @classmethod ---> 装饰器 ---> 第一个参数(cls)是接收消息的类
Date: 2021/8/5
"""
class Triangle:
"""三角形"""
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
# @classmethod
# def is_valid(cls, a, b, c):
# return a + b > c and b + c > a and a + c > b
@staticmethod
def is_valid(a, b, c):
return a + b > c and b + c > a and a + c > b
def perimeter(self):
return self.a + self.b + self.c
def area(self):
half = self.perimeter() / 2
return (half * (half - self.a) * (half - self.b) * (half - self.c)) ** 0.5
3.闹钟倒计时******值得反复推敲
import os
import time
class CountDown:
def __init__(self, *, second=3, minute=0, hour=0):
self.second = second
self.minute = minute
self.hour = hour
def show(self):
return f'{self.hour:0>2d}:{self.minute:0>2d}:{self.second:0>2d}'
def run(self):
if self.hour > 0 or self.minute > 0 or self.second > 0:
self.second -= 1
if self.hour == 0 and self.minute == 0 and self.second == 0:
return 1
elif self.second == 0:
self.second = 60
self.minute -= 1
if self.minute == 0:
self.minute = 60
self.hour -= 1
if __name__ == '__main__':
clock = CountDown()
while True:
os.system('cls')
print(clock.show())
time.sleep(1)
if clock.run()==1:
print('时间到')
while True:
print('嘀嘀嘀!')
time.sleep(0.5)
4.继承(text01)35
"""
example01 -
如果要限制一个类的对象只能拥有某些属性,可以在类中使用__slots__魔法属性
class Student:
__slots__ = ('name', 'gender')
继承:对已有的类进行扩展创建出新的类,这个过程就叫继承。
提供继承信息的类叫做父类(超类、基类),得到继承信息的类称为子类(派生类)。
继承是实现代码复用的一种手段,但是千万不要滥用继承。
继承是一种is-a关系。
a student is a person.
a teacher is a person.
a programmer is a person.
子类直接从父类继承公共的属性和行为,再添加自己特有的属性和行为,
所以子类一定是比父类更强大的,任何时候都可以用子类对象去替代父类对象。
Python中的继承允许多重继承,一个类可以有一个或多个父类。
如果不是必须使用多重继承的场景下,请尽量使用单一继承。
Date: 2021/8/6
"""
class Person:
"""人"""
def __init__(self, name, gender):
self.name = name
self.gender = gender
def eat(self):
"""吃饭"""
print(f'{self.name}正在吃饭.')
def play(self, game_name):
"""玩"""
print(f'{self.name}正在玩{game_name}.')
def introduce(self):
"""自我介绍"""
sex = "男" if self.gender else "女"
print(f'我叫{self.name}, 是一个{sex}人.')
class Student(Person):
"""学生"""
def __init__(self, name, gender, grade):
super().__init__(name,gender)
self.grade = grade
def study(self, course_name):
"""学习"""
print(f'{self.name}正在学习{course_name}.')
class Teacher(Person):
"""老师"""
def __init__(self, name, gender, title):
super().__init__(name, gender)
self.title = title
def teach(self, course_name):
"""教课"""
print(f'{self.name}{self.title}正在讲授{course_name}.')
class Programmer(Person):
"""程序员"""
def write_code(self, programming_language):
"""写代码"""
print(f'{self.name}正在用{programming_language}写代码.')
stu = Student('王大锤', True, '五年级')
stu.study('语文')
stu.play('王者荣耀')
stu.eat()
stu.introduce()
teacher = Teacher('骆昊', True, '叫兽')
teacher.eat()
teacher.play('斗地主')
teacher.teach('Python程序设计')
teacher.introduce()
programmer = Programmer('白元芳', True)
programmer.eat()
programmer.play('吃鸡')
programmer.write_code('Python')
5扑克游戏(枚举)******值得反复推敲(TOcard,TOpoker,TOplayer):
TOCARD:
""" example06 - 扑克游戏,四个玩家参与,先洗牌,再把牌发到四个玩家的手上。 ~ 牌(Card) - 属性:花色(suite)、点数(face) - 行为:显示 ~ 扑克(Poker) - 属性:保存牌的列表 - 行为:洗牌(shuffle)、发牌(deal) ~ 玩家 - 属性:名字(昵称)、保存玩家手牌的列表 - 行为:摸牌(get)、整理(arrange) 魔术方法(魔法方法)---> 有特殊用途和意义的方法 ~ __init__ ---> 初始化方法,在调用构造器语法创建对象的时候会被自动调用 ~ __str__ ---> 获得对象的字符串表示,在调用print函数输出对象时会被自动调用 ~ __repr__ ---> 获得对象的字符串表示,把对象放到容器中调用print输出时会自动调用 ---> representation ~ __lt__ ---> 在使用 < 运算符比较两个对象大小时会自动调用 如果一个变量的取值只有有限个选项,可以型的语法,但是可以通过继承Enum类来实现枚举类型。 结论1:枚举考虑使用枚举类型。 Python中没有定义枚举类类型是定义符号常量的最佳选择!!! 结论2:符号常量(有意义的名字)总是优于字面常量!!! Date: 2021/8/5 """ from enum import Enum # 枚举类型 class Suite(Enum): SPADE, HEART, CLUB, DIAMOND = range(4) class Card: """牌""" def __init__(self, suite, face): self.suite = suite self.face = face def __str__(self): return self.show() def __repr__(self): return self.show() def __lt__(self, other): if self.suite == other.suite: return self.face < other.face return self.suite.value < other.suite.value def show(self): """显示""" suites = ['♠️', '❤️', '♣️', '♦️'] faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'] return f'{suites[self.suite.value]}{faces[self.face]}' def main(): """程序入口""" card1 = Card(Suite.HEART, 1) card2 = Card(Suite.SPADE, 13) print(card1, card2) print(card1 is card2) card3 = Card(Suite.DIAMOND, 9) card4 = Card(Suite.CLUB, 11) print(card3.show(), card4.show()) card1 = card2 print(card1, card2, card3) # 身份运算符 print(card1 is card2) print(card1 is card3) cards = [card1, card2, card3, card4] print(cards) if __name__ == '__main__': main()
TOpoker
"""
example08 - 玩家
Date: 2021/8/6
"""
from TOplayer import Poker
class Player:
"""玩家"""
def __init__(self, nickname):
self.nickname = nickname
self.cards = []
def get_one_card(self, card):
"""摸一张牌"""
self.cards.append(card)
def arrange(self):
"""整理手上的牌"""
self.cards.sort()
def show(self):
"""显示玩家手上的牌"""
print(self.nickname, end=': ')
for card in self.cards:
print(card, end=' ')
print()
def main():
nicknames = ('东邪', '西毒', '南帝', '北丐')
players = [Player(nickname) for nickname in nicknames]
poker = Poker()
poker.shuffle()
# 将牌发到四个玩家的手上
for _ in range(13):
for player in players:
card = poker.deal()
player.get_one_card(card)
# 显示四个玩家手上的牌
for player in players:
player.arrange()
player.show()
if __name__ == '__main__':
main()
- TOplayer:
"""
example07 - 扑克
Date: 2021/8/6
"""
import random
from TOcard import Card
from TOcard import Suite
class Poker:
"""扑克"""
def __init__(self):
self.cards = [Card(suite, face)
for suite in Suite
for face in range(1, 14)]
self.counter = 0
def shuffle(self):
"""洗牌"""
self.counter = 0
random.shuffle(self.cards)
def deal(self) -> Card:
"""发牌"""
card = self.cards[self.counter]
self.counter += 1
return card
def has_more(self) -> bool:
"""是否还有牌"""
return self.counter < len(self.cards)
def main():
poker = Poker()
poker.shuffle()
while poker.has_more():
print(poker.deal(), end=' ')
if __name__ == '__main__':
main()
版权声明:本文为sishuiniulian原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。