1. 函数补充

1.1 参数的内存地址

函数执行传参时,传递的是内存地址

# 查看某个值的在内存中的地址
data = [11, 22, 33]
addr = id(data)
print(addr)  # 1476589905352

v1 = [11, 22, 33]
v2 = [11, 22, 33]
print(id(v1))  # 2469738598920
print(id(v2))  # 2469738599432

v1 = [11, 22, 33]
v2 = v1
print(id(v1))  # 2192460370440
print(id(v2))  # 2192460370440

对于可变类型在函数中修改元素的内容,所有的地方都会修改。可变类型:列表、字典、集合

# 可变类型 & 修改内部修改
def func(data):
    data.append(999)


v1 = [11, 22, 33]
func(v1)
print(v1)  # [11,22,33,999]
# 特殊情况:可变类型 & 重新赋值
def func(data):
    data = ["a", "b"]


v1 = [11, 22, 33]
func(v1)
print(v1)  # [11,22,33]
# 特殊情况:不可变类型,无法修改内部元素,只能重新赋值。
def func(data):
    data = "a"


v1 = "b"
func(v1)
print(v1)  # b

1.2 函数的返回值是内存地址

def func():
    data = [11, 22, 33]  # 如果是字符串或者数字会有内存驻留机制,内存地址不变
    print(id(data))
    return data


v1 = func()  # 3156157354504
print(v1, id(v1))  # [11, 22, 33] 3156157354504

v2 = func()  # 3156157909832
print(v2, id(v2))  # [11, 22, 33] 3156157909832

# 两次的内存地址是不一样的(变量释放,重新创建)

上述代码执行过程:

  1. 执行第一次函数 v1 = func()
  2. data = [11,22,33] 创建一块内存区域,内部存储 [11,22,33],data变量指向这块存储地址 3156157354504
  3. return data 返回data指向的内存地址
  4. v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址 (两个变量指向此内存,引用计数器为2)
  5. 由函数执行完毕之后,函数内部的变量都会被释放 (删除data变量,引用计数器-1)
    • v1最终执行函数内部创建的那块存储地址 3156157354504
  6. 第二次执行函数 v2 = func()
  7. data = [11,22,33] 创建一块内存区域,内部存储 [11,22,33],data变量指向这块存储地址 3156157909832
  8. return data 返回data指向的内存地址
  9. v2接收返回值,所以 v2 和 data 都指向 [11,22,33] 的内存地址 (两个变量指向此内存,引用计数器为2)
  10. 由函数执行完毕之后,函数内部的变量都会被释放 (删除data变量,引用计数器-1)
  • v2最终执行函数内部创建的那块存储地址 3156157909832

1.3 参数的默认值

def func(a1,a2=18):
    print(a1,a2)

Python在创建函数(未执行)时,如果发现函数的参数中有默认值,则在函数内部会创建一块区域并维护这个默认值。

  • 执行函数未传值时,则让a2指向函数维护的那个值的地址
    • func("root") # root 18
  • 执行函数传值时,则让a2指向新传入的值的地址
    • func("admin",20) # admin 20
# 在函数内存中会维护一块区域存储 [1,2,666,666,666] 100010001
def func(a1, a2=[1, 2]):
    a2.append(666)
    print(a1, a2)


func(100)  # 100  [1,2,666]
# a1=100
# a2 -> 100010001

func(200)  # 200 [1,2,666,666]
# a1=200
# a2 -> 100010001

func(99, [77, 88])  # 99 [77,88,666]
# a1=99
# a2 -> 1111111101

func(300)  # 300 [1,2,666,666,666] 
# a1=300
# a2 -> 100010001
# 在内部会维护一块区域存储 [1,2,10,20,40 ] ,内存地址 1010101010
def func(a1, a2=[1, 2]):
    a2.append(a1)
    return a2


v1 = func(10)
print(v1)  # [1, 2, 10]
# a1=10
# a2 -> 1010101010
# v1 -> 1010101010

v2 = func(20)
print(v2)  # [1, 2, 10, 20 ]
# a1=20
# a2 -> 1010101010
# v2 -> 1010101010

v3 = func(30, [11, 22])
print(v3)  # [11, 22,30]
# a1=30
# a2 -> 11111111111        [11, 22,30]
# v3 -> 11111111111

v4 = func(40)
print(v4)  # [1,2,10,20,40 ]
# a1=40
# a2 -> 1010101010
# v4 -> 1010101010
# 内存中创建空间存储 [1, 2, 10, 20, 40] 地址: 1010101010
def func(a1, a2=[1, 2]):
    a2.append(a1)
    return a2


# a1=10
# a2 -> 1010101010
# v1 -> 1010101010
v1 = func(10)

# a1=20
# a2 -> 1010101010
# v2 -> 1010101010
v2 = func(20)

# a1=30
# a2 -> 11111111111   [11,22,30]
# v3 -> 11111111111
v3 = func(30, [11, 22])

# a1=40
# a2 -> 1010101010
# v4 -> 1010101010
v4 = func(40)

print(v1)  # [1, 2, 10, 20, 40]
print(v2)  # [1, 2, 10, 20, 40]
print(v3)  # [11,22,30]
print(v4)  # [1, 2, 10, 20, 40]

1.4 动态参数

动态参数,定义函数时在形参位置用 *** 可以接任意个参数

def func(*args, **kwargs):
    print(args, kwargs)


func("a", "b", n1='aaaaaa', n2='bbbbbb')  # ('a', 'b') {'n1': 'aaaaaa', 'n2': 'bbbbbb'}

在执行函数时,也可以用 ***

  • 形参固定,实参用 ***
def func(a1, a2):
    print(a1, a2)


func(11, 22)
func(a1=11, a2=22)
func(*(11, 22))

func(**{"a1": 11, "a2": 22})
# 需要字典键必须为字符串类型,否则报错:TypeError: keywords must be strings,因为**本质为形参和实参对的传递,而参数变量名不可以数字开头
  • 形参和实参都用 ***
def func(*args, **kwargs):
    print(args, kwargs)


func(11, 22)  # (11, 22) {}
func(11, 22, name='小明', age=18)  # (11, 22) {'name': '小明', 'age': 18}
func([11, 22], {'k1': 1, 'k2': 2})  # ([11, 22], {'k1': 1, 'k2': 2}) {}
func(*[11, 22], **{'k1': 1, 'k2': 2})  # (11, 22) {'k1': 1, 'k2': 2}
# 按照这个方式将数据传递给args和kwagrs时,数据会重新拷贝一份 (可理解为内部循环每个原始并设置到args和kwargs中)
# 原来格式化方式:
v1 = "姓名:{} 年龄:{}".format('小明', 18)
v2 = "姓名:{} 年龄:{}".format(*['小明'], 18)

# 在使用format字符串格式化时可以这样:
v3 = "姓名:{name},年龄:{age}".format(name='小明', age=18)
v4 = "姓名:{name},年龄:{age}".format(**{'name': '小明', 'age': 18})

练习题

  1. 看代码写结果
def func(*args, **kwargs):
    print(args, kwargs)


params = {'k1': 'v1', 'k2': 'v2'}
func(params)
func(**params)
  1. 读取文件中的 URL 和 标题,根据URL下载视频到本地(以标题作为文件名)
import requests


def download(title, url):
    """下载并保存视频"""
    res = requests.get(
        url=url,
        headers={
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS"
        }
    )
    with open('{}.mp4'.format(title), mode='wb') as f:
        f.write(res.content)


url_list = [
    ["测试1", "https://aweme.snssdk.com/aweme/v1/play/?video_id=v0d00fg10000c820qnrc77u1ofqasjdg&ratio=720p&line=0"],
    ["测试2", "h ttps://aweme.snssdk.com/aweme/v1/play/?video_id=v0d00fg10000c4tlq83c77u8tcoaf3cg&ratio=720p&line=0"],
    ["测试3", "https://aweme.snssdk.com/aweme/v1/play/?video_id=v0300fg10000c8s5sbrc77ubpv4as270&ratio=720p&line=0"]
]

for item in url_list:
    title, url = item
    download(title, url)

2. 函数和函数名

2.1 函数做元素

函数相当于是一个变量,在列表等元素中可以把函数当做元素

def func():
    return 123


data_list = ["小明", "func", func, func()]

print(data_list[0])
print(data_list[1])
print(data_list[2])
print(data_list[3])

res = data_list[2]()
print(res)

注意:函数同时也可被哈希,所以函数名同时也可以当做 集合的元素字典的键

  • 情景1:开发一个类似于微信的功能
def send_message():
    """发送消息"""
    pass


def send_image():
    """发送图片"""
    pass


def send_emoji():
    """发送表情"""
    pass


def send_file():
    """发送文件"""
    pass


def xxx():
    """收藏"""
    pass


function_dict = {
    "1": send_message,
    "2": send_image,
    "3": send_emoji,
    "4": send_file,
    "5": xxx
}

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片;3.发送表情;4.发送文件")
choice = input("输入选择的序号:")  # "1"

func = function_dict.get(choice)
if not func:
    print("输入错误")
else:
    # 执行函数
    func()
  • 情景2:某个特定情况,要实现发送短信、微信、邮件
def send_msg():
    """发送短信"""
    pass

def send_email():
    """发送图片"""
    pass

def send_wechat():
    """发送微信"""
    pass
    
    
func_list = [ send_msg, send_email, send_wechat ]
for item in func_list:
    item()

上述两种情景,在参数相同时才可用,如果参数不一致,会出错。
所以,在项目设计时就要让程序满足这一点,如果无法满足,也可以通过其他手段实现,例如:

  • 情景1:
def send_message(phone, content):
    """发送消息"""
    pass


def send_image(img_path, content):
    """发送图片"""
    pass


def send_emoji(emoji):
    """发送表情"""
    pass


def send_file(path):
    """发送文件"""
    pass


function_dict = {
    "1": [send_message, ['15131255089', '你好呀']],
    "2": [send_image, ['xxx/xxx/xx.png', '消息内容']],
    "3": [send_emoji, ["😁"]],
    "4": [send_file, ['xx.zip']]
}

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片;3.发送表情;4.发送文件")
choice = input("输入选择的序号:")  # 1

item = function_dict.get(choice)  # [ send_message,  ['15131255089', '你好呀']],
if not item:
    print("输入错误")
else:
    # 执行函数
    func = item[0]  # send_message
    param_list = item[1]  # ['15131255089', '你好呀']

    func(*param_list)  # send_message(*['15131255089', '你好呀'])
  • 情景2:
def send_msg(mobile, content):
    """发送短信"""
    pass


def send_email(to_email, subject, content):
    """发送图片"""
    pass


def send_wechat(user_id, content):
    """发送微信"""
    pass


func_list = [
    {"name": send_msg, "params": {'mobile': "15131255089", "content": "你有新短消息"}},
    {"name": send_email, "params": {'to_email': "xxx@live.com", "subject": "报警消息", "content": "硬盘容量不够用了"}},
    {"name": send_wechat, "params": {'user_id': 1, 'content': "在吗"}},
]

for item in func_list:
    func = item['name']  # send_msg
    param_dict = item['params']  # {'mobile': "15131255089", "content": "你有新短消息"}
    func(**param_dict)  # send_msg(**{'mobile': "15131255089", "content": "你有新短消息"})

2.2 函数名赋值

  • 将函数名赋值给其他变量,函数名其实就个变量,代指某函数;如果将函数名赋值给另外一个变量,则此变量也会代指该函数,例如:
def v1(a1, a2):
    print(a1, a2)


v2 = v1  # 此时,xxxxx和func都代指上面的那个函数,所以都可以被执行
v1(1, 1)
v2(2, 2)
def func(a1, a2):
    print(a1, a2)


func_list = [func, func, func]

func(11, 22)
func_list[0](11, 22)
func_list[1](33, 44)
func_list[2](55, 66)
  • 对函数名重新赋值,如果将函数名修改为其他值,函数名便不再代指函数,例如:
def func(a1, a2):
    print(a1, a2)


# 执行func函数
func(11, 22)

# func重新赋值成一个字符串
func = "小明"
print(func)  # 小明
  • 注意:由于函数名被重新定义之后,就会变量新被定义的值
    在自定义函数时,不要与python内置的函数 id,bin,hex,oct,len...同名,否则会覆盖内置函数的功能,例如:
# len内置函数用于计算值得长度
v1 = len("小明")
print(v1)  # 2


# len重新定义成另外一个函数
def len(a1, a2):
    return a1 + a2


# 以后执行len函数,只能按照重新定义的来使用
v3 = len(1, 2)
print(v3)

2.3 函数名做参数和返回值

函数名其实就一个变量,代指某个函数,所以,它和其它的数据类型一样,也可以当做函数的参数和返回值

  • 参数
def plus(num):
    return num + 100


def handler(func):
    res = func(10)  # 110 # handler(func) -> handler(plus) -> plus(10)
    msg = "执行func,并获取到的结果为:{}".format(res)
    print(msg)  # 执行func,并获取到的结果为:110


# 执行handler函数,将plus作为参数传递给handler的形式参数func
handler(plus)
  • 返回值
def plus(num):
    return num + 100


def handler():
    print("执行handler函数")
    return plus


result = handler()
data = result(20)  # 等于plus(20)
print(data)  # 120

3. 返回值和print

  • 在函数中使用print,只是用于在某个位置输出内容而已
  • 在函数中使用return,是为了将函数的执行结果返回给调用者,以便于后续其他操作
def add(n1, n2):
    print(n1 + n2)


v1 = add(1, 3)
print(v1)

4. 作用域

作用域,可以理解为一块空间,这块空间的数据是可以共享的。通俗点来说,作用域就类似于一个房子,房子中的东西归里面的所有人共享,其他房子的人无法获取。


4.1 函数为作用域

Python以函数为作用域,所以在函数内创建的所有数据,可以此函数中被使用,无法在其他函数中被使用。

学会分析代码,了解变量到底属于哪个作用域且是否可以被调用:

def func():
    name = "小明"
    data_list = [11, 22, 33, 44]
    print(name, data_list)
    age = 20
    print(name, age, data_list)

    for num in range(10):
        print(num)
    print(num)

    if 1 == 1:
        value = "admin"
        print(value)


def handler():
    age = 18
    print(age)


func()
handler()

4.2 全局和局部

Python中以函数为作用域,函数的作用域其实是一个局部作用域

image-20220320171646324.png

# 全局变量(变量名大写)
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    # 局部变量
    url = "http://www.xxx.com"
    ...
    
def upload():
    # 局部变量
    file_name = "rose.zip"
    ...
  • COUNTRYCITY_LIST 是在 全局作用域 中,全局作用域中创建的变量称之为 全局变量 ,可以在全局作用域中被使用,也可以在其局部作用域中被使用。
  • downloadupload 函数内部维护的就是一个局部作用域,在各自函数内部创建变量称之为 局部变量,且局部变量只能在此作用域中被使用。局部作用域中想使用某个变量时,寻找的顺序为:优先在局部作用域中寻找,如果没有则去上级作用域(全局)中寻找。
  • 全局变变量一般都是大写
  • 示例1:在局部作用域中读取全局作用域的变量
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    print(url)
    print(COUNTRY)
    print(CITY_LIST)
    
def upload():
    file_name = "rose.zip"
    print(file_name)
    print(COUNTRY)
    print(CITY_LIST)
    
print(COUNTRY,CITY_LIST)   # "中国" ["北京","上海","深圳"]
download()		 # "http://www.xxx.com"...
upload()		 # "rose.zip"...
print(file_name) # 在全局作用域执行的,全局作用域没有,报错
print(url)       # 在全局作用域执行的,全局作用域没有,报错
  • 示例2:局部作用域和全局作用域变量同名
COUNTRY = "中国"
CITY_LIST = ["北京", "上海", "深圳"]


def download():
    url = "http://www.xxx.com"
    CITY_LIST = ["河北", "河南", "山西"]
    print(url)
    print(COUNTRY)
    print(CITY_LIST)


print(COUNTRY)  # "中国"  # 在全局作用域执行的,取全局
print(CITY_LIST)  # ["北京", "上海", "深圳"]  # 在全局作用域执行的,取全局

download()
# 输出:
# "http://www.xxx.com"  # 局部有,取局部的
# COUNTRY = "中国"       # 局部没有,取全局的
# CITY_LIST = ['河北', '河南', '山西'] # 局部有,取局部的

4.3 global关键字

默认情况下,在局部作用域对全局变量只能进行:读取修改内部元素(可变类型),对全局变量 无法进行重新赋值

  • 读取
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    print(COUNTRY)
    print(CITY_LIST)
    
download()
  • 修改内部元素(可变类型)
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    print(CITY_LIST)
    
    CITY_LIST.append("广州")
    CITY_LIST[0] = "南京"
    print(CITY_LIST)
    
download()
  • 无法对全局变量重新赋值
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    # 不是对全部变量赋值,而是在局部作用域中又创建了一个局部变量 CITY_LIST 。
    CITY_LIST =  ["河北","河南","山西"]
    print(CITY_LIST)

def upload():
    file_name = "rose.zip"
    print(COUNTRY)
    print(CITY_LIST)
    
download()
upload()
  • 如果想要在局部作用域中对全局变量重新赋值,则可以基于 global关键字实现,例如:
COUNTRY = "中国"
CITY_LIST = ["北京", "上海", "深圳"]


def download():
    url = "http://www.xxx.com"

    global CITY_LIST
    CITY_LIST = ["河北", "河南", "山西"]
    print(CITY_LIST)

    global COUNTRY
    COUNTRY = "中华人民共和国"
    print(COUNTRY)


def upload():
    file_name = "rose.zip"
    print(COUNTRY)
    print(CITY_LIST)


download()
upload()
print(COUNTRY, CITY_LIST)

5. 练习题

  1. 看代码写结果
def func(k, v, info={}):
    info[k] = v
    return info


v1 = func(1, 2)
print(v1)  # {'1':2}

v2 = func(4, 5, {})
print(v2)  # {4: 5}

v3 = func(5, 6)
print(v3)  # {1: 2, 5: 6}

# 执行时机不同,结果不同
  1. 看代码写结果
def func(*args, **kwargs):
    return (args, kwargs)


# print(func(11, 22, 33))
# print(func([11, 22, 33]))
# print(func(*[11, 22, 33]))
# print(func(k1=123, k2=456))
# print(func({"k1": 123, "k2": 456}))
# print(func(**{"k1": 123, "k2": 456}))
# print(func([11, 22, 33], **{"k1": 123, "k2": 456}))
# print(func(*[11, 22, 33], **{"k1": 123, "k2": 456}))
  1. 看代码写结果
def func(*args,**kwargs):
    prev = "-".join(args)
    data_list = []
    for k,v in kwargs.items():
        item = "{}-{}".format(k,v)
        data_list.append(item)
	content = "*".join(data_list)
    
    return prev,content

v1 = func("北京","上海",city="深圳",count=99)
print(v1)	# ('北京-上海', 'city-深圳*count-99')

v2 = func(*["北京","上海"],**{"city":"深圳","count":99})
print(v2)   # ('北京-上海', 'city-深圳*count-99')
  1. 获取天气信息并按照指定格式写入到文件中
# 获取天气信息示例
import requests
import os

# 补充代码
base_dir = os.path.dirname(os.path.abspath(__file__))
db_file_path = os.path.join(base_dir, 'files', 'weather.txt')
if not os.path.exists(base_dir):
    os.makedirs(base_dir)

def write_file(**kwargs):
    row_dict = kwargs["weatherinfo"]
    data_list = []
    # data_list = [f"{k}-{v}" for k, v in kwargs["weatherinfo"].items()]
    for k, v in row_dict.items():
        group = "{}-{}".format(k, v)
        data_list.append(group)
    row_string = ",".join(data_list)

    with open(db_file_path, mode='a', encoding="utf-8") as file_object:
        file_object.write("{}\n".format(row_string))

def get_weather(code):
    url = "http://www.weather.com.cn/data/ks/{}.html".format(code)
    res = requests.get(url=url)
    res.encoding = "utf-8"
    weather_dict = res.json()
    return weather_dict

city_list = [
    {'code': "101020100", 'title': "上海"},
    {'code': "101010100", 'title': "北京"},
]

for item in city_list:
    # 101020100
    result_dict = get_weather(item["code"])
    write_file(**result_dict)
  1. 看代码写结果
def func():
    return 1, 2, 3


val = func()
print(type(val) == tuple)  # True
print(type(val) == list)  # False
  1. 看代码写结果
def func(v1):
    return v1 * 10


def bar(arg):
    return "{}".format(arg)


val = func('=')
data = bar(val)
print(data)
  1. 看代码写结果
def func():
    data = 2 * 3
    return data

data_list = [func,func,func]
for item in data_list:
    v = item()
    print(v) # 返回值 6 6 6
  1. 看代码写结果
def func(handler, **kwargs):
    # v1: handler() -> something()
    # v1: kwargs = {'k1':123,'k2':456}

    # v2: handler() -> killer()
    # v2: kwargs = {"name":"小明","age":18}

    extra = {
        "code": 123,
        "name": "小明"
    }
    kwargs.update(extra)
    # v1: {'k1':123,'k2':456,'code':123,'name':'小明'}
    # v2: {"name":"小明","age":18,'code':123} # 有重复去掉
    return handler(**kwargs)


def something(**kwargs):
    # len({'k1':123,'k2':456,'code':123,'name':'小明'})
    return len(kwargs)  # 4


def killer(**kwargs):
    # {"name":"小明","age":18,'code':123}
    key_list = []
    for key in kwargs.keys():
        key_list.append(key)
        # return key_list  # 如果return放在这则只返回name便结束
    return key_list


v1 = func(something, k1=123, k2=456)
print(v1)  # 4

v2 = func(killer, **{"name": "小明", "age": 18})
print(v2)  # ['name','age','code']
  1. 看代码写结果
def func():
    return 123


v1 = [func, func, func, func]
print(v1)
# [<function func at 0x000000D25BA4E440>, <function func at 0x000000D25BA4E440>, <function func at 0x000000D25BA4E440>, <function func at 0x000000D25BA4E440>]

v2 = [func(), func(), func(), func()]
print(v2)
# [123, 123, 123, 123]

# v1没有执行函数,只接收了内存地址,v2列表内的函数元素被执行得到了返回值
  1. 看代码写结果
NUM_LIST = []
SIZE = 18


def f1():
    NUM_LIST.append(8)
    SIZE = 19


def f2():
    print(NUM_LIST)
    print(SIZE)


f2()  # [] 18
f1()  # 无输出,但执行了一次 NUM_LIST.append(8) SIZE = 19
f2()  # [8] 18
  1. 看代码写结果
NUM_LIST = []
SIZE = 18


def f1():
    global NUM_LIST
    global SIZE
    NUM_LIST = "嘿嘿"
    SIZE = 19


def f2():
    print(NUM_LIST)
    print(SIZE)


f2()  # [] 18
f1()  # 无输出,但执行了一次 NUM_LIST = "嘿嘿" SIZE = 19
f2()  # "嘿嘿" 19
  1. 根据要求实现资源下载器。
  2. 启动后,让用户选择专区,每个专区用单独的函数实现,提供的专区如下:
    1. 下载 花瓣网图片专区
    2. 下载 抖音短视频专区
    3. 下载 NBA锦集 专区
  3. 在用户选择了某个功能之后,表示进入某下载专区,在里面循环提示用户可以下载的内容选项(已下载过的则不再提示下载)
    提醒:可基于全部变量保存已下载过得资源。
  4. 在某个专区中,如果用户输入(Q/q)表示 退出上一级,即:选择专区。
  5. 在选择专区如果输入Q/q则退出整个程序。
  6. 每个专区实现下载的案例如下:
    1. 图片
# 可供用户下载的图片如下
image_dict = {
    "1":("吉他男神","https://hbimg.huabanimg.com/51d46dc32abe7ac7f83b94c67bb88cacc46869954f478-aP4Q3V"),
    "2":("漫画美女","https://hbimg.huabanimg.com/703fdb063bdc37b11033ef794f9b3a7adfa01fd21a6d1-wTFbnO"),
    "3":("游戏地图","https://hbimg.huabanimg.com/b438d8c61ed2abf50ca94e00f257ca7a223e3b364b471-xrzoQd"),
    "4":("美女","https://hbimg.huabanimg.com/4edba1ed6a71797f52355aa1de5af961b85bf824cb71-px1nZz"),
}
  2.  短视频 
# 可供用户下载的短视频如下
video_dict = {
	"1":{"title":"东北F4模仿秀",'url':"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"},
	"2":{"title":"卡特扣篮",'url':"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"},
	"3":{"title":"罗斯mvp",'url':"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg"},
}
  3.  NBA 
# 可供用户下载的NBA视频如下
nba_dict = {
    "1":{"title":"威少奇才首秀三双","url":"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300fc20000bvi413nedtlt5abaa8tg&ratio=720p&line=0"},
    "2":{"title":"塔图姆三分准绝杀","url":"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0d00fb60000bvi0ba63vni5gqts0uag&ratio=720p&line=0"}
}

初始版本:

import requests

SELECTED_IMAGE_SET = set()  # 已下载图片ID(序号)
SELECTED_VIDEO_SET = set()
SELECTED_NBA_SET = set()


def download(file_path, url):
    res = requests.get(
        url=url,
        headers={
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS"
        }
    )
    with open(file_path, mode='wb') as f:
        f.write(res.content)


def download_image():
    total_image_dict = {
        "1": ("吉他男神", "https://hbimg.huabanimg.com/51d46dc32abe7ac7f83b94c67bb88cacc46869954f478-aP4Q3V"),
        "2": ("漫画美女", "https://hbimg.huabanimg.com/703fdb063bdc37b11033ef794f9b3a7adfa01fd21a6d1-wTFbnO"),
        "3": ("游戏地图", "https://hbimg.huabanimg.com/b438d8c61ed2abf50ca94e00f257ca7a223e3b364b471-xrzoQd"),
        "4": ("美女", "https://hbimg.huabanimg.com/4edba1ed6a71797f52355aa1de5af961b85bf824cb71-px1nZz"),
    }
    while True:
        # 构造 1.吉他男神;2.漫画美女;
        text_list = []
        for num, item in total_image_dict.items():
            if num in SELECTED_IMAGE_SET:
                continue
            data = "{}.{}".format(num, item[0])
            text_list.append(data)
        if text_list:
            text = ";".join(text_list)
        else:
            text = "无可下载选项"
        # 输出:1.吉他男神;2.漫画美女;3.游戏地图;4.美女
        print(text)

        # 返回上一步
        index = input("请输入要选择的序号(Q/q退出):")
        if index.upper() == "Q":
            return

        # 选择序号 3
        if index in SELECTED_IMAGE_SET:
            print("已下载,无法再继续下载,请重新选择!")
            continue

        group = total_image_dict.get(index)
        if not group:
            print("序号不存在,请重新选择")
            continue

        # 下载图片
        file_path = "{}.png".format(group[0])
        download(file_path, group[1])

        # 已下载集合中
        SELECTED_IMAGE_SET.add(index)


def download_video():
    total_video_dict = {
        "1": {"title": "东北F4模仿秀",
              'url': "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"},
        "2": {"title": "卡特扣篮",
              'url': "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"},
        "3": {"title": "罗斯mvp",
              'url': "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg"},
    }

    while True:
        text_list = []
        for num, item in total_video_dict.items():
            if num in SELECTED_VIDEO_SET:
                continue
            data = "{}.{}".format(num, item["title"])
            text_list.append(data)
        if text_list:
            text = ";".join(text_list)
        else:
            text = "无可下载选项"
        print(text)
        index = input("请输入要选择的序号(Q/q退出):")
        if index.upper() == "Q":
            return

        if index in SELECTED_VIDEO_SET:
            print("已下载,无法再继续下载,请重新选择!")
            continue

        group = total_video_dict.get(index)
        if not group:
            print("序号不存在,请重新选择")
            continue

        file_path = "{}.mp4".format(group["title"])
        download(file_path, group["url"])

        SELECTED_VIDEO_SET.add(index)


def download_nba():
    total_nba_dict = {
        "1": {"title": "威少奇才首秀三双",
              "url": "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300fc20000bvi413nedtlt5abaa8tg&ratio=720p&line=0"},
        "2": {"title": "塔图姆三分准绝杀",
              "url": "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0d00fb60000bvi0ba63vni5gqts0uag&ratio=720p&line=0"}

    }
    while True:
        text_list = []
        for num, item in total_nba_dict.items():
            if num in SELECTED_NBA_SET:
                continue
            data = "{}.{}".format(num, item["title"])
            text_list.append(data)
        if text_list:
            text = ";".join(text_list)
        else:
            text = "无可下载选项"
        print(text)
        index = input("请输入要选择的序号(Q/q退出):")
        if index.upper() == "Q":
            return

        if index in SELECTED_NBA_SET:
            print("已下载,无法再继续下载,请重新选择!")
            continue

        group = total_nba_dict.get(index)
        if not group:
            print("序号不存在,请重新选择")
            continue

        file_path = "{}.mp4".format(group["title"])
        download(file_path, group["url"])

        SELECTED_NBA_SET.add(index)


print("欢迎使用xxx系统")
func_dict = {
    "1": download_image,
    "2": download_video,
    "3": download_nba
}
while True:
    print("1.花瓣网图片专区;2.抖音短视频专区;3.NBA锦集专区 ")
    choice = input("请选择序号:")
    if choice.upper() == "Q":
        break
    func = func_dict.get(choice)
    if not func:
        print("输入错误,请重新选择!")
        continue
    # 进入专区
    func()

v2:

import requests

DB = {
    "1": {
        "area": "花瓣网图片专区",
        "total_dict": {
            "1": ("吉他男神", "https://hbimg.huabanimg.com/51d46dc32abe7ac7f83b94c67bb88cacc46869954f478-aP4Q3V"),
            "2": ("漫画美女", "https://hbimg.huabanimg.com/703fdb063bdc37b11033ef794f9b3a7adfa01fd21a6d1-wTFbnO"),
            "3": ("游戏地图", "https://hbimg.huabanimg.com/b438d8c61ed2abf50ca94e00f257ca7a223e3b364b471-xrzoQd"),
            "4": ("美女", "https://hbimg.huabanimg.com/4edba1ed6a71797f52355aa1de5af961b85bf824cb71-px1nZz"),
        },
        "ext": "png",
        "selected": set()
    },
    "2": {
        "area": "抖音短视频专区",
        "total_dict": {
            "1": {"title": "东北F4模仿秀",
                  'url': "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"},
            "2": {"title": "卡特扣篮",
                  'url': "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"},
            "3": {"title": "罗斯mvp",
                  'url': "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg"},
        },
        "ext": "mp4",
        "selected": set()
    },
    "3": {
        "area": "NBA锦集专区",
        "total_dict": {
            "1": {"title": "威少奇才首秀三双",
                  "url": "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300fc20000bvi413nedtlt5abaa8tg&ratio=720p&line=0"},
            "2": {"title": "塔图姆三分准绝杀",
                  "url": "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0d00fb60000bvi0ba63vni5gqts0uag&ratio=720p&line=0"}
        },
        "ext": "mp4",
        "selected": set()
    },
}
def download(file_path, url):
    res = requests.get(
        url=url,
        headers={
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS"
        }
    )
    with open(file_path, mode='wb') as f:
        f.write(res.content)
def handler(area_info):
    # 进入专区提醒
    summary = "欢迎进入{}".format(area_info['area'])
    print(summary)

    # 专区中选择下载
    while True:
        text_list = []
        for num, item in area_info['total_dict'].items():
            if num in area_info['selected']:
                continue
            if type(item) == tuple:
                data = "{}.{}".format(num, item[0])
            else:
                data = "{}.{}".format(num, item["title"])
            text_list.append(data)
        if text_list:
            text = ";".join(text_list)
        else:
            text = "无可下载选项"

        print(text)
        index = input("请输入要选择的序号(Q/q退出):")
        if index.upper() == "Q":
            return

        if index in area_info['selected']:
            print("已下载,无法再继续下载,请重新选择!")
            continue

        group = area_info['total_dict'].get(index)
        if not group:
            print("序号不存在,请重新选择")
            continue

        if type(group) == tuple:
            title, url = group
        else:
            title, url = group['title'], group['url']

        file_path = "{}.{}".format(title, area_info['ext'])
        download(file_path, url)

        area_info['selected'].add(index)
print("欢迎使用xxx系统")
while True:
    print("1.花瓣网图片专区;2.抖音短视频专区;3.NBA锦集 专区 ")
    choice = input("请选择序号(Q/q退出):")
    if choice.upper() == "Q":
        break

    # 选择序号: 去db中找对应的字典信息
    area_dict = DB.get(choice)

    if not area_dict:
        print("输入错误,请重新选择!")
        continue

    # 进入专区(area_dict选择的专区信息)
    handler(area_dict)
posted on 2023-10-20 16:48  龙泉寺老方丈  阅读(18)  评论(0)    收藏  举报