编程语言经典小例题—Python版【持续

发布时间:2019-09-21 10:47:35编辑:auto阅读(1467)

    本文用于记录一些学习过程中使用python3写过的小程序,和一些经典的编程小例题。

    【例题1】
    编写一个简单的个人所得税计算器,设定起征点为3500元。

    print("个人所得税计算器\n")
    
    gongZi = int(input("请输入你的工资:"))
    qiZheng = gongZi - 3500
    suiWu = 0
    
    if gongZi <= 3500:
        print("无需缴纳个人所得税!")
    elif qiZheng <= 1500:
        suiWu = int(qiZheng * 0.03)
    elif qiZheng <= 4500:
        suiWu = int(qiZheng * 0.1) - 105
    elif qiZheng <= 9000:
        suiWu = int(qiZheng * 0.2) - 555
    elif qiZheng <= 35000:
        suiWu = int(qiZheng * 0.25) - 1005
    elif qiZheng <= 55000:
        suiWu = int(qiZheng * 0.30) - 2755
    elif qiZheng <= 80000:
        suiWu = int(qiZheng * 0.35) - 5505
    else:
        suiWu = int(qiZheng * 0.45) - 13505
    
    print("税前工资:", gongZi, "元")
    print("税后工资:", gongZi - suiWu, "元")
    print("需要缴纳个人所得税:", suiWu, "元")

    【例题2】
    使用for循环打印菱形

    #打印菱形
    for i in range(5):
        for j in range(5-i):
            print(" ", end=" ")
        for k in range(2 * i - 1):
            print("*", end=" ")
        print()
    
    for i2 in range(5):
        for j2 in range(i2):
            print(" ", end=" ")
        for k2 in range(2 * (5-i2) - 1):
            print("*", end=" ")
            k2+=1
        print()

    【例题3】
    题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    # 用于计数的变量
    count = 0
    
    # 使用三个循环生成三个不同的数字
    for i in range(1, 5):
        for j in range(1, 5):
            for k in range(1, 5):
                # 三位数字不重复才进行组合
                if i != j and i != k and j != k:
                    # i组合第一位,j第二位,k第三位
                    print((i * 100) + (j * 10) + k)
                    # 组合一次就计数一次
                    count += 1
    
    print(count)

    【例题3】
    使用python代码编写一个简单的爬虫:

    '''
        This is a spider
    '''
    
    from urllib import request
    import re
    
    class Spider():
        # 目标页面
        url = 'https://www.panda.tv/cate/kingglory'
    
        # 如果不使用非贪婪模式就会匹配多个</div>
        root_pattern = '<div class="video-info">([\s\S]*?)</div>'
        name_pattern='</i>([\s\S]*?)</span>'
        number_pattern='<span class="video-number">([\s\S]*?)</span>'
    
        # 读取网页数据
        def __fetch_content(self):
            r = request.urlopen(Spider.url)
            # 读出来的是字节
            htmls = r.read()
            htmls = str(htmls,encoding='utf-8')
    
            return htmls
    
        # 使用正则表达式匹配数据
        def __analysis(self, htmls):
            root_html = re.findall(Spider.root_pattern, htmls)
    
            anchors = []
            for html in root_html:
                name = re.findall(Spider.name_pattern,html)
                number = re.findall(Spider.number_pattern,html)
                anchor = {'name' : name, 'number' : number}
                anchors.append(anchor)
    
            return anchors
    
        # 数据精炼
        def __refine(self, anchors):
            l = lambda anchor: {
                'name':anchor['name'][0].strip(), 
                'number':anchor['number'][0]
                }
    
            return map(l, anchors)
    
        # 数据处理(排序)
        def __sort(self, anchors):
            # key指定排序元素
            anchors = sorted(anchors, key=self.__sort_seed, reverse=True)
    
            return anchors
    
        # 排序种子
        def __sort_seed(self, anchor):
            r = re.findall('\d*', anchor['number'])
            number = float(r[0])
            if '万'  in anchor['number']:
                number *= 10000
    
            return number
    
        # 打印数据
        def __show(self, anchors):
            for rank in range(0, len(anchors)):
                print('rank' + str(rank + 1) + '   :  ' + anchors[rank]['name'] + '\t\t' + anchors[rank]['number'] + '人')
    
        # 总控方法
        def go(self):
            htmls = self.__fetch_content()
            anchors = self.__analysis(htmls)
            anchors = list(self.__refine(anchors))
            anchors = self.__sort(anchors)
            self.__show(anchors)
    
    s = Spider()
    s.go()

    【例题4】
    题目:已知1颗六级石头的市场售价为750金,请问是自己合成石头划算还是直接购买划算

    '''
        计算五行石是自己合成划算还是直接购买已经合成好的划算;
        自己合成只能购买一级五行石;
        七级和八级只能通过剥离获得
        市场货币:金
        还需要消耗金、钻石、体力
    '''
    
    '''
        合成规律
        1. 购买1级五行石:消耗金和钻石
        2. 1级五行石合成3级五行石:消耗金、体力和1级五行石
        3. 3级五行石合成4级五行石:消耗金、体力和1级五行石、一定概率
        4. 4级五行石合成6级五行石:消耗金、体力和4级五行石
        目标:
        合成6级五行石
    '''
    
    '''
        购买1级石头
    '''
    l1_value = 0.75 # 1颗1级石头消耗0.75金
    l1_value_diamond = 8 # 1颗1级石头同时还需要消耗8颗钻石
    
    '''
        1级合成3级
    '''
    l1_to_l3 = 12 # 1颗1级石头变成1颗3级石头,需要消耗13颗1级石头
    l1_to_l3_gold = 0.39 # 同时还需要消耗0.39金
    l1_to_l3_vit = 10 # 同时还需要消耗10点体力
    
    '''
        3级合成4级
    '''
    l3_to_l4 = 16 # 1颗3级石头变成1颗4级石头,需要消耗16个1级石头
    l3_to_14_gold = 0.897 # 1颗3级石头变成1颗4级石头,需要消耗0.897金
    l3_to_l4_vit = 10
    l3_to_l4_rate = 0.4878 # 1颗3级石头变成1颗4级石头,成功概率只有0.4878,并非100%
                           # 如果失败,则金和16级1级石头也将被扣除,但是不消耗体力
    
    '''
        4级合成6级
    '''
    l4_to_l6 = 12 # 12颗4级石头变成6级石头,概率100%
    l4_to_l6_gold = 19.75 # 需要消耗19.75金
    l4_to_l6_vit = 10
    
    '''
        已知1颗六级石头的市场售价为750金,请问是自己合成石头划算还是直接购买划算
        其他数据:
            1颗钻石diamond 卖出0.05金
            1点体力vit 可以卖出1金
    '''

    实现代码:

    # 购买1级石头
    def buy_l1(l1_number):
        gold = l1_number * 0.75
        diamond = l1_number * 8
        return gold, diamond
    
    # 合成3级石头
    def l1_to_l3(l3_number):
        gold, diamond = buy_l1(l3_number * 12)
        gold += l3_number * 0.39
        vit = l3_number * 10
        return gold, diamond, vit
    
    # 合成4级石头
    def l3_to_l4(l4_number):
        # 需要先有相应的3级石头
        gold, diamond, vit = l1_to_l3(l4_number)
        # 按照成功的前提计算出实际消耗的1级石头
        count = l4_number * 16
        wastage = count // 0.4878
        # 购买实际消耗的1级石头
        gold_l4, diamond_l4 = buy_l1(wastage)
        gold += gold_l4
        diamond += diamond_l4
        # 计算实际消耗的体力值
        vit = (wastage//16) * l4_number
        gold += l4_number * 0.897
        return gold, diamond, vit
    
    # 合成6级石头
    def l4_to_l6(l6_number):
        # 需要先有相应的4级石头
        gold, diamond, vit = l3_to_l4(l6_number * 12)
        gold += l6_number * 19.75
        vit += l6_number * 10
        return gold, diamond, vit
    
    # 根据需要合成的数量与石头的级别,得到合成所需要消耗的金
    def synthesis(ln_name, number):
        if ln_name == 'L3':
            gold, diamond, vit = l1_to_l3(number)
        elif ln_name == 'L4':
            gold, diamond, vit = l3_to_l4(number)
        elif ln_name == 'L6':
            gold, diamond, vit = l4_to_l6(number)
        else:
            print("输入有误!")
    
        gold += vit
        gold += diamond*0.05
        return gold
    
    # 处理用户的输入
    def user_input():
        print("1.计算合成五行石所耗费的金", "\t", "2.计算购买1级五行石所耗费的金")
        input_str = input("请输入:")
        if input_str == "1":
            print("\n1.合成3级五行石", "\t", "2.合成4级五行石", "\t", "3.合成6级五行石")
            input_str = input("请输入:")
            num = int(input("请输入需要合成的数量:"))
            if input_str == "1":
                gold = synthesis('L3',num)
                print('\n需要消耗:', gold, '金')
            elif input_str == "2":
                gold = synthesis('L4',num)
                print('\n需要消耗:', gold, '金')
            elif input_str == "3":
                gold = synthesis('L6',num)
                print('\n需要消耗:', gold, '金')
            else:
                print("输入错误!")
        elif input_str == "2":
            num = int(input("请输入购买数量:"))
            gold, diamond = buy_l1(num)
            print("需要消耗", gold, '金,', diamond, '个钻石。')
        else:
            print("输入错误!")
    
    user_input()

    【例题5】
    过滤列表中的负数:

    from random import randint
    
    # randint生成-10到10之间的随机数
    data = [randint(-10,10) for _ in range(10)]
    print(data)
    
    # 需求:过滤列表中的负数
    lists = filter(lambda x:x >= 0,data)
    print(*lists)
    
    # 第二种解法
    lists2 = [x for x in data if x >= 0]
    print(lists2)
    
    # 列表推导式的性能要比filter高

    【例题6】
    筛出字典中值高于90的元素:

    from random import randint
    
    d = {x: randint(60, 100) for x in range(1, 21)}
    print(d)
    
    # 使用字典推导式实现
    di = {k: v for k,v in d.items() if v > 90}
    print(di)

    【例题7】
    过滤集合中能被3整除的子集:

    from random import randint
    
    data = [randint(-10,10) for _ in range(10)]
    s = set(data)
    print(s)
    
    # 使用集合推导式实现
    si = {x for x in s if x % 3 ==0}
    print(si)

    【例题8】
    如何为元组中的每个元素命名, 提高程序可读性:

    # 学生信息系统中数据为固定格式:(名字,年龄,性别,邮箱地址,。。。。)
    # 学生数量很大为了减小存储开销,对每个学生信息用元组表示:
    # ('Jim', 16, 'man', 'jim8721@gmail.com')
    # 问题:访问时,我们使用下标访问,大量的使用下标会降低程序的可读性,如何解决这个问题?
    
    # 解决方案1:通过枚举类型来解决,也就是定义一系列数值常量
    from enum import Enum
    
    class StudentEnum(Enum):
        NAME, AGE, SEX, EMAIL_ADDR = range(4)
    
    student = ('Jim', 16, 'man', 'jim8721@gmail.com')
    
    print(student[StudentEnum.NAME.value])
    print(student[StudentEnum.AGE.value])
    print(student[StudentEnum.SEX.value])
    print(student[StudentEnum.EMAIL_ADDR.value])
    
    # 解决方案2:使用标准库中collection.namedtuple替代内置tuple
    from collections import namedtuple
    
    # namedtuple会返回一个创建好的类,相当于是类的工厂
    Student = namedtuple('Student', ['name', 'age', 'sex', 'email_addr'])
    stu = Student('Jim', 16, 'man', 'jim8721@gmail.com')
    
    # 返回的类型是tuple的子类
    print(isinstance(stu, tuple))
    print(stu.name)
    print(stu.age)
    print(stu.sex)
    print(stu.email_addr)
    
    # 支持使用关键字传参
    stu2 = Student(name='Jim', age=16, sex='man', email_addr='jim8721@gmail.com')

    【例题9】
    从一个随机数列中,找到出现次数最高的3个元素,并统计出现的次数:

    # 需求:从一个随机数列中,找到出现次数最高的3个元素,并统计出现的次数
    from random import randint
    from collections import Counter
    
    # 生成一个随机序列
    data = [randint(0, 20) for _ in range(30)]
    print(data)
    
    # 使用序列中的元素作为键,数字0作为初始值,创建一个字典
    count = dict.fromkeys(data, 0)
    
    # 统计序列元素出现的次数
    for x in data:
        count[x] += 1
    
    # 对字典的value进行排序
    di = sorted(count.items(), key=lambda item: item[1], reverse=True)
    # 拿出前三个元素
    print(di[0:3])
    
    '''
        另一个解决方法是将序列传入Counter构造器中,得到的对象是元素频度的字典,
        也就是说可以得到一个根据字典中的value排序后的字典
    '''
    count2 = Counter(data)
    print(count2)
    
    # 通过most_common方法可以拿出字典的前n个元素,返回类型是列表
    print(count2.most_common(3))

    【例题10】
    对某英文文章的单词,进行词频统计,找到出现次数最高的10个单词,并统计出现的次数:

    # 需求:对某英文文章的单词,进行词频统计,找到出现次数最高的10个单词,并统计出现的次数
    import re
    from collections import Counter
    
    # 读取文本内容
    txt = open('E:\\test.txt').read()
    
    # 对非字母的文字进行分割
    txt_list = re.split('\W+', txt)
    
    # 统计排序
    c3 = Counter(txt_list)
    
    # 拿出前10个元素
    print(c3.most_common(10))

    【例题11】
    根据成绩高低,计算学生排名:

    # 某班英语成绩以字典形式存储为:{'Lilei':79,'Jim':88,'Lucy':92...}
    # 需求:根据成绩高低,计算学生排名
    from random import randint
    
    # 生成一个随机字典
    data_dict = {x: randint(60, 100) for x in 'xyzabc'}
    
    # 方案1:利用zip将字典转换为元组进行排序:
    data_tuple = zip(data_dict.values(), data_dict.keys())
    print(sorted(data_tuple))
    
    # 方案2:传递sorted函数的key参数:
    data_list = sorted(data_dict.items(), key=lambda item: item[1],reverse=False)
    print(data_list)

    【例题12】
    制作一个简单的猜数字小游戏,需要添加历史记录功能,能够显示用户最近5次猜过的数字,并且记录要持久存储:

    '''
        很多应用程序都有浏览用户的历史记录功能,例如:
        1.浏览器可以查看最近访问过的网页
        2.视频播放器可以查看最近播放过的视频文件
        3.shell可以查看用户输入过的命令
        ......
    
        需求:制作一个简单的猜数字小游戏,需要添加历史记录功能,
              能够显示用户最近5次猜过的数字,并且记录要持久存储
    '''
    
    from random import randint
    import pickle
    
    '''
        使用容量为n的队列来存储历史记录,可以用到
        collections中的deque,deque是一个双端循环队列
    '''
    from collections import deque
    
    N = randint(0, 100)
    
    # 运行程序时将文件数据导入
    def get_history():
        try:
            with open('E:\\history.txt', 'rb') as history_txt:
                history = pickle.load(history_txt)
                if history :
                    return history
        except FileNotFoundError as e:
            # 第一个参数为队列的初始值,第二个参数为队列的容量
            history = deque([], 5)
            return history
    
    # 猜数字
    def guess(key):
        if key == N:
            print('right')
            return True
    
        if key < N:
            print(key, 'is less-than N')
        else:
            print(key, 'is greater-than N')
    
        return False
    
    # 获得队列对象
    history = get_history()
    while True:
        line = input('please input a number: ')
        if line.isdigit():
            key = int(line)
            # append是从右边入队
            history.append(key)
            if guess(key):
                break
    
        # 当用户输入history或者h?时打印历史记录
        elif line == 'history' or  line == 'h?':
            print(list(history))
        elif line == 'exit':
            # 程序退出前,可以使用pickle将队列对象存储到本地文件中
            with open('E:\\history.txt', 'wb') as output:
                pickle.dump(history, output)
    
            break

    【例题13】
    从网络抓取各个城市气温信息,并依次显示:

    '''
        从网络抓取各个城市气温信息,并依次显示:
        北京:15~20
        天津:17~22
        长春:12~18
        ......
    
        如果一次抓取所有城市天气再显示,显示第一个城市气温时,有很高的延迟,并且
        浪费存储空间,我们期望以“用时访问”的策略,并且能把所有城市气温封装到一个
        对象里,可用for语句进行迭代,如何解决?
    '''
    
    from collections import Iterable, Iterator
    from urllib import request
    import urllib
    import json
    import gzip
    
    ''' 
        1.实现一个迭代器对象WeatherIterator,__next__方法每次返回一个城市的气温,
        迭代器对象的实现需要继承 Iterator
    '''
    class WeatherIterator(Iterator):
    
        def __init__(self, cities):
            '''
                构造器需要接收一个可迭代的对象,在这里这个cities是一个城市列表
                index用于记录迭代次数,也用于充当下标索引
            '''
            self.cities = cities
            self.index = 0
    
        def getWeather(self, city):
            '''
               抓取城市天气信息
            '''
            url_str = 'http://wthrcdn.etouch.cn/weather_mini?city=' + city
    
            # 转换URL的中文,safe参数指定哪些符号不转换
            url = urllib.parse.quote(url_str, safe='/:?=')
            resp = request.urlopen(url).read()
    
            # 由于返回的的数据是gzip的压缩格式,所以需要解压返回的数据
            resp = gzip.decompress(resp)
    
            # 将字节转换成字符串,编码设置为utf-8
            json_data = str(resp, encoding = 'utf-8')
    
            # 解析json数据
            data = json.loads(json_data)['data']['forecast'][0]
            return '%s: %s , %s ' % (city, data['low'], data['high'])
    
        def __next__(self):
            if self.index == len(self.cities):
                # 被迭代的次数等于迭代对象的长度时就需要抛异常
                raise StopIteration
    
            # 从城市列表中迭代取出城市名称,每被取出一个,就需要增加一次迭代次数
            city = self.cities[self.index]
            self.index += 1
    
            # 返回城市的天气数据
            return self.getWeather(city)
    
    '''
        2.实现一个可迭代对象WeatherIterable,__iter__方法返回一个迭代器对象
        可迭代对象的实现需要继承 Iterable
    '''
    class WeatherIterable(Iterable):
    
        def __init__(self, cities):
            self.cities = cities
    
        def __iter__(self):
            # 返回迭代器对象的实例
            return WeatherIterator(self.cities)
    
    cities = ['北京', '上海', '广州', '深圳']
    for x in WeatherIterable(cities):
        print(x)

    【例题14】

    实现一个可迭代对象的类,它能迭代出给定范围内所有素数:
    '''
        将该类的__iter__方法实现成生成器函数,每次yield返回一个素数
    '''
    class PrimeNumbers:
        def __init__(self, start, end):
            '''
                初始化数字的范围
            '''
            self.start = start
            self.end = end
    
        def isPrime(self, k):
            '''
                判断是否是素数
            '''
            if k < 2:
                return False
    
            for i in range(2, k):
                if k % i == 0:
                    return False
    
            return True
    
        def __iter__(self):
            for k in range(self.start, self.end + 1):
                # 是素数就返回
                if self.isPrime(k):
                    yield k
    
    for x in PrimeNumbers(1, 100):
        print(x, end=' ')

    【例题15】
    实现一个连续浮点数发生器,根据给定范围和步进值产生一些列连续浮点数:

    '''
        实现一个连续浮点数发生器FloatRange,根据给定范围
        和步进值产生一些列连续浮点数
    '''
    
    class FloatRange:
        def __init__(self, start , end, step = 0.1):
            self.start = start
            self.end = end
            self.step = step
    
        def __iter__(self):
            ''' 正向迭代 '''
            t = self.start
            while t <= self.end:
                yield t
                t += self.step
    
        def __reversed__(self):
            ''' 反向迭代 '''
            t = self.end
            while t >= self.start:
                yield t
                t -= self.step
    
    for x in FloatRange(1.0, 4.0, 0.5):
        print(x, end=' ')
    
    print()
    for x in reversed(FloatRange(1.0, 4.0, 0.5)):
        print(x, end=' ')

    【例题16】
    使用readlines方法对迭代对象进行切片:

    '''
        有某个文本文件,我们想读取其中某范围的内容,如100~300行
        之间的内容。python中文本文件是可迭代对象,我们是否可以
        使用类似列表切片的方式得到一个100~300行文件内容的生成器?
    '''
    
    # 使用标准库中的itertools.islice,它能返回一个迭代对象切片的生成器
    from itertools import islice
    
    f = open('E:/test.txt')
    
    # 迭代10到20行的内容
    for line in islice(f, 10, 20):
        print(line)
    
    # 迭代前10行的内容
    for line in islice(f, 10):
        print(line)
    
    # 迭代第10行到末尾行的内容
    for line in islice(f, 10, None):
        print(line)
    
    lists = range(20)
    t = iter(lists)
    
    for x in islice(t, 5, 10):
        print(x, end=' ')
    

    【例题17】

    '''
        1.某班学生期末考试成绩,语文、数学、英语分别存储在3个列表中,同时
        迭代三个列表,计算每个学生的总分数(并行)
    '''
    
    from random import randint
    
    chinese = [randint(60, 100) for _ in range(40)]
    math = [randint(60, 100) for _ in range(40)]
    english = [randint(60, 100) for _ in range(40)]
    
    # 第一种解决方案就是使用循环,通过下标拿出相应的值,进行计算,但是这种方式局限性很大
    for i in range(len(chinese)):
        chinese[i] + math[i] + english[i]
    
    # 第二种方式就是使用内置函数zip,它能将多个可迭代对象合并,每次迭代返回一个元组
    total = []
    for c, m, e in zip(chinese, math, english):
        total.append(c + m + e)
    
    print(total)

    【例题18】

    '''
        2.某年级有4个班,某次考试每班英语成绩分别存储在4个列表中,依次迭代
        每个列表,统计全学年成绩高于90分的人数(串行)
    '''
    
    # 使用标准库中的itertools.chain,它能将多个可迭代对象进行连接
    from itertools import chain
    from random import randint
    
    # 生成4个班的英语成绩
    class1 = [randint(60, 100) for _ in range(40)]
    class2 = [randint(60, 100) for _ in range(42)]
    class3 = [randint(60, 100) for _ in range(39)]
    class4 = [randint(60, 100) for _ in range(41)]
    
    # 存储高于90分的人数
    count = 0
    
    for s in chain(class1, class2, class3, class4):
        if s > 90:
            count += 1
    
    print('全学年成绩高于90分的人数为:' + str(count) + '人')

    【例题19】

    清除爱奇艺所有后台进程

    import psutil
    import os
    import time
    
    def search():
            # 进程名称列表
        process_list = ['QyFragment.exe', 'QyPlayer.exe', 'QyClient.exe', 'QyClient.exe', 'QyKernel.exe']
        for proc in psutil.process_iter():
            if proc.name() in process_list:
                print(proc.name())
                kill(proc.pid)
    
    def kill(pid):
        # 使用信号量kill进程
        os.kill(pid, 9)
        # 每秒检查一遍,直到杀干净为止
        time.sleep(1)
        search()
    
    if __name__ == '__main__':
        search()

关键字