0%

day14 模块

image-20210102105502236

课程目标:掌握Python中常用模块的使用方法。

今日概要:

  • 自定义模块(包)
  • 第三方模块
  • 内置模块【1/2】

1. 自定义模块

1.1 模块和包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import hashlib


def encrypt(data):
""" 数据加密 """
hash_object = hashlib.md5()
hash_object.update(data.encode('utf-8'))
return hash_object.hexdigest()


user = input("请输入用户名:")
pwd = input("请输入密码:")
md5_password = encrypt(pwd)

message = "用户名:{},密码:{}".format(user, md5_password)
print(message)

在开发简单的程序时,使用一个py文件就可以搞定,如果程序比较庞大,需要些10w行代码,此时为了,代码结构清晰,将功能按照某种规则拆分到不同的py文件中,使用时再去导入即可。另外,当其他项目也需要此项目的某些模块时,也可以直接把模块拿过去使用,增加重用性。

如果按照某个规则进行拆分,发现拆分到 commons.py 中函数太多,也可以通过文件夹来进行再次拆分,例如:

1
2
3
4
5
6
├── commons
│   ├── convert.py
│   ├── page.py
│   └── utils.py
└── run.py

image-20210103144059473

在Python中一般对文件和文件的称呼(很多开发者的平时开发中也有人都称为模块)

  • 一个py文件,模块(module)。
  • 含多个py文件的文件夹,包(package)。

注意:在包(文件夹)中有一个默认内容为空的__init__.py的文件,一般用于描述当前包的信息(在导入他下面的模块时,也会自动加载)。

  • py2必须有,如果没有导入包就会失败。
  • py3可有可无。

1.2 导入

当定义好一个模块或包之后,如果想要使用其中定义的功能,必须要先导入,然后再能使用。

导入,其实就是将模块或包加载的内存中,以后再去内存中去拿就行。

关于导如时的路径:

在Python内部默认设置了一些路径,导入模块或包时,都会按照指定顺序逐一去特定的路径查找。

1
2
import sys
print(sys.path)
1
2
3
4
5
6
7
8
9
10
11
[
'当前执行脚本所在的目录', /Users/wupeiqi/PycharmProjects/luffyCourse/day14/bin
/Users/wupeiqi/PycharmProjects/luffyCourse/day14
'/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_display',
'/Library/Frameworks/Python.framework/Versions/3.9/lib/python39.zip',
'/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9',
'/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/lib-dynload',
'/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages',
'/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_matplotlib_backend'

]

想要导入任意的模块和包,都必须写在如下路径下,才能被找到。

也可以自动手动在sys.path中添加指定路径,然后再导入可以,例如:

1
2
3
4
import sys
sys.path.append("路径A")

import xxxxx # 导入路径A下的一个xxxxx.py文件
  1. 你以后写模块名称时,千万不能和内置和第三方的同名(新手容易犯错误)。
  2. 项目执行文件一般都在项目根目录,如果执行文件嵌套的内存目录,就需要自己手动在sys.path中添加路径。
    image-20210103163446464
  3. pycharm中默认会将项目目录加入到sys.path中

关于导入的方式:

导入本质上是将某个文件中的内容先加载到内存中,然后再去内存中拿过来使用。而在Python开发中常用的导入的方式有2类方式,每类方式都也多种情况。

  • 第一类:import xxxx(开发中,一般多用于导入sys.path目录下的一个py文件)

    • 模块级别

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      ├── commons
      │   ├── __init__.py
      │   ├── convert.py
      │   ├── page.py
      │   ├── tencent
      │   │   ├── __init__.py
      │   │   ├── sms.py
      │   │   └── wechat.py
      │   └── utils.py
      ├── many.py
      └── run.py
      image-20210102175534535
    • 包级别

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      ├── commons
      │   ├── __init__.py
      │   ├── convert.py
      │   ├── page.py
      │   └── utils.py
      ├── third
      │   ├── __init__.py
      │   ├── ali
      │   │   └── oss.py
      │   └── tencent
      │   ├── __init__.py
      │   ├── __pycache__
      │   ├── sms.py
      │   └── wechat.py
      └── run.py
      image-20210102180002867
  • 第二类:from xxx import xxx 【常用】,一般适用于多层嵌套和导入模块中某个成员的情况。

    • 成员级别

      1
      2
      3
      4
      5
      6
      7
      ├── commons
      │   ├── __init__.py
      │   ├── convert.py
      │   ├── page.py
      │   └── utils.py
      ├── many.py
      └── run.py
      image-20210102173907386

      提示:基于from模式也可以支持 from many import *,即:导入一个模块中所有的成员(可能会重名,所以用的少)。

    • 模块级别

      1
      2
      3
      4
      5
      6
      7
      ├── commons
      │   ├── __init__.py
      │   ├── convert.py
      │   ├── page.py
      │   └── utils.py
      ├── many.py
      └── run.py
      image-20210102174119314
    • 包级别

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      ├── commons
      │   ├── __init__.py
      │   ├── convert.py
      │   ├── page.py
      │   ├── tencent
      │   │   ├── __init__.py
      │   │   ├── sms.py
      │   │   └── wechat.py
      │   └── utils.py
      ├── many.py
      └── run.py
      image-20210102182326500

1.3 相对导入

在导入模块时,对于 from xx import xx这种模式,还支持相对到导入。例如:

image-20210102182539642

切记,相对导入只能用在包中的py文件中(即:嵌套在文件中的py文件才可以使用,项目根目录下无法使用)。

image-20210102182921911

1.4 导入别名

如果项目中导入 成员/模块/包 有重名,那么后导入的会覆盖之前导入,为了避免这种情况的发生,Python支持重命名,即:

1
2
from xxx.xxx import xx as xo
import x1.x2 as pg

除此之外,有了as的存在,让 import xx.xxx.xxxx.xxx 在调用执行时,会更加简单(不常用,了解即可)。

  • 原来

    1
    2
    3
    import commons.page

    v1 = commons.page.pagination()
  • 现在

    1
    2
    3
    import commons.page as pg

    v1 = pg.pagination()

1.5 主文件

  • 执行一个py文件时

    1
    __name__ = "__main__"
  • 导入一个py文件时

    1
    __name__ = "模块名"

主文件,其实就是在程序执行的入口文件,例如:

1
2
3
4
5
6
7
8
9
10
11
├── commons
│   ├── __init__.py
│   ├── convert.py
│   ├── page.py
│   ├── tencent
│   │   ├── __init__.py
│   │   ├── sms.py
│   │   └── wechat.py
│   └── utils.py
├── many.py
└── run.py

我们通常是执行 run.py 去运行程序,其他的py文件都是一些功能代码。当我们去执行一个文件时,文件内部的 __name__变量的值为 __main__,所以,主文件经常会看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
import many
from commons import page
from commons import utils


def start():
v1 = many.show()
v2 = page.pagination()
v3 = utils.encrypt()


if __name__ == '__main__':
start()

只有是以主文件的形式运行此脚本时start函数才会执行,被导入时则不会被执行。

小结

  1. 模块和包的区别

  2. 导入模块的两种方式:

    1
    2
    import xx
    from xxx import xxx
  3. 相对导入,需要有包名称。

  4. 模块重名可以通过as取别名。

  5. 执行py文件时,内部__name__=="__main__",导入模块时,被导入的模块 __name__="模块名"

  6. 在项目开发中,一般在主文件中会写上 main (主文件标记,不是绝对的,因为其他文件在开发调试时候有时候也可能有main)。

2. 第三方模块

Python内部提供的模块有限,所以在平时在开发的过程中,经常会使用第三方模块。

而第三方模块必须要先安装才能可以使用,下面介绍常见的3中安装第三方模块的方式。

其实,使用第三方模块的行为就是去用别人写好并开源出来的py代码,这样自己拿来就用,不必重复造轮子了。。。。

2.1 pip(最常用)

这是Python中最最最常用的安装第三方模块的方式。

pip其实是一个第三方模块包管理工具,默认安装Python解释器时自动会安装,默认目录:

1
2
3
4
5
6
7
MAC系统,即:Python安装路径的bin目录下
/Library/Frameworks/Python.framework/Versions/3.9/bin/pip3
/Library/Frameworks/Python.framework/Versions/3.9/bin/pip3.9

Windows系统,即:Python安装路径的scripts目录下
C:\Python39\Scripts\pip3.exe
C:\Python39\Scripts\pip3.9.exe

提示:为了方便在终端运行pip管理工具,我们也会把它所在的路径添加到系统环境变量中。

1
pip3 install 模块名称

如果你的电脑上某个写情况没有找到pip,也可以自己手动安装:

  • 下载 get-pip.py 文件,到任意目录

    1
    地址:https://bootstrap.pypa.io/get-pip.py
  • 打开终端进入目录,用Python解释器去运行已下载的 get-pip.py文件即刻安装成功。
    image-20210102191829546

使用pip去安装第三方模块也非常简单,只需要在自己终端执行:pip install 模块名称 即可。

image-20210102192637805

image-20210102192757171

默认安装的是最新的版本,如果想要指定版本:

1
2
3
4
pip3 install 模块名称==版本

例如:
pip3 install django==2.2

2.1.1 pip更新

上图的黄色字体提示:目前我电脑上的pip是20.2.3版本,最新的是 20.3.3 版本,如果想要升级为最新的版本,可以在终端执行他提示的命令:

1
/Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 -m pip install --upgrade pip

注意:根据自己电脑的提示命令去执行,不要用我这里的提示命令哈。

2.1.2 豆瓣源

pip默认是去 https://pypi.org 去下载第三方模块(本质上就是别人写好的py代码),国外的网站速度会比较慢,为了加速可以使用国内的豆瓣源。

  • 一次性使用

    1
    pip3.9 install 模块名称  -i  https://pypi.douban.com/simple/
  • 永久使用

    • 配置

      1
      2
      3
      4
      5
      6
      # 在终端执行如下命令
      pip3.9 config set global.index-url https://pypi.douban.com/simple/

      # 执行完成后,提示在我的本地文件中写入了豆瓣源,以后再通过pip去安装第三方模块时,就会默认使用豆瓣源了。
      # 自己以后也可以打开文件直接修改源地址。
      Writing to /Users/wupeiqi/.config/pip/pip.conf
    • 使用

      1
      pip3.9 install 模块名称

写在最后,也还有其他的源可供选择(豆瓣应用广泛)。

1
2
3
4
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科技大学:https://pypi.mirrors.ustc.edu.cn/simple/
清华大学:https://pypi.tuna.tsinghua.edu.cn/simple/
中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/

2.2 源码

如果要安装的模块在pypi.org中不存在 或 因特殊原因无法通过pip install 安装时,可以直接下载源码,然后基于源码安装,例如:

  • 下载requests源码(压缩包zip、tar、tar.gz)并解压。

    1
    下载地址:https://pypi.org/project/requests/#files
  • 进入目录

  • 执行编译和安装命令

    1
    2
    python3 setup.py build
    python3 setup.py install

    image-20210102215833498
    image-20210102220013804

2.3 wheel

wheel是Python的第三方模块包的文件格式的一种,我们也可以基于wheel去安装一些第三方模块。

  • 安装wheel格式支持,这样pip再安装第三方模块时,就可以处理wheel格式的文件了。

    1
    pip3.9 install wheel
  • 下载第三方的包(wheel格式),例如:https://pypi.org/project/requests/#files

    image-20210102221033465
  • 进入下载目录,在终端基于pip直接安装

    image-20210102221254461

无论通过什么形式去安装第三方模块,默认模块的安装路径在:

1
2
3
4
Max系统:
/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages
Windows系统:
C:\Python39\Lib\site-packages\

提醒:这个目录在sys.path中,所以我们直接在代码中直接导入下载的第三方包是没问题的。

3.内置模块(一)

Python内置的模块有很多,我们也已经接触了不少相关模块,接下来咱们就来做一些汇总和介绍。

内置模块有很多 & 模块中的功能也非常多,我们是没有办法注意全局给大家讲解,在此我会整理出项目开发最常用的来进行讲解。

3.1 os

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import os

# 1. 获取当前脚本绝对路径
"""
abs_path = os.path.abspath(__file__)
print(abs_path)
"""

# 2. 获取当前文件的上级目录
"""
base_path = os.path.dirname( os.path.dirname(路径) )
print(base_path)
"""

# 3. 路径拼接
"""
p1 = os.path.join(base_path, 'xx')
print(p1)

p2 = os.path.join(base_path, 'xx', 'oo', 'a1.png')
print(p2)
"""

# 4. 判断路径是否存在
"""
exists = os.path.exists(p1)
print(exists)
"""

# 5. 创建文件夹
"""
os.makedirs(路径)
"""
"""
path = os.path.join(base_path, 'xx', 'oo', 'uuuu')
if not os.path.exists(path):
os.makedirs(path)
"""

# 6. 是否是文件夹
"""
file_path = os.path.join(base_path, 'xx', 'oo', 'uuuu.png')
is_dir = os.path.isdir(file_path)
print(is_dir) # False

folder_path = os.path.join(base_path, 'xx', 'oo', 'uuuu')
is_dir = os.path.isdir(folder_path)
print(is_dir) # True

"""

# 7. 删除文件或文件夹
"""
os.remove("文件路径")
"""
"""
path = os.path.join(base_path, 'xx')
shutil.rmtree(path)
"""

  • listdir,查看目录下所有的文件
  • walk,查看目录下所有的文件(含子孙文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os

"""
data = os.listdir("/Users/wupeiqi/PycharmProjects/luffyCourse/day14/commons")
print(data)
# ['convert.py', '__init__.py', 'page.py', '__pycache__', 'utils.py', 'tencent']
"""

"""
要遍历一个文件夹下的所有文件,例如:遍历文件夹下的所有mp4文件
"""

data = os.walk("/Users/wupeiqi/Documents/视频教程/路飞Python/mp4")
for path, folder_list, file_list in data:
for file_name in file_list:
file_abs_path = os.path.join(path, file_name)
ext = file_abs_path.rsplit(".",1)[-1]
if ext == "mp4":
print(file_abs_path)

3.2 shutil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import shutil

# 1. 删除文件夹
"""
path = os.path.join(base_path, 'xx')
shutil.rmtree(path)
"""

# 2. 拷贝文件夹
"""
shutil.copytree("/Users/wupeiqi/Desktop/图/csdn/","/Users/wupeiqi/PycharmProjects/CodeRepository/files")
"""

# 3.拷贝文件
"""
shutil.copy("/Users/wupeiqi/Desktop/图/csdn/WX20201123-112406@2x.png","/Users/wupeiqi/PycharmProjects/CodeRepository/")
shutil.copy("/Users/wupeiqi/Desktop/图/csdn/WX20201123-112406@2x.png","/Users/wupeiqi/PycharmProjects/CodeRepository/x.png")
"""

# 4.文件或文件夹重命名
"""
shutil.move("/Users/wupeiqi/PycharmProjects/CodeRepository/x.png","/Users/wupeiqi/PycharmProjects/CodeRepository/xxxx.png")
shutil.move("/Users/wupeiqi/PycharmProjects/CodeRepository/files","/Users/wupeiqi/PycharmProjects/CodeRepository/images")
"""

# 5. 压缩文件
"""
# base_name,压缩后的压缩包文件
# format,压缩的格式,例如:"zip", "tar", "gztar", "bztar", or "xztar".
# root_dir,要压缩的文件夹路径
"""
# shutil.make_archive(base_name=r'datafile',format='zip',root_dir=r'files')


# 6. 解压文件
"""
# filename,要解压的压缩包文件
# extract_dir,解压的路径
# format,压缩文件格式
"""
# shutil.unpack_archive(filename=r'datafile.zip', extract_dir=r'xxxxxx/xo', format='zip')

3.3 sys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import sys

# 1. 获取解释器版本
"""
print(sys.version)
print(sys.version_info)
print(sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
"""

# 2. 导入模块路径
"""
print(sys.path)
"""

  • argv,执行脚本时,python解释器后面传入的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import sys

print(sys.argv)


# [
# '/Users/wupeiqi/PycharmProjects/luffyCourse/day14/2.接受执行脚本的参数.py'
# ]

# [
# "2.接受执行脚本的参数.py"
# ]

# ['2.接受执行脚本的参数.py', '127', '999', '666', 'wupeiqi']

# 例如,请实现下载图片的一个工具。

def download_image(url):
print("下载图片", url)


def run():
# 接受用户传入的参数
url_list = sys.argv[1:]
for url in url_list:
download_image(url)


if __name__ == '__main__':
run()

3.4 random

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import random

# 1. 获取范围内的随机整数
v = random.randint(10, 20)
print(v)

# 2. 获取范围内的随机小数
v = random.uniform(1, 10)
print(v)

# 3. 随机抽取一个元素
v = random.choice([11, 22, 33, 44, 55])
print(v)

# 4. 随机抽取多个元素
v = random.sample([11, 22, 33, 44, 55], 3)
print(v)

# 5. 打乱顺序
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
random.shuffle(data)
print(data)

3.5 hashlib

1
2
3
4
5
6
import hashlib

hash_object = hashlib.md5()
hash_object.update("武沛齐".encode('utf-8'))
result = hash_object.hexdigest()
print(result)
1
2
3
4
5
6
import hashlib

hash_object = hashlib.md5("iajfsdunjaksdjfasdfasdf".encode('utf-8'))
hash_object.update("武沛齐".encode('utf-8'))
result = hash_object.hexdigest()
print(result)

3.6 configparser

见:day09

3.7 xml

见:day09

总结

  1. 模块和包的区别

  2. 了解如何导入模块

    • 路径
    • 导入方式
  3. 导入模块时一般要遵循的规范【补充】

    • 注释:文件顶部或init文件中。

    • 在文件顶部导入

    • 有规则导入,并用空行分割。

      1
      2
      3
      4
      5
      # 先内置模块

      # 再第三方模块

      # 最后自定义模块
      1
      2
      3
      4
      5
      6
      7
      8
      9
      import os
      import sys
      import random
      import hashlib

      import requests
      import openpyxl

      from commons.utils import encrypt
  4. 第三方模块安装的方法

  5. 常见内置模块

作业

  1. 自己去网上搜索如何基于Python计算mp4视频的时长,最终实现用代码统计某个文件夹下所有mp4的时长。

day13 内置函数和推导式

image-20201230125816095

今日概要:

  • 匿名函数
  • 生成器
  • 内置函数
  • 附加:推导式,属于数据类型的知识,内部的高级的用法会涉及到【生成器】和【函数】的知识。

1. 匿名函数

传统的函数的定义包括了:函数名 + 函数体。

1
2
3
4
5
6
7
8
9
def send_email():
pass

# 1. 执行
send_email()
# 2. 当做列表元素
data_list = [send_email, send_email, send_email ]
# 3. 当做参数传递
other_function(send_email)

匿名函数,则是基于lambda表达式实现定义一个可以没有名字的函数,例如:

1
2
3
data_list = [ lambda x:x+100,  lambda x:x+110, lambda x:x+120 ]

print( data_list[0] )
1
2
3
4
f1 = lambda x:x+100

res = f1(100)
print(res)

基于Lambda定义的函数格式为:lambda 参数:函数体

  • 参数,支持任意参数。

    1
    2
    3
    lambda x: 函数体
    lambda x1,x2: 函数体
    lambda *args, **kwargs: 函数体
  • 函数体,只能支持单行的代码。

    1
    2
    3
    4
    def xxx(x):
    return x + 100

    lambda x: x + 100
  • 返回值,默认将函数体单行代码执行的结果返回给函数的执行这。

    1
    2
    3
    4
    func = lambda x: x + 100

    v1 = func(10)
    print(v1) # 110
1
2
3
4
def func(a1,a2):
return a1 + a2 + 100

foo = lambda a1,a2: a1 + a2 + 100

匿名函数适用于简单的业务处理,可以快速并简单的创建函数。

练习题

根据函数写写出其匿名函数的表达方式

1
2
3
4
def func(a1,a2):
return a1 + a2

func = lambda a1,a2: a1+a2
1
2
3
4
def func(data):
return data.replace("苍老师","***")

func= lambda data: data.replace("苍老师","***")
1
2
3
4
5
def func(data):
name_list = data.replace(".")
return name_list[-1]

func = lambda data: data.replace(".")[-1]

在编写匿名函数时,由于受限 函数体只能写一行,所以匿名函数只能处理非常简单的功能。

扩展:三元运算

简单的函数,可以基于lambda表达式实现。

简单的条件语句,可以基于三元运算实现,例如:

1
2
3
4
5
6
7
8
num = input("请写入内容")

if "苍老师" in num:
data = "臭不要脸"
else:
data = "正经人"

print(data)
1
2
3
4
5
num = input("请写入内容")
data = "臭不要脸" if "苍老师" in num else "正经人"
print(data)

# 结果 = 条件成立时 if 条件 else 不成立

lambda表达式和三元运算没有任何关系,属于两个独立的知识点。

掌握三元运算之后,以后再编写匿名函数时,就可以处理再稍微复杂点的情况了,例如:

1
2
3
4
5
6
7
func = lambda x: "大了" if x > 66 else "小了"

v1 = func(1)
print(v1) # "小了"

v2 = func(100)
print(v2) # "大了"

2. 生成器

生成器是由函数+yield关键字创造出来的写法,在特定情况下,用他可以帮助我们节省内存。

  • 生成器函数,但函数中有yield存在时,这个函数就是生产生成器函数。

    1
    2
    3
    def func():
    print(111)
    yield 1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def func():
    print(111)
    yield 1

    print(222)
    yield 2

    print(333)
    yield 3

    print(444)
  • 生成器对象,执行生成器函数时,会返回一个生成器对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def func():
    print(111)
    yield 1

    print(222)
    yield 2

    print(333)
    yield 3

    print(444)

    data = func()

    # 执行生成器函数func,返回的生成器对象。
    # 注意:执行生成器函数时,函数内部代码不会执行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    def func():
    print(111)
    yield 1

    print(222)
    yield 2

    print(333)
    yield 3

    print(444)

    data = func()

    v1 = next(data)
    print(v1)

    v2 = next(data)
    print(v2)

    v3 = next(data)
    print(v3)

    v4 = next(data)
    print(v4) # 结束或中途遇到return,程序爆:StopIteration 错误
    1
    2
    3
    4
    data = func()

    for item in data:
    print(item)

生成器的特点是,记录在函数中的执行位置,下次执行next时,会从上一次的位置基础上再继续向下执行。

应用场景

  • 假设要让你生成 300w个随机的4位数,并打印出来。

    • 在内存中一次性创建300w个
    • 动态创建,用一个创建一个。
    1
    2
    3
    4
    import random

    val = random.randint(1000, 9999)
    print(val)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import random

    data_list = []
    for i in range(300000000):
    val = random.randint(1000, 9999)
    data_list.append(val)

    # 再使用时,去 data_list 中获取即可。
    # ...
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import random


    def gen_random_num(max_count):
    counter = 0
    while counter < max_count:
    yield random.randint(1000, 9999)
    counter += 1


    data_list = gen_random_num(3000000)
    # 再使用时,去 data_list 中获取即可。
  • 假设让你从某个数据源中获取300w条数据(后期学习操作MySQL 或 Redis等数据源再操作,了解思想即可)。

image-20201230174253215

所以,当以后需要我们在内存中创建很多数据时,可以想着用基于生成器来实现一点一点生成(用一点生产一点),以节省内存的开销。

扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def func():
print(111)
v1 = yield 1
print(v1)

print(222)
v2 = yield 2
print(v2)

print(333)
v3 = yield 3
print(v3)

print(444)


data = func()

n1 = data.send(None)
print(n1)

n2 = data.send(666)
print(n2)

n3 = data.send(777)
print(n3)

n4 = data.send(888)
print(n4)

3.内置函数

image-20201230201618164

Python内部为我们提供了很多方便的内置函数,在此整理出来36个给大家来讲解。

  • 第1组(5个)

    • abs,绝对值

      1
      v = abs(-10)
    • pow,指数

      1
      2
      v1 = pow(2,5) # 2的5次方  2**5
      print(v1)
    • sum,求和

      1
      2
      v1 = sum([-11, 22, 33, 44, 55]) # 可以被迭代-for循环
      print(v1)
    • divmod,求商和余数

      1
      2
      v1, v2 = divmod(9, 2)
      print(v1, v2)
    • round,小数点后n位(四舍五入)

      1
      2
      v1 = round(4.11786, 2)
      print(v1) # 4.12
  • 第2组:(4个)

    • min,最小值

      1
      2
      v1 = min(11, 2, 3, 4, 5, 56)
      print(v1) # 2
      1
      2
      v2 = min([11, 22, 33, 44, 55]) # 迭代的类型(for循环)
      print(v2)
      1
      2
      v3 = min([-11, 2, 33, 44, 55], key=lambda x: abs(x))
      print(v3) # 2
    • max,最大值

      1
      2
      3
      4
      5
      v1 = max(11, 2, 3, 4, 5, 56)
      print(v1)

      v2 = max([11, 22, 33, 44, 55])
      print(v2)
      1
      2
      v3 = max([-11, 22, 33, 44, 55], key=lambda x: x * 10)
      print(v3) # 55
    • all,是否全部为True

      1
      v1 = all(   [11,22,44,""]   ) # False
    • any,是否存在True

      1
      v2 = any([11,22,44,""]) # True
  • 第3组(3个)

    • bin,十进制转二进制
    • oct,十进制转八进制
    • hex,十进制转十六进制
  • 第4组(2个)

    • ord,获取字符对应的unicode码点(十进制)

      1
      2
      v1 = ord("武")
      print(v1, hex(v1))
    • chr,根据码点(十进制)获取对应字符

      1
      2
      v1 = chr(27494)
      print(v1)
  • 第5组(9个)

    • int

    • foat

    • str,unicode编码

    • bytes,utf-8、gbk编码

      1
      2
      3
      4
      5
      v1 = "武沛齐"  # str类型

      v2 = v1.encode('utf-8') # bytes类型

      v3 = bytes(v1,encoding="utf-8") # bytes类型
    • bool

    • list

    • dict

    • tuple

    • set

  • 第6组(13个)

    • len

    • print

    • input

    • open

    • type,获取数据类型

      1
      2
      3
      4
      5
      6
      v1 = "123"

      if type(v1) == str:
      pass
      else:
      pass
    • range

      1
      range(10)
    • enumerate

      1
      2
      3
      4
      v1 = ["武沛齐", "alex", 'root']

      for num, value in enumerate(v1, 1):
      print(num, value)
    • id

    • hash

      1
      v1 = hash("武沛齐")
    • help,帮助信息

      • pycharm,不用
      • 终端,使用
    • zip

      1
      2
      3
      4
      5
      6
      7
      v1 = [11, 22, 33, 44, 55, 66]
      v2 = [55, 66, 77, 88]
      v3 = [10, 20, 30, 40, 50]

      result = zip(v1, v2, v3)
      for item in result:
      print(item)
    • callable,是否可执行,后面是否可以加括号。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      v1 = "武沛齐"
      v2 = lambda x: x
      def v3():
      pass


      print( callable(v1) ) # False
      print(callable(v2))
      print(callable(v3))
    • sorted,排序

      1
      v1 = sorted([11,22,33,44,55])
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      info = {
      "wupeiqi": {
      'id': 10,
      'age': 119
      },
      "root": {
      'id': 20,
      'age': 29
      },
      "seven": {
      'id': 9,
      'age': 9
      },
      "admin": {
      'id': 11,
      'age': 139
      },
      }

      result = sorted(info.items(), key=lambda x: x[1]['id'])
      print(result)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      data_list = [
      '1-5 编译器和解释器.mp4',
      '1-17 今日作业.mp4',
      '1-9 Python解释器种类.mp4',
      '1-16 今日总结.mp4',
      '1-2 课堂笔记的创建.mp4',
      '1-15 Pycharm使用和破解(win系统).mp4',
      '1-12 python解释器的安装(mac系统).mp4',
      '1-13 python解释器的安装(win系统).mp4',
      '1-8 Python介绍.mp4', '1-7 编程语言的分类.mp4',
      '1-3 常见计算机基本概念.mp4',
      '1-14 Pycharm使用和破解(mac系统).mp4',
      '1-10 CPython解释器版本.mp4',
      '1-1 今日概要.mp4',
      '1-6 学习编程本质上的三件事.mp4',
      '1-18 作业答案和讲解.mp4',
      '1-4 编程语言.mp4',
      '1-11 环境搭建说明.mp4'
      ]
      result = sorted(data_list, key=lambda x: int(x.split(' ')[0].split("-")[-1]) )
      print(result)

4.推导式

推导式是Python中提供了一个非常方便的功能,可以让我们通过一行代码实现创建list、dict、tuple、set 的同时初始化一些值。

请创建一个列表,并在列表中初始化:0、1、2、3、4、5、6、7、8、9…299 整数元素。

1
2
3
data = []
for i in range(300):
data.append(i)
  • 列表

    1
    2
    3
    4
    5
    num_list = [ i for i in range(10)]

    num_list = [ [i,i] for i in range(10)]

    num_list = [ [i,i] for i in range(10) if i > 6 ]
  • 集合

    1
    2
    3
    4
    5
    num_set = { i for i in range(10)}

    num_set = { (i,i,i) for i in range(10)}

    num_set = { (i,i,i) for i in range(10) if i>3}
  • 字典

    1
    2
    3
    4
    5
    num_dict = { i:i for i in range(10)}

    num_dict = { i:(i,11) for i in range(10)}

    num_dict = { i:(i,11) for i in range(10) if i>7}
  • 元组,不同于其他类型。

    1
    2
    3
    4
    5
    # 不会立即执行内部循环去生成数据,而是得到一个生成器。
    data = (i for i in range(10))
    print(data)
    for item in data:
    print(item)

练习题

  1. 去除列表中每个元素的 .mp4后缀。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    data_list = [
    '1-5 编译器和解释器.mp4',
    '1-17 今日作业.mp4',
    '1-9 Python解释器种类.mp4',
    '1-16 今日总结.mp4',
    '1-2 课堂笔记的创建.mp4',
    '1-15 Pycharm使用和破解(win系统).mp4',
    '1-12 python解释器的安装(mac系统).mp4',
    '1-13 python解释器的安装(win系统).mp4',
    '1-8 Python介绍.mp4', '1-7 编程语言的分类.mp4',
    '1-3 常见计算机基本概念.mp4',
    '1-14 Pycharm使用和破解(mac系统).mp4',
    '1-10 CPython解释器版本.mp4',
    '1-1 今日概要.mp4',
    '1-6 学习编程本质上的三件事.mp4',
    '1-18 作业答案和讲解.mp4',
    '1-4 编程语言.mp4',
    '1-11 环境搭建说明.mp4'
    ]

    result = []
    for item in data_list:
    result.append(item.rsplit('.',1)[0])

    result = [ item.rsplit('.',1)[0] for item in data_list]
  2. 将字典中的元素按照 键-值格式化,并最终使用 ;连接起来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    info = {
    "name":"武沛齐",
    "email":"xxx@live.com",
    "gender":"男",
    }

    data_list []
    for k,v in info.items():
    temp = "{}-{}".format(k,v)
    temp.append(data_list)
    resutl = ";".join(data)

    result = ";".join( [ "{}-{}".format(k,v) for k,v in info.items()] )
  3. 将字典按照键从小到大排序,然后在按照如下格式拼接起来。(微信支付API内部处理需求)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    info = {
    'sign_type': "MD5",
    'out_refund_no': "12323",
    'appid': 'wx55cca0b94f723dc7',
    'mch_id': '1526049051',
    'out_trade_no': "ffff",
    'nonce_str': "sdfdffd",
    'total_fee': 9901,
    'refund_fee': 10000
    }

    data = "&".join(["{}={}".format(key, value) for key, value in sorted(info.items(), key=lambda x: x[0])])
    print(data)
  4. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    def func():
    print(123)


    data_list = [func for i in range(10)]

    print(data_list)
  5. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    def func(num):
    return num + 100


    data_list = [func(i) for i in range(10)]

    print(data_list)
  6. 看代码写结果(执行出错,通过他可以让你更好的理解执行过程)

    1
    2
    3
    4
    5
    6
    7
    def func(x):
    return x + i

    data_list = [func for i in range(10)]

    val = data_list[0](100)
    print(val)
  7. 看代码写结果(新浪微博面试题)

    1
    2
    3
    4
    5
    data_list = [lambda x: x + i for i in range(10)]  # [函数,函数,函数]   i=9

    v1 = data_list[0](100)
    v2 = data_list[3](100)
    print(v1, v2) # 109 109

小高级

  1. 推导式支持嵌套

    1
    2
    3
    4
    5
    data = [ i for i in range(10)]

    data = []
    for i in range(10):
    data.append(i)
    1
    2
    3
    4
    5
    6
    data = [ [i,j] for j in range(5) for i in range(10) ]

    data = []
    for j in range(5):
    for i in range(10):
    data.append([i,j])
    1
    2
    3
    4
    5
    6
    # 一副扑克牌
    poker_list = [ [color, num] for num in range(1, 14) for color in ["红桃", "黑桃", "方片", "梅花"]]
    print(poker_list)


    poker_list = [ (color,num) for num in range(1,14) for color in ["红桃", "黑桃", "方片", "梅花"] ]
  2. 烧脑面试题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def num():
    return [lambda x: i * x for i in range(4)]


    # 1. num()并获取返回值 [函数,函数,函数,函数] i=3
    # 2. for循环返回值
    # 3. 返回值的每个元素(2)
    result = [m(2) for m in num()] # [6,6,6,6]
    print(result)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def num():
    return (lambda x: i * x for i in range(4))


    # 1. num()并获取返回值 生成器对象
    # 2. for循环返回值
    # 3. 返回值的每个元素(2)
    result = [m(2) for m in num()] # [0,2,4,6 ]
    print(result)

总结

  1. 匿名函数,基于lambda表达式实现一行创建一个函数。一般用于编写简单的函数。
  2. 三元运算,用一行代码实现处理简单的条件判断和赋值。
  3. 生成器,函数中如果yield关键字
    • 生成器函数
    • 生成器对象
    • 执行生成器函数中的代码
      • next
      • for(常用)
      • send
  4. 内置函数(36个)
  5. 推导式
    • 常规操作
    • 小高级操作

作业

  1. 看代码写结果

    1
    2
    3
    4
    v = [ lambda :x  for x in range(10)] 
    print(v)
    print(v[0])
    print(v[0]())
  2. 看代码写结果

    1
    2
    v = [i for i in range(10,0,-1) if i > 5]
    print(v)
  3. 看代码写结果

    1
    2
    3
    4
    data = [lambda x:x*i for i in range(10)]
    print(data)
    print(data[0](2))
    print(data[0](2) == data[8](2))
  4. 请用列表推导式实现,踢出列表中的字符串,最终生成一个新的列表保存。

    1
    2
    3
    4
    5
    data_list = [11,22,33,"alex",455,'eirc']

    new_data_list = [ ... ] # 请在[]中补充代码实现。

    # 提示:可以用type判断类型
  5. 请用列表推导式实现,对data_list中的每个元素判断,如果是字符串类型,则计算长度作为元素放在新列表的元素中;如果是整型,则让其值+100 作为元素放在新的列表的元素中。

    1
    2
    3
    4
    5
    data_list = [11,22,33,"alex",455,'eirc']

    new_data_list = [ ... ] # 请在[]中补充代码实现。

    # 提示:可以基于三元运算实现
  6. 请使用字典推导式实现,将如果列表构造成指定格式字典.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    data_list = [
    (1,'alex',19),
    (2,'老男',84),
    (3,'老女',73)
    ]

    # 请使用推导式将data_list构造生如下格式:
    """
    info_dict = {
    1:(1,'alex',19),
    2:(2,'老男',84),
    3:(3,'老女',73)
    }
    """
  7. 有4个人玩扑克牌比大小,请对比字典中每个人的牌的大小,并输入优胜者的姓名(值大的胜利,不必考虑A)。

    1
    2
    3
    4
    5
    6
    player = {
    "武沛齐":["红桃",10],
    "alex":["红桃",8],
    'eric':["黑桃",3],
    'killy':["梅花",12],
    }
  8. 尽量多的列举你记得的内置函数?【能记住多少就写多少,不强制去背,在此尽权利写即可,这种公共后续用的多了就自然而然就记住了】

  9. 请编写一个生成器函数实现生成n个斐波那契数列的值。

    • 什么是斐波那契数列?

      1
      2
      前两个数相加的结果,就是下一个数。
      1 1 2 3 5 8 13 21 34 55 ...
    • 代码结构示例,请在此基础上补充代码实现。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      def fib(max_count):
      pass


      count = input("请输入要生成斐波那契数列的个数:")
      count = int(count)
      fib_generator = fib(count)
      for num in fib_generator:
      print(num)

day12 函数高级

image-20201228153850400

课程目标:掌握函数嵌套、闭包、装饰器等高级知识点。

今日概要:

  • 函数的嵌套
  • 闭包
  • 装饰器

上述内容均属于函数部分必备知识,以后开发时直接和间接都会使用,请务必理解(重在理解,不要去死记硬背)。

1. 函数嵌套

Python中以函数为作用域,在作用域中定义的相关数据只能被当前作用域或子作用域使用。

1
2
3
4
5
6
7
NAME = "武沛齐"
print(NAME)

def func():
print(NAME)

func()

1.1 函数在作用域中

其实,函数也是定义在作用域中的数据,在执行函数时候,也同样遵循:优先在自己作用域中寻找,没有则向上一接作用域寻找,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 在全局作用域定义了函数func
def func():
print("你好")

# 2. 在全局作用域找到func函数并执行。
func()


# 3.在全局作用域定义了execute函数
def execute():
print("开始")
# 优先在当前函数作用域找func函数,没有则向上级作用域中寻找。
func()
print("结束")

# 4.在全局作用域执行execute函数
execute()

此处,有一个易错点:作用域中的值在被调用时到底是啥?

  • 情景1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def func():
    print("你好")

    func()

    def execute():
    print("开始")
    func()
    print("结束")

    execute()

    def func():
    print(666)

    func()
  • 情景2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def func():
    print("你好")

    func()

    def execute():
    print("开始")
    func()
    print("结束")

    def func():
    print(666)

    func()
    execute()

1.2 函数定义的位置

上述示例中的函数均定义在全局作用域,其实函数也可以定义在局部作用域,这样函数被局部作用域和其子作用于中调用(函数的嵌套)。

1
2
3
4
5
6
7
8
9
10
11
12
def func():
print("沙河高晓松")

def handler():
print("昌平吴彦祖")
def inner():
print("朝阳大妈")
inner()
func()
print("海淀网友")

handler()

到现在你会发现,只要理解数据定义时所存在的作用域,并根据从上到下代码执行过程进行分析,再怎么嵌套都可以搞定。

现在的你可能有疑问:为什么要这么嵌套定义?把函数都定义在全局不好吗?

其实,大多数情况下我们都会将函数定义在全局,不会嵌套着定义函数。不过,当我们定义一个函数去实现某功能,想要将内部功能拆分成N个函数,又担心这个N个函数放在全局会与其他函数名冲突时(尤其多人协同开发)可以选择使用函数的嵌套。

1
2
3
4
5
6
7
8
9
def f1():
pass

def f2():
pass

def func():
f1()
f2()
1
2
3
4
5
6
7
8
def func():
def f1():
pass

def f2():
pass
f1()
f2()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""
生成图片验证码的示例代码,需要提前安装pillow模块(Python中操作图片中一个第三方模块)
pip3 install pillow
"""
import random
from PIL import Image, ImageDraw, ImageFont


def create_image_code(img_file_path, text=None, size=(120, 30), mode="RGB", bg_color=(255, 255, 255)):
""" 生成一个图片验证码 """
_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(3, 10))) # 数字
chars = ''.join((_letter_cases, _upper_cases, _numbers))

width, height = size # 宽高
# 创建图形
img = Image.new(mode, size, bg_color)
draw = ImageDraw.Draw(img) # 创建画笔

def get_chars():
"""生成给定长度的字符串,返回列表格式"""
return random.sample(chars, 4)

def create_lines():
"""绘制干扰线"""
line_num = random.randint(*(1, 2)) # 干扰线条数

for i in range(line_num):
# 起始点
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
# 结束点
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0))

def create_points():
"""绘制干扰点"""
chance = min(100, max(0, int(2))) # 大小限制在[0, 100]

for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0))

def create_code():
"""绘制验证码字符"""
if text:
code_string = text
else:
char_list = get_chars()
code_string = ''.join(char_list) # 每个字符前后以空格隔开

# Win系统字体
# font = ImageFont.truetype(r"C:\Windows\Fonts\SEGOEPR.TTF", size=24)
# Mac系统字体
# font = ImageFont.truetype("/System/Library/Fonts/SFNSRounded.ttf", size=24)
# 项目字体文件
font = ImageFont.truetype("MSYH.TTC", size=15)
draw.text([0, 0], code_string, "red", font=font)
return code_string

create_lines()
create_points()
code = create_code()

# 将图片写入到文件
with open(img_file_path, mode='wb') as img_object:
img.save(img_object)
return code


code = create_image_code("a2.png")
print(code)

1.3 嵌套引发的作用域问题

基于内存和执行过程分析作用域。

1
2
3
4
5
6
7
8
9
name = "武沛齐"

def run():
name = "alex"
def inner():
print(name)
inner()

run()

image-20201229131739455

1
2
3
4
5
6
7
8
9
10
11
12
13
name = "武沛齐"

def run():
name = "alex"
def inner():
print(name)
return inner

v1 = run()
v1()

v2 = run()
v2()

image-20201229132237241

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
name = "武沛齐"

def run():
name = "alex"
def inner():
print(name)
return [inner,inner,inner]

func_list = run()
func_list[2]()
func_list[1]()

funcs = run()
funcs[2]()
funcs[1]()

image-20201229132648896

三句话搞定作用域:

  • 优先在自己的作用域找,自己没有就去上级作用域。
  • 在作用域中寻找值时,要确保此次此刻值是什么。
  • 分析函数的执行,并确定函数作用域链。(函数嵌套)

练习题

  1. 分析代码,写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    name = '武沛齐'

    def func():
    def inner():
    print(name)
    res = inner()
    return res

    v = func()
    print(v)

    # 武沛齐
    # None
  2. 分析代码,写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    name = '武沛齐'

    def func():
    def inner():
    print(name)
    return "alex"
    res = inner()
    return res

    v = func()
    print(v)

    # 武沛齐
    # alex
  3. 分析代码,写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    name = 'root'

    def func():
    def inner():
    print(name)
    return 'admin'
    return inner

    v = func()
    result = v()
    print(result)

    # root
    # admin
  4. 分析代码,写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def func():
    name = '武沛齐'
    def inner():
    print(name)
    return '路飞'
    return inner

    v11 = func()
    data = v11()
    print(data)


    v2 = func()()
    print(v2)
  5. 分析代码,写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def func(name):
    # name="alex"
    def inner():
    print(name)
    return 'luffy'
    return inner

    v1 = func('武沛齐')()
    print(v1)

    v2 = func('alex')()
    print(v2)

    image-20201229140559322

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def func(name):
    def inner():
    print(name)
    return 'luffy'
    return inner

    v1 = func('武沛齐')
    v2 = func('alex')
    v1()
    v2()

    image-20201229165929911

  6. 分析代码,写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def func(name=None):
    if not name:
    name= '武沛齐'
    def inner():
    print(name)
    return 'root'
    return inner

    v1 = func()()
    v2 = func('alex')()
    print(v1,v2)

    # 武沛齐
    # alex
    # root root

    image-20201229171258454

2.闭包

闭包,简而言之就是将数据封装在一个包(区域)中,使用时再去里面取。(本质上 闭包是基于函数嵌套搞出来一个中特殊嵌套)

  • 闭包应用场景1:封装数据防止污染全局。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    name = "武沛齐"

    def f1():
    print(name, age)

    def f2():
    print(name, age)

    def f3():
    print(name, age)

    def f4():
    pass
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def func(age):
    name = "武沛齐"

    def f1():
    print(name, age)

    def f2():
    print(name, age)

    def f3():
    print(name, age)

    f1()
    f2()
    f3()

    func(123)
  • 闭包应用场景2:封装数据封到一个包里,使用时在取。
    image-20201229181719550

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def task(arg):
    def inner():
    print(arg)
    return inner

    v1 = task(11)
    v2 = task(22)
    v3 = task(33)
    v1()
    v2()
    v3()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def task(arg):
    def inner():
    print(arg)
    return inner

    inner_func_list = []
    for val in [11,22,33]:
    inner_func_list.append( task(val) )

    inner_func_list[0]() # 11
    inner_func_list[1]() # 22
    inner_func_list[2]() # 33
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    """ 基于多线程去下载视频 """
    from concurrent.futures.thread import ThreadPoolExecutor

    import requests


    def download_video(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"
    }
    )
    return res.content


    def outer(file_name):
    def write_file(response):
    content = response.result()
    with open(file_name, mode='wb') as file_object:
    file_object.write(content)

    return write_file


    POOL = ThreadPoolExecutor(10)

    video_dict = [
    ("东北F4模仿秀.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"),
    ("卡特扣篮.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"),
    ("罗斯mvp.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg")
    ]
    for item in video_dict:
    future = POOL.submit(download_video, url=item[1])
    future.add_done_callback(outer(item[0]))

    POOL.shutdown()

    image-20201229185549102

3.装饰器

现在给你一个函数,在不修改函数源码的前提下,实现在函数执行前和执行后分别输入 “before” 和 “after”。

1
2
3
4
5
6
7
def func():
print("我是func函数")
value = (11,22,33,44)
return value

result = func()
print(result)

3.1 第一回合

你的实现思路:

1
2
3
4
5
6
7
8
9
10
11
def func():
print("before")

print("我是func函数")
value = (11,22,33,44)

print("after")

return value

result = func()

我的实现思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def func():
print("我是func函数")
value = (11, 22, 33, 44)
return value


def outer(origin):
def inner():
print('inner')
origin()
print("after")

return inner

func = outer(func)
result = func()

处理返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def func():
print("我是func函数")
value = (11, 22, 33, 44)
return value


def outer(origin):
def inner():
print('inner')
res = origin()
print("after")
return res
return inner

func = outer(func)
result = func()

3.2 第二回合

在Python中有个一个特殊的语法糖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def outer(origin):
def inner():
print('inner')
res = origin()
print("after")
return res
return inner


@outer
def func():
print("我是func函数")
value = (11, 22, 33, 44)
return value


func()

3.3 第三回合

请在这3个函数执行前和执行后分别输入 “before” 和 “after”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def func1():
print("我是func1函数")
value = (11, 22, 33, 44)
return value


def func2():
print("我是func2函数")
value = (11, 22, 33, 44)
return value

def func3():
print("我是func3函数")
value = (11, 22, 33, 44)
return value

func1()
func2()
func3()

你的实现思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def func1():
print('before')
print("我是func1函数")
value = (11, 22, 33, 44)
print("after")
return value


def func2():
print('before')
print("我是func2函数")
value = (11, 22, 33, 44)
print("after")
return value

def func3():
print('before')
print("我是func3函数")
value = (11, 22, 33, 44)
print("after")
return value

func1()
func2()
func3()

我的实现思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def outer(origin):
def inner():
print("before 110")
res = origin() # 调用原来的func函数
print("after")
return res

return inner


@outer
def func1():
print("我是func1函数")
value = (11, 22, 33, 44)
return value


@outer
def func2():
print("我是func2函数")
value = (11, 22, 33, 44)
return value


@outer
def func3():
print("我是func3函数")
value = (11, 22, 33, 44)
return value


func1()
func2()
func3()

装饰器,在不修改原函数内容的前提下,通过@函数可以实现在函数前后自定义执行一些功能(批量操作会更有意义)。

优化

优化以支持多个参数的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def outer(origin):
def inner(*args, **kwargs):
print("before 110")
res = origin(*args, **kwargs) # 调用原来的func函数
print("after")
return res

return inner


@outer # func1 = outer(func1)
def func1(a1):
print("我是func1函数")
value = (11, 22, 33, 44)
return value


@outer # func2 = outer(func2)
def func2(a1, a2):
print("我是func2函数")
value = (11, 22, 33, 44)
return value


@outer # func3 = outer(func3)
def func3(a1):
print("我是func3函数")
value = (11, 22, 33, 44)
return value


func1(1)
func2(11, a2=22)
func3(999)

其中,我的那种写法就称为装饰器。

  • 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数。

  • 实现效果:可以在不改变原函数内部代码 和 调用方式的前提下,实现在函数执行和执行扩展功能。

  • 适用场景:多个函数系统统一在 执行前后自定义一些功能。

  • 装饰器示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def outer(origin):
    def inner(*args, **kwargs):
    # 执行前
    res = origin(*args, **kwargs) # 调用原来的func函数
    # 执行后
    return res
    return inner


    @outer
    def func():
    pass

    func()

伪应用场景

在以后编写一个网站时,如果项目共有100个页面,其中99个是需要登录成功之后才有权限访问,就可以基于装饰器来实现。

1
pip3 install flask

基于第三方模块Flask(框架)快速写一个网站:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from flask import Flask

app = Flask(__name__)


def index():
return "首页"


def info():
return "用户中心"


def order():
return "订单中心"


def login():
return "登录页面"


app.add_url_rule("/index/", view_func=index)
app.add_url_rule("/info/", view_func=info)
app.add_url_rule("/login/", view_func=login)

app.run()

基于装饰器实现的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from flask import Flask

app = Flask(__name__)


def auth(func):
def inner(*args, **kwargs):
# 在此处,判断如果用户是否已经登录,已登录则继续往下,未登录则自动跳转到登录页面。
return func(*args, **kwargs)

return inner


@auth
def index():
return "首页"


@auth
def info():
return "用户中心"


@auth
def order():
return "订单中心"


def login():
return "登录页面"


app.add_url_rule("/index/", view_func=index, endpoint='index')
app.add_url_rule("/info/", view_func=info, endpoint='info')
app.add_url_rule("/order/", view_func=order, endpoint='order')
app.add_url_rule("/login/", view_func=login, endpoint='login')

app.run()

重要补充:functools

你会发现装饰器实际上就是将原函数更改为其他的函数,然后再此函数中再去调用原函数。

1
2
3
4
5
def handler():
pass

handler()
print(handler.__name__) # handler
1
2
3
4
5
6
7
8
9
10
11
def auth(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner

@auth
def handler():
pass

handler()
print(handler.__name__) # inner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import functools

def auth(func):
@functools.wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner

@auth
def handler():
pass

handler()
print(handler.__name__) # handler

其实,一般情况下大家不用functools也可以实现装饰器的基本功能,但后期在项目开发时,不加functools会出错(内部会读取__name__,且__name__重名的话就报错),所以在此大家就要规范起来自己的写法。

1
2
3
4
5
6
7
8
9
10
11
import functools


def auth(func):
@functools.wraps(func)
def inner(*args, **kwargs):
"""巴巴里吧"""
res = func(*args, **kwargs) # 执行原函数
return res

return inner

总结

  1. 函数可以定义在全局、也可以定义另外一个函数中(函数的嵌套)

  2. 学会分析函数执行的步骤(内存中作用域的管理)

  3. 闭包,基于函数的嵌套,可以将数据封装到一个包中,以后再去调用。

  4. 装饰器

    • 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数。

    • 实现效果:可以在不改变原函数内部代码 和 调用方式的前提下,实现在函数执行和执行扩展功能。

    • 适用场景:多个函数系统统一在 执行前后自定义一些功能。

    • 装饰器示例

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      import functools


      def auth(func):
      @functools.wraps(func)
      def inner(*args, **kwargs):
      """巴巴里吧"""
      res = func(*args, **kwargs) # 执行原函数
      return res

      return inner

作业

  1. 请为以下所有函数编写一个装饰器,添加上装饰器后可以实现:执行func时,先执行func函数内部代码,再输出 “after”

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def func(a1):
    return a1 + "傻叉"

    def base(a1,a2):
    return a1 + a2 + '傻缺'


    def foo(a1,a2,a3,a4):
    return a1 + a2 + a3 + a4 + '傻蛋'
  2. 请为以下所有函数编写一个装饰器,添加上装饰器后可以实现:将被装饰的函数执行5次,讲每次执行函数的结果按照顺序放到列表中,最终返回列表。

    1
    2
    3
    4
    5
    6
    7
    8
    import random 


    def func():
    return random.randint(1,4)

    result = func() # 内部自动执行5次,并将每次执行的结果追加到列表最终返回给result
    print(result)
  3. 请为以下函数编写一个装饰器,添加上装饰器后可以实现: 检查文件所在路径(文件件)是否存在,如果不存在自动创建文件夹(保证写入文件不报错)。

    1
    2
    3
    4
    5
    6
    def write_user_info(path):
    file_obj = open(path, mode='w', encoding='utf-8')
    file_obj.write("武沛齐")
    file_obj.close()

    write_user_info('/usr/bin/xxx/xxx.png')
  4. 分析代码写结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def get_data():
    scores = []

    def inner(val):
    scores.append(val)
    print(scores)

    return inner


    func = get_data()

    func(10)
    func(20)
    func(30)
  5. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    name = "武沛齐"


    def foo():
    print(name)


    def func():
    name = "root"
    foo()


    func()
  6. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    name = "武沛齐"


    def func():
    name = "root"

    def foo():
    print(name)

    foo()


    func()
  7. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def func(val):
    def inner(a1, a2):
    return a1 + a2 + val

    return inner


    data_list = []

    for i in range(10):
    data_list.append( func(i) )

    print(data_list)
  8. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def func(val):
    def inner(a1, a2):
    return a1 + a2 + val

    return inner


    data_list = []

    for i in range(10):
    data_list.append(func(i))

    v1 = data_list[0](11,22)
    v2 = data_list[2](33,11)

    print(v1)
    print(v2)

day11 函数进阶

image-20201222145103056

目标:掌握函数相关易错点 & 项目开发必备技能。

今日概要:

  • 参数的补充
  • 函数名,函数名到底是什么?
  • 返回值和print,傻傻分不清楚。
  • 函数的作用域

1.参数的补充

在函数基础部分,我们掌握函数和参数基础知识,掌握这些其实完全就可以进行项目的开发。

今天的补充的内容属于进阶知识,包含:内存地址相关、面试题相关等,在特定情况下也可以让代码更加简洁,提升开发效率。

1.1 参数内存地址相关【面试题】

在开始开始讲参数内存地址相关之前,我们先来学习一个技能:

如果想要查看下某个值的在内存中的地址?

1
2
3
4
v1 = "武沛齐"
addr = id(v1)

print(addr) # 140691049514160
1
2
3
4
5
v1 = [11,22,33]
v2 = [11,22,33]

print( id(v1) ) #different
print( id(v2) )
1
2
3
4
5
v1 = [11,22,33]
v2 = v1

print( id(v1) )
print( id(v2) )

记住一句话:函数执行传参时,传递的是内存地址。

image-20201223234934053

1
2
3
4
5
6
7
8
9
def func(data):
print(data, id(data)) # 武沛齐 140247057684592


v1 = "武沛齐"
print(id(v1)) # 140247057684 592

func(v1)

面试题:请问Python的参数默认传递的是什么?

Python参数的这一特性有两个好处:

  • 节省内存

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

    1
    2
    3
    4
    5
    6
    7
    8
    # 可变类型 & 修改内部修改
    def func(data):
    data.append(999)

    v1 = [11,22,33]
    func(v1)

    print(v1) # [11,22,33,666]
    1
    2
    3
    4
    5
    6
    7
    8
    # 特殊情况:可变类型 & 重新赋值
    def func(data):
    data = ["武沛齐","alex"]

    v1 = [11,22,33]
    func(v1)

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

    v1 = "武沛齐"
    func(v1)

其他很多编程语言执行函数时,默认传参时会将数据重新拷贝一份,会浪费内存。

提示注意:其他语言也可以通过 ref 等关键字来实现传递内存地址。

当然,如果你不想让外部的变量和函数内部参数的变量一致,也可以选择将外部值拷贝一份,再传给函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
import copy


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


v1 = [11, 22, 33]
new_v1 = copy.deepcopy(v1) # 拷贝一份数据
func(new_v1)

print(v1) # [11,22,33]

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

1
2
3
4
5
6
def func():
data = [11, 22, 33]
return data

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

上述代码的执行过程:

  • 执行func函数
  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址。
  • return data 返回data指向的内存地址
  • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)
  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v1指向的函数内部创建的那块内存地址。

1
2
3
4
5
6
7
8
9
def func():
data = [11, 22, 33]
return data

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

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

上述代码的执行过程:

  • 执行func函数
  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址 1000001110。
  • return data 返回data指向的内存地址
  • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)
  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v1指向的函数内部创建的那块内存地址。(v1指向的1000001110内存地址)

  • 执行func函数
  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址 11111001110。
  • return data 返回data指向的内存地址
  • v2接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)
  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v1指向的函数内部创建的那块内存地址。(v1指向的11111001110内存地址)

1
2
3
4
5
6
7
8
9
10
11
def func():
data = [11, 22, 33]
print(id(data))
return data


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

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

1.3 参数的默认值【面试题】

这个知识点在面试题中出现的概率比较高,但真正实际开发中用的比较少。

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

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

  • 执行函数未传值时,则让a2指向 函数维护的那个值的地址。

    1
    func("root")
  • 执行函数传值时,则让a2指向新传入的值的地址。

    1
    func("admin",20)

在特定情况【默认参数的值是可变类型 list/dict/set】 & 【函数内部会修改这个值】下,参数的默认值 有坑 。

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 在函数内存中会维护一块区域存储 [1,2,666,666,666] 100010001
    def func(a1,a2=[1,2]):
    a2.append(666)
    print(a1,a2)

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

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

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

    # a1=300
    # a2 -> 100010001
    func(300) # 300 [1,2,666,666,666]
  • 大坑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # 在内部会维护一块区域存储 [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)
    print(v1) # [1, 2, 10]

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

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

    # a1=40
    # a2 -> 1010101010
    # v4 -> 1010101010
    v4 = func(40)
    print(v4) # [1, 2, 10, 20,40 ]
  • 深坑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    # 内存中创建空间存储 [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 动态参数

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

1
2
3
4
def func(*args,**kwargs):
print(args,kwargs)

func("宝强","杰伦",n1="alex",n2="eric")

在定义函数时可以用 *和**,其实在执行函数时,也可以用。

  • 形参固定,实参用*和**

    1
    2
    3
    4
    5
    6
    7
    8
    def func(a1,a2):
    print(a1,a2)

    func( 11, 22 )
    func( a1=1, a2=2 )

    func( *[11,22] )
    func( **{"a1":11,"a2":22} )
  • 形参用*和**,实参也用 *和**

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def func(*args,**kwargs):
    print(args,kwargs)

    func( 11, 22 )
    func( 11, 22, name="武沛齐", age=18 )

    # 小坑,([11,22,33], {"k1":1,"k2":2}), {}
    func( [11,22,33], {"k1":1,"k2":2} )

    # args=(11,22,33),kwargs={"k1":1,"k2":2}
    func( *[11,22,33], **{"k1":1,"k2":2} )

    # 值得注意:按照这个方式将数据传递给args和kwargs时,数据是会重新拷贝一份的(可理解为内部循环每个元素并设置到args和kwargs中)。

所以,在使用format字符串格式化时,可以可以这样:

1
2
3
4
5
6
v1 = "我是{},年龄:{}。".format("武沛齐",18)
v2 = "我是{name},年龄:{age}。".format(name="武沛齐",age=18)


v3 = "我是{},年龄:{}。".format(*["武沛齐",18])
v4 = "我是{name},年龄:{age}。".format(**{"name":"武沛齐","age":18})

练习题

  1. 看代码写结果

    1
    2
    3
    4
    5
    6
    def func(*args,**kwargs):
    print(args,kwargs)

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

    1
    2
    3
    模仿,https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog&ratio=720p&line=0
    卡特,https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g&ratio=720p&line=0
    罗斯,https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg&ratio=720p&line=0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 下载视频示例
    import requests

    res = requests.get(
    url="https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg&ratio=720p&line=0",
    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('rose.mp4', mode='wb') as f:
    f.write(res.content)

2. 函数和函数名

函数名其实就是一个变量,这个变量只不过代指的函数而已。

1
name = "武沛齐"
1
2
def add(n1,n2):
return n1 + n2

注意:函数必须先定义才能被调用执行(解释型语言)。

1
2
3
4
5
6
# 正确
def add(n1,n2):
return n1 + n2

ret = add(1,2)
print(ret)
1
2
3
4
5
6
# 错误
ret = add(1,2)
print(ret)

def add(n1,n2):
return n1 + n2

2.1 函数做元素

既然函数就相当于是一个变量,那么在列表等元素中是否可以把行数当做元素呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def func():
return 123

data_list = ["武沛齐", "func", func , func() ]

print( data_list[0] ) # 字符串"武沛齐"
print( data_list[1] ) # 字符串 "func"
print( data_list[2] ) # 函数 func
print( data_list[3] ) # 整数 123

res = data_list[2]()
print( res ) # 执行函数 func,并获取返回值;print再输出返回值。

print( data_list[2]() ) # 123

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

掌握这个知识之后,对后续的项目开发有很大的帮助,例如,在项目中遇到根据选择做不同操作时:

  • 情景1,例如:要开发一个类似于微信的功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    def send_message():
    """发送消息"""
    pass

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

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

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

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

    if choice == "1":
    send_message()
    elif choice == "2":
    send_image()
    elif choice == "3":
    send_emoji()
    elif choice == "4":
    send_file()
    else:
    print("输入错误")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    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,例如:某个特定情况,要实现发送短信、微信、邮件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def send_msg():
    """发送短信"""
    pass

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

    def send_wechat():
    """发送微信"""

    # 执行函数
    send_msg()
    send_email()
    send_wechat()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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': "wupeiqi@live.com", "subject": "报警消息", "content": "硬盘容量不够用了"}},
{"name": send_wechat, "params": {'user_id': 1, 'content': "约吗"}},
]

# {"name": send_msg, "params": {'mobile': "15131255089", "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 函数名赋值

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

    1
    2
    3
    4
    5
    6
    7
    8
    def func(a1,a2):
    print(a1,a2)

    xxxxx = func

    # 此时,xxxxx和func都代指上面的那个函数,所以都可以被执行。
    func(1,1)
    xxxxx(2,2)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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)
  • 对函数名重新赋值,如果将函数名修改为其他值,函数名便不再代指函数,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def func(a1,a2):
    print(a1,a2)

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

    # func重新赋值成一个字符串
    func = "武沛齐"

    print(func)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def func(a1,a2):
    print(a1+a2)

    func(1,2)

    def func():
    print(666)

    func()

    注意:由于函数名被重新定义之后,就会变量新被定义的值,所以大家在自定义函数时,不要与python内置的函数同名,否则会覆盖内置函数的功能,例如:

    1
    id,bin,hex,oct,len...
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # len内置函数用于计算值得长度
    v1 = len("武沛齐")
    print(v1) # 3

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

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

2.3 函数名做参数和返回值

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

  • 参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def plus(num):
    return num + 100

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def plus(num):
    return num + 100

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

    result = handler()
    data = result(20) # 120
    print(data)

3.返回值和print

对于初学者的同学,很多人都对print和返回值分不清楚,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def add(n1,n2):
print(n1 + n2)

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

# 输出
4
None



def plus(a1,a2):
return a1 + a2

v2 = plus(1,2)
print(v2)
# 输出
3

这两个函数是完全不同的

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

在调用并执行函数时,要学会分析函数的执行步骤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def f1():
print(123)


def f2(arg):
ret = arg()
return ret


v1 = f2(f1)
print(v1)

# 输出
123
None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def f1():
print(123)


def f2(arg):
ret = arg()
return f1


v1 = f2(f1)

v2 = v1()
print(v2)

# 输出
123
123
None

4. 作用域

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

4.1 函数为作用域

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

1
2
3
4
5
6
7
8
9
10
11
12
13
def func():
name = "武沛齐"
data_list = [11,22,33,44]
print(name,data_list)
age = 20
print(age)

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

func()
handler()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def func():
name = "武沛齐"
age = 29
print(age)
data_list = [11,22,33,44]
print(name,data_list)

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

print(num)

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

if 1 > 2:
max_num = 10
print(max_num)
print(max_num)


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

handler()
func()

4.2 全局和局部

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

image-20201223022803940

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
goods = [
{"name": "电脑", "price": 1999},
{"name": "鼠标", "price": 10},
{"name": "游艇", "price": 20},
{"name": "美女", "price": 998}
]
for index in range(len(goods)):
item = goods[index]
print(index + 1, item['name'], item['price'])

while True:
num = input("请输入要选择的商品序号(Q/q):") # "1"
if num.upper() == "Q":
break
if not num.isdecimal():
print("用输入的格式错误")
break
num = int(num)
send_email()
if num > 4 or num < 0:
print("范围选择错误")
break
target_index = num - 1
choice_item = goods[target_index]
print(choice_item["name"], choice_item['price'])
send_email()
1
2
3
4
5
6
7
8
9
10
11
12
13
# 全局变量(变量名大写)
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
# 局部变量
url = "http://www.xxx.com"
...

def upload():
file_name = "rose.zip"
...

COUNTRYCITY_LIST是在全局作用域中,全局作用域中创建的变量称之为【全局变量】,可以在全局作用域中被使用,也可以在其局部作用域中被使用。

downloadupload函数内部维护的就是一个局部作用域,在各自函数内部创建变量称之为【局部变量】,且局部变量只能在此作用域中被使用。局部作用域中想使用某个变量时,寻找的顺序为:优先在局部作用域中寻找,如果没有则去上级作用域中寻找

注意:全局变量一般都是大写。

示例1:在局部作用域中读取全局作用域的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)
print(CITY_LIST)
downlowd()
upload()

print(file_name) # 报错
print(url) # 报错

示例2:局部作用域和全局作用域变量同名,这算啥?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

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

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

print(COUNTRY)
print(CITY_LIST)
download()
upload()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

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

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

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

COUNTRY = "中华人民共和共国"
CITY_LIST = [11,22,33]

download()
upload()

# 输出
中国
["北京","上海","深圳"]
http://www.xxx.com
中国
["河北","河南","山西"]
中国
["北京","上海","深圳"]
http://www.xxx.com
中华人民共和共国
["河北","河南","山西"]
中华人民共和共国
[11,22,33]

4.3 global关键字

image-20201223022803940

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

  • 读取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    COUNTRY = "中国"
    CITY_LIST = ["北京","上海","深圳"]

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

    download()
  • 修改内部元素(可变类型)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    COUNTRY = "中国"
    CITY_LIST = ["北京","上海","深圳"]

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

    CITY_LIST.append("广州")
    CITY_LIST[0] = "南京"
    print(CITY_LIST)

    download()
  • 无法对全局变量重新赋值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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关键字实现,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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()

总结

  1. 函数参数传递的是内存地址。

    • 想重新创建一份数据再传递给参数,可以手动拷贝一份。

    • 特殊:参数是动态参数时,通过*或**传参时,会将数据循环添加到参数中(类似于拷贝一份)

      1
      2
      3
      4
      5
      def fun(*args, **kwargs):
      print(args, kwargs)


      fun(*[11, 22, 33], **{"k1": 1, "k2": 2})
  2. 函数的返回值也是内存地址。(函数执行完毕后,其内部的所有变量都会被销毁,引用计数器为0时,数据也销毁)

    1
    2
    3
    4
    5
    def func():
    name = [11,22,33]
    data = name

    func()
    1
    2
    3
    4
    5
    6
    7
    def func():
    name = [11,22,33]
    return name

    data = func()
    while True:
    print(data)
  3. 当函数的参数有默认值 & 默认值是可变类型 & 函数内部会修改内部元素(有坑)

    1
    2
    3
    # 内部会维护一个列表 [],只要b不传值则始终使用都是这个列表。
    def func(a,b=[]):
    b.append(a)
  4. 定义函数写形式参数时可以使用***,执行函数时也可以使用。

  5. 函数名其实也是个变量,他也可以做列表、字典、集合等元素(可哈希)

  6. 函数名可以被重新赋值,也可以做另外一个函数的参数和返回值。

  7. 掌握 print 和 return的区别,学会分析代码的执行流程。

  8. python是以函数为作用域。

  9. 在局部作用域中寻找某数据时,优先用自己的,自己没有就在上级作用域中寻找。

  10. 基于 global关键字可以在局部作用域中实现对全局作用域中的变量(全局变量)重新赋值。

作业

  1. 如何查看一个值得内存地址?

  2. 函数的参数传递的是引用(内存地址)还是值(拷贝一份)?

  3. 看代码写结果

    1
    2
    3
    4
    5
    v1 = {}
    v2 = v1
    v1["k1"] = 123

    print(v1,v2)
  4. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def func(k,v,info={}):
    info[k] = v
    return info

    v1 = func(1,2)
    print(v1)

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

    v3 = func(5,6)
    print(v3)
  5. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def func(k,v,info={}):
    info[k] = v
    return info

    v1 = func(1,2)
    v2 = func(4,5,{})
    v3 = func(5,6)

    print(v1,v2,v3)
  6. 简述第5题、第6题的结果为何结果不同。

  7. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    def func(*args, **kwargs):
    print(args, kwargs)
    return "完毕"


    v1 = func(11, 22, 33)
    print(v1)

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

    v3 = func(*[11, 22, 33])
    print(v3)

    v4 = func(k1=123, k2=456)
    print(v4)

    v5 = func({"k1": 123, "k2": 456})
    print(v5)

    v6 = func(**{"k1": 123, "k2": 456})
    print(v6)

    v7 = func([11, 22, 33], **{"k1": 123, "k2": 456})
    print(v7)

    v8 = func(*[11, 22, 33], **{"k1": 123, "k2": 456})
    print(v8)
  8. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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)

    v2 = func(*["北京","上海"],**{"city":"深圳","count":99})
    print(v2)
  9. 补充代码,实现获取天气信息并按照指定格式写入到文件中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # 获取天气信息示例
    import requests
    res = requests.get(url="http://www.weather.com.cn/data/ks/101010100.html")
    res.encoding = "utf-8"
    weather_dict = res.json()

    # 获取的天气信息是个字典类型,内容如下:
    print(weather_dict)

    """
    {
    'weatherinfo': {
    'city': '北京',
    'cityid': '101010100',
    'temp': '18',
    'WD': '东南风',
    'WS': '1级',
    'SD': '17%',
    'WSE': '1',
    'time': '17:05',
    'isRadar': '1',
    'Radar': 'JC_RADAR_AZ9010_JB',
    'njd': '暂无实况',
    'qy': '1011',
    'rain': '0'
    }
    }
    """
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import requests


    def write_file(**kwargs):
    """将天气信息拼接起来,并写入到文件
    格式要求:
    1. 每个城市的天气占一行
    2. 每行的格式为:city-北京,cityid-101010100,temp-18...
    """
    # 补充代码


    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': "北京"},
    ]

    # 补充代码
  10. 看代码写结果

    1
    2
    3
    4
    5
    6
    def func():
    return 1,2,3

    val = func()
    print( type(val) == tuple )
    print( type(val) == list )
  11. 看代码写结果

    1
    2
    3
    4
    5
    6
    def func(users,name):
    users.append(name)
    print(users)

    result = func(['武沛齐','李杰'],'alex')
    print(result)
  12. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def func(v1):
    return v1 * 2

    def bar(arg):
    return "%s 是什么玩意?" %(arg,)

    val = func('你')
    data = bar(val)
    print(data)
  13. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def func(v1):
    return v1* 2

    def bar(arg):
    msg = "%s 是什么玩意?" %(arg,)
    print(msg)

    val = func('你')
    data = bar(val)
    print(data)
  14. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    def func():
    data = 2 * 2
    return data

    data_list = [func,func,func]
    for item in data_list:
    v = item()
    print(v)
  15. 分析代码,写结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    def func(handler,**kwargs):
    extra = {
    "code":123,
    "name":"武沛齐"
    }
    kwargs.update(extra)
    return handler(**kwargs)


    def something(**kwargs):
    return len(kwargs)

    def killer(**kwargs):
    key_list = []
    for key in kwargs.keys():
    key_list.append(key)
    return key_list


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

    v2 = func(killer,**{"name":"武沛齐","age":18})
    print(v2)
  16. 两个结果输出的分别是什么?并简述其原因。

    1
    2
    3
    4
    5
    6
    7
    8
    def func():
    return 123

    v1 = [func,func,func,func,]
    print(v1)

    v2 = [func(),func(),func(),func()]
    print(v2)
  17. 看代码结果

    1
    2
    3
    4
    5
    6
    7
    v1 = '武沛齐'

    def func():
    print(v1)

    func()
    func()
  18. 看代码结果

    1
    2
    3
    4
    5
    6
    7
    8
    v1 = '武沛齐'

    def func():
    print(v1)

    func()
    v1 = '老男人'
    func()
  19. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    NUM_LIST = []
    SIZE = 18
    def f1():
    NUM_LIST.append(8)
    SIZE = 19

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

    f2()
    f1()
    f2()
  20. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    NUM_LIST = []
    SIZE = 18
    def f1():
    global NUM_LIST
    global SIZE
    NUM_LIST.append(8)
    SIZE = 19

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

    f2()
    f1()
    f2()
  21. 根据要求实现资源下载器。

    • 启动后,让用户选择专区,每个专区用单独的函数实现,提供的专区如下:

      • 下载 花瓣网图片专区
      • 下载 抖音短视频专区
      • 下载 NBA锦集 专区
    • 在用户选择了某个功能之后,表示进入某下载专区,在里面循环提示用户可以下载的内容选项(已下载过的则不再提示下载)
      提醒:可基于全部变量保存已下载过得资源。

    • 在某个专区中,如果用户输入(Q/q)表示 退出上一级,即:选择专区。

    • 在选择专区如果输入Q/q则退出整个程序。

    • 每个专区实现下载的案例如下:

      • 图片

        1
        2
        3
        4
        5
        6
        7
        # 可供用户下载的图片如下
        image_dict = {
        "1":("吉他男神","https://hbimg.huabanimg.com/51d46dc32abe7ac7f83b94c67bb88cacc46869954f478-aP4Q3V"),
        "2":("漫画美女","https://hbimg.huabanimg.com/703fdb063bdc37b11033ef794f9b3a7adfa01fd21a6d1-wTFbnO"),
        "3":("游戏地图","https://hbimg.huabanimg.com/b438d8c61ed2abf50ca94e00f257ca7a223e3b364b471-xrzoQd"),
        "4":("alex媳妇","https://hbimg.huabanimg.com/4edba1ed6a71797f52355aa1de5af961b85bf824cb71-px1nZz"),
        }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        # 下载图片示例
        import request

        res = requests.get(
        url="https://hbimg.huabanimg.com/4edba1ed6a71797f52355aa1de5af961b85bf824cb71-px1nZz",
        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"
        }
        )

        with open("alex媳妇.png",mode="wb") as f:
        f.write(res.content)
      • 短视频

        1
        2
        3
        4
        5
        6
        # 可供用户下载的短视频如下
        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"},
        }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        # 下载视频示例
        import requests

        res = requests.get(
        url="https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg",
        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('罗斯mvp.mp4', mode='wb') as f:
        f.write(res.content)
      • NBA

        1
        2
        3
        4
        5
        # 可供用户下载的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"}
        }
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        # 下载示例
        import requests

        res = requests.get(
        url="https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0d00fb60000bvi0ba63vni5gqts0uag&ratio=720p&line=0",
        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', mode='wb') as f:
        f.write(res.content)

day10 函数入门

image-20201220155910093

目标:掌握函数的编写方式以及函数的基本使用。

今日概要:

  • 初识函数
  • 函数的参数
  • 函数的返回值

提示:由于昨天的内容比较多,为了减轻大家的学习压力,今天设计的课程内容会比较少。

1. 初识函数

函数到底是个什么东西?

函数,可以当做是一大堆功能代码的集合。

1
2
3
4
5
6
def 函数名():
函数内编写代码
...
...

函数名()

例如:

1
2
3
4
5
6
7
# 定义名字叫info的函数
def info():
print("第一行")
print("第二行")
print("第n行...")

info()

什么时候会用到函数?

什么时候会用到函数呢?一般在项目开发中有会有两种应用场景:

  • 有重复代码,用函数增加代码的重用性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def send_email():
    # 10行代码

    print("欢迎使用计算机监控系统")
    if CPU占用率 > 90%:
    send_email()

    if 硬盘使用率 > 99%:
    send_email()

    if 内存使用率 > 98%:
    send_email()
    ...
  • 代码太长,用函数增强代码的可读性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    def calculate_same_num_rule():
    """判断是否是豹子"""
    pass

    def calculate_same_color_rule():
    """判断是否是同花"""
    pass

    def calculate_straight_rule():
    """判断是否顺子"""
    pass

    def calculate_double_card_rule(poke_list):
    """判断是否对子"""
    pass

    def calculate_single_card_rule():
    """判断是否单牌"""
    pass



    # 1. 生成一副扑克牌
    card_color_list = ["红桃", "黑桃", "方片", "梅花"]
    card_nums = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] # A
    all_card_list = [[color, num] for color in card_color_list for num in card_nums]

    # 2.洗牌
    random.shuffle(all_card_list)

    # 3.给玩家发牌
    ...
    # 4.判断牌是:豹子?同花顺?顺子?对子?单点?

    calculate_same_num_rule()
    calculate_same_color_rule()
    calculate_straight_rule()
    ...

以前我们变成是按照业务逻辑从上到下逐步完成,称为:面向过程编程;现在学了函数之后,利用函数编程称为:函数式编程。

2. 函数的参数

之前说了很好多次发送邮件的案例,下面就来教大家用python发邮件,然后再由此引出函数的参数。

  • 注册邮箱
  • 基础配置
    • 授权码
    • SMTP服务器: smtp.126.com
  • 代码发送邮件

image-20201220180545406

image-20201220180613478

以下是我为大家提供的发邮件的一个函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

# ### 1.邮件内容配置 ###
msg = MIMEText("约吗", 'html', 'utf-8')
msg['From'] = formataddr(["武沛齐", "yangliangran@126.com"])
msg['Subject'] = "180一晚"

# ### 2.发送邮件 ###
server = smtplib.SMTP_SSL("smtp.126.com")
server.login("yangliangran@126.com", "LAYEVIAPWQAVVDEP")
server.sendmail("yangliangran@126.com", "424662508@qq.com", msg.as_string())
server.quit()

那么需求来了,请求大家提一个需求:根据上述代码实现给3个用户发邮件。

1
2
3
4
5
v1 = "424662508@qq.com"
v2 = "424662509@qq.com"
v3 = "wupeiqi@live.com"


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

def send_email(xx):
# ### 1.邮件内容配置 ###
msg = MIMEText("约吗", 'html', 'utf-8')
msg['From'] = formataddr(["武沛齐", "yangliangran@126.com"])
msg['Subject'] = "180一晚"

# ### 2.发送邮件 ###
server = smtplib.SMTP_SSL("smtp.126.com")
server.login("yangliangran@126.com", "LAYEVIAPWQAVVDEP")
server.sendmail("yangliangran@126.com", xx, msg.as_string())
server.quit()

send_email("424662508@qq.com")
send_email("424662509@qq.com")
send_email("wupeiqi@live.com")
  • 思路1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    def send_email1():
    # ### 1.邮件内容配置 ###
    # 邮件文本
    msg = MIMEText("约吗", 'html', 'utf-8')
    # 邮件上显示的发件人
    msg['From'] = formataddr(["武沛齐", "wptawy@126.com"])
    # 邮件上显示的主题
    msg['Subject'] = "邮件主题"

    # ### 2.发送邮件 ###
    server = smtplib.SMTP_SSL("smtp.126.com")
    server.login("wptawy@126.com", "WIYSAILOVUKPQGHY")
    server.sendmail("wptawy@126.com", "424662508@qq.com", msg.as_string())
    server.quit()

    def send_email2():
    # ### 1.邮件内容配置 ###
    # 邮件文本
    msg = MIMEText("约吗", 'html', 'utf-8')
    # 邮件上显示的发件人
    msg['From'] = formataddr(["武沛齐", "wptawy@126.com"])
    # 邮件上显示的主题
    msg['Subject'] = "邮件主题"

    # ### 2.发送邮件 ###
    server = smtplib.SMTP_SSL("smtp.126.com")
    server.login("wptawy@126.com", "WIYSAILOVUKPQGHY")
    server.sendmail("wptawy@126.com", "424662509@qq.com", msg.as_string())
    server.quit()

    def send_email3():
    # ### 1.邮件内容配置 ###
    # 邮件文本
    msg = MIMEText("约吗", 'html', 'utf-8')
    # 邮件上显示的发件人
    msg['From'] = formataddr(["武沛齐", "wptawy@126.com"])
    # 邮件上显示的主题
    msg['Subject'] = "邮件主题"

    # ### 2.发送邮件 ###
    server = smtplib.SMTP_SSL("smtp.126.com")
    server.login("wptawy@126.com", "WIYSAILOVUKPQGHY")
    server.sendmail("wptawy@126.com", "wupeiqi@live.com", msg.as_string())
    server.quit()


    send_email1()
    send_email2()
    send_email3()
  • 思路2,基于函数的参数(将代码中动态部分提取到参数位置,让函数可以充分被重用)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    def send_email(email):
    # ### 1.邮件内容配置 ###
    # 邮件文本
    msg = MIMEText("约吗", 'html', 'utf-8')
    # 邮件上显示的发件人
    msg['From'] = formataddr(["武沛齐", "wptawy@126.com"])
    # 邮件上显示的主题
    msg['Subject'] = "邮件主题"

    # ### 2.发送邮件 ###
    server = smtplib.SMTP_SSL("smtp.126.com")
    server.login("wptawy@126.com", "WIYSAILOVUKPQGHY")
    server.sendmail("wptawy@126.com", email, msg.as_string())
    server.quit()


    v1 = "424662508@qq.com"
    send_email(v1)

    v2 = "424662509@qq.com"
    send_email(v2)

    v3 = "wupeiqi@live.com"
    send_email(v3)

2.1 参数

在定义函数时,如果在括号中添加变量,我们称它为函数的形式参数:

1
2
3
4
5
6
7
8
9
# ###### 定义有三个参数的函数(a1/a2/a3一般称为形式参数-形参) #####
def func(a1,a2,a3):
print(a1+a2+a3)

# 执行函数并传入参数(执行函数传值时一般称为实际参数-实参)
func(11,22,33)

# 执行函数并传入参数
func(9,2,103)
  • 位置传参

    1
    2
    3
    4
    def add(n1,n2):
    print(n1+n2)

    add(1,22)
  • 关键字传参

    1
    2
    3
    4
    def add(n1,n2):
    print(n1+n2)

    add(n1=1,n2=22)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"""
1. 形参
2. 实参
3. 位置传参
4. 关键字传参
"""


# ###### 定义有三个参数的函数(a1/a2/a3一般称为形式参数-形参) #####
def func(a1, a2, a3):
print(a1 + a2 + a3)


# 执行函数并传入参数(执行函数传值时一般称为实际参数-实参)
func(11, 22, 33)

# 执行函数并传入参数
func(9, 2, 103)

# 执行函数
func(a1=99, a2=88, a3=1)
func(a1=99, a3=1, a2=88)

2.2 默认参数

1
2
3
4
5
6
7
8
9
10
11
12
def func(a1, a2, a3=10):
print(a1 + a2 + a3)


# 位置传参
func(8, 19)
func(1, 2, 99)

# 关键字传参(位置和关键混合时,关键字传参要在后面)
func(12, 9, a3=90)
func(12, a2=9, a3=90)
func(a1=12, a2=9, a3=90)
1
file_object = open("xxx.txt")

2.3 动态参数

    1
    2
    3
    4
    5
    6
    7
    8
    def func(*args):
    print(args) # 元组类型 (22,) (22,33,99,) ()

    # 只能按照位置传参
    func(22)
    func(22,33)
    func(22,33,99)
    func()
  • **

    1
    2
    3
    4
    5
    6
    7
    def func(**kwargs):
    print(kwargs) # 字典类型 {"n1":"武沛齐"} {"n1":"武沛齐","age":"18","email":"xxxx"} {}

    # 只能按关键字传参
    func(n1="武沛齐")
    func(n1="武沛齐",age=18)
    func(n1="武沛齐",age=18,email="xx@live.com")
  • ,*

    1
    2
    3
    4
    5
    6
    7
    def func(*args,**kwargs):
    print(args,kwargs) # (22,33,99) {}

    func(22,33,99)
    func(n1="武沛齐",age=18)
    func(22,33,99,n1="武沛齐",age=18)
    func()

    提示:是否还记得字符串格式化时的format功能。

    1
    2
    3
    v1 = "我叫{},今年{},性别{}".format("武沛齐",18,"男")

    v2 = "我叫{name},今年{age},性别{gender}".format(name="武沛齐",age=18,gender="男")

注意事项(不重要,听过一遍即可)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. ** 必须放在 * 的后面
def func1(*args, **kwargs):
print(args, **kwargs)


# 2. 参数和动态参数混合时,动态参数只能放在最后。
def func2(a1, a2, a3, *args, **kwargs):
print(a1, a2, a3, args, **kwargs)


# 3. 默认值参数和动态参数同时存在
def func3(a1, a2, a3, a4=10, *args, a5=20, **kwargs):
print(a1, a2, a3, a4, a5, args, kwargs)


func3(11, 22, 33, 44, 55, 66, 77, a5=10, a10=123)

3. 函数返回值

在开发过程中,我们希望函数可以帮助我们实现某个功能,但让函数实现某功能之后有时也需要有一些结果需要反馈给我们,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
from xml.etree import ElementTree as ET


def xml_to_list(city):
data_list = []
url = "http://ws.webxml.com.cn//WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName={}".format(city)
res = requests.get(url=url)
root = ET.XML(res.text)
for node in root:
data_list.append(node.text)
return data_list


result = xml_to_list("北京")
print(result)
1
2
3
4
5
def func():
return 666

res = func()
print(res) # 666
1
2
3
4
5
6
def magic(num):
result = num + 1000
return result

data = magic(9)
print(data) # 1009

在了解了返回值的基本使用之后,接下来在学3个关键知识:

  • 返回值可以是任意类型,如果函数中没写return,则默认返回None

    1
    2
    3
    4
    5
    def func():
    return [1,True,(11,22,33)]

    result = func()
    print(result)
    1
    2
    3
    4
    5
    def func():
    value = 1 + 1

    ret = func()
    print(ret) # None

    当在函数中未写返回值returnreturn None ,执行函数获取的返回值都是None。

    1
    2
    3
    4
    5
    6
    def func():
    value = 1 + 1
    return # 或 return None

    ret = func()
    print(ret) # None
  • return后面的值如果有逗号,则默认会将返回值转换成元组再返回。

    1
    2
    3
    4
    5
    def func():
    return 1,2,3

    value = func()
    print(value) # (1,2,3)
  • 函数一旦遇到return就会立即退出函数(终止函数中的所有代码)

    1
    2
    3
    4
    5
    6
    7
    def func():
    print(1)
    return "结束吧"
    print(2)

    ret = func()
    print(ret)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def func():
    print(1)
    for i in range(10):
    print(i)
    return 999
    print(2)

    result = func()
    print(result)

    # 输出
    1
    0
    999
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def func():
    print(1)
    for i in range(10):
    print(i)
    for j in range(100):
    print(j)
    return
    print(2)

    result = func()
    print(result)

    # 输出
    1
    0
    0
    None

小结:

  • 完成某个结果并希望的到结果。

    1
    2
    3
    4
    5
    def send_email():
    ...
    return True

    v1 = send_email()
    1
    2
    3
    4
    5
    6
    def encrypt(old):
    ...
    return "密文..."

    data = encrypt("武沛齐")
    print(data)
  • 基于return控制让函数终止执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def func(name):
    with open("xxx.txt",mode='r',encoding="utf-8") as file_object:
    for line in file_object:
    if name in line:
    return True

    data = func("武沛齐")
    if data:
    print("存在")
    else:
    print("不存在")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def foo():
    while True:
    num = input("请输入数字(Q):")
    if num.upper() == "Q":
    return
    num = int(num)
    if num == 99:
    print("猜对了")
    else:
    print("猜错了,请继续!")
    print("....")

    foo()

总结

  1. 如何定义一个函数?

  2. 函数名的规范。(同变量名规范)

    • 规范

    • 建议

      1
      2
      def change_num():
      pass
  3. 函数的注释,说明函数的作用。

    1
    2
    3
    def encrypt(origin):
    """ 用于数据加密和xxx """
    pass
  4. 定义函数时,参数一般有以下情况(形式参数)

    • 情景1

      1
      2
      def func(a1,a2):
      pass
    • 情景2:

      1
      2
      def func(a1,a2=123):
      pass
    • 情景2:

      1
      2
      def func(*args,**kwargs):
      pass
  5. 函数的返回值,一般用于将函数执行的返回给调用者。

    • 默认返回None
    • 遇到return则函数执行完毕

作业

  1. 请定义一个函数,用于计算一个字符串中字符a出现的次数并通过return返回。

    • 参数,字符串。
    • 返回值,字符串中 a 出现的次数。
  2. 写函数,判断用户传入的一个值(字符串或列表或元组任意)长度是否大于5,并返回真假。

  3. 写函数,接收两个数字参数,返回比较大的那个数字(等于时返回两个中的任意一个都可以)。

  4. 写函数,函数接收四个参数分别是:姓名,性别,年龄,学历,然后将这四个值通过”*”拼接起来并追加到一个student_msg.txt文件中。

  5. 补充代码,实现如下功能:

    • 【位置1】读取文件中的每一行数据,将包含特定关键的数据筛选出来,并以列表的形式返回。
    • 【位置1】文件不存在,则返回None
    • 【位置2】文件不存在,输出 “文件不存在”,否则循环输出匹配成功的每一行数据。
    1
    2
    3
    4
    5
    def select_content(file_path,key):
    # 补充代码【位置1】

    result = select_content("files/xxx.txt","股票")
    # 补充代码【位置2】
  6. 补充代码,实现敏感词替换的功能。

    1
    2
    3
    4
    5
    6
    7
    def change_string(origin):
    # 补充代码,将字符串origin中中的敏感词替换为 **,最后将替换好的值返回。
    data_list = ["苍老师","波多老师","大桥"]

    text = input("请输入内容:")
    result = change_string(text)
    print(result)
  7. 基于函数实现用户认证,要求:

    • 写函数,读取的用户信息并构造为字典(用户信息存放在files/user.xlsx文件中)

      image-20201220144654241
      1
      2
      3
      4
      5
      # 构造的字典格式如下
      user_dict = {
      "用户名":"密码"
      ...
      }
    • 用户输入用户名和密码,进行校验。(且密码都是密文,所以,需要将用户输入的密码进行加密,然后再与Excel中的密文密码进行比较)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      import hashlib

      def encrypt(origin):
      origin_bytes = origin.encode('utf-8')
      md5_object = hashlib.md5()
      md5_object.update(origin_bytes)
      return md5_object.hexdigest()


      p1 = encrypt('admin')
      print(p1) # "21232f297a57a5a743894a0e4a801fc3"

      p2 = encrypt('123123')
      print(p2) # "4297f44b13955235245b2497399d7a93"

      p3 = encrypt('123456')
      print(p3) # "e10adc3949ba59abbe56e057f20f883e"

扩展:密码都不是明文。

  • 注册京东,京东存储:用户名和密码(密文)
  • 登录京东:用户名& 密码。

day08 总结和考试

课程目标:对第一模块 “Python基础” 阶段的知识点进行总结和考试,让学员更好的掌握此模块的相关知识。

课程概要:

  • 代码规范
  • 知识补充
  • 阶段总结(思维导图)
  • 考试题

1. 代码规范

程序员写代码是有规范的,不只是实现功能而已。

1.1 名称

在Python开发过程中会创建文件夹/文件/变量等,这些在命名有一些潜规则(编写代码时也要注意pep8规范)。

  • 文件夹,小写 & 小写下划线连接,例如:commandsdata_utils等。

  • 文件,小写 & 小写下划线连接,例如:page.pydb_convert.py等。

  • 变量

    • 全局变量,大写 & 大写下划线连接,例如:NAME = "武沛齐"BASE_NAME = 18
    • 局部变量,小写 & 小写下划线连接,例如:data = [11,22,33]user_parent_id = 9等。

1.2 注释

作为程序员,写代码注释是非常基础且有用的技能,方便以后对代码进行维护和理解。

  • 文件夹
    image-20201122135126441

  • 文件注释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    """
    这个文件主要为项目提供工具和转换的功能,初次之外还有日志....
    例如:
    ...
    ...
    ...
    """


    ....
  • 代码注释

    1
    2
    3
    4
    name = "alex"
    # 在名称后面添加一个大烧饼
    data = name + "dsb"
    print(data)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    name = "alex"
    """
    在名称后面添加一个大烧饼,内部的实现机制:
    1. xxx
    2. xxx
    3. xx
    """
    data = name + "dsb"
    print(data)

1.3 todo

基于注释可以实现todo注释的效果,例如:

image-20201122112314543

1.4 条件嵌套

以后写条件语句一定要想办法减少嵌套的层级(最好不要超过3层)。

image-20201122112505721

1.5 简单逻辑先处理

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
goods = [
{"name": "电脑", "price": 1999},
{"name": "鼠标", "price": 10},
{"name": "游艇", "price": 20},
{"name": "美女", "price": 998}
]
for index in range(len(goods)):
item = goods[index]
print(index + 1, item['name'], item['price'])

while True:
num = input("请输入要选择的商品序号(Q/q):") # "1"
if num.upper() == "Q":
break
if num.isdecimal():
num = int(num)
if 0 < num < 5:
target_index = num - 1
choice_item = goods[target_index]
print(choice_item["name"], choice_item['price'])
else:
print("序号范围选择错误")
else:
print("用户输入的序号格式错误")

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
goods = [
{"name": "电脑", "price": 1999},
{"name": "鼠标", "price": 10},
{"name": "游艇", "price": 20},
{"name": "美女", "price": 998}
]
for index in range(len(goods)):
item = goods[index]
print(index + 1, item['name'], item['price'])

while True:
num = input("请输入要选择的商品序号(Q/q):") # "1"
if num.upper() == "Q":
break
if not num.isdecimal():
print("用输入的格式错误")
break
num = int(num)

if num > 4 or num < 0:
print("范围选择错误")
break
target_index = num - 1
choice_item = goods[target_index]
print(choice_item["name"], choice_item['price'])

1.6 循环

尽量少循环多干事,提高代码效率。

1
2
3
4
5
6
7
8
key_list = []
value_list = []

info = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

for key, value in info.items():
key_list.append(key)
value_list.append(value)
1
2
3
4
5
info = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

key_list = list(info.keys())
value_list = list(info.values())

1.7 变量和值

1
2
3
# 推荐
name = "武沛齐"
age = 19
1
2
3
# 不推荐
name="武沛齐"
age= 18

可以基于Pycharm的格式化工具来实现自动处理。

python代码规范:PEP8规范。

2.知识补充

2.1 pass

一般Python的代码块是基于 :缩进来实现,Python中规定代码块中必须要有代码才算完整,在没有代码的情况下为了保证语法的完整性可以用pass代替,例如:

1
2
3
4
5
6
# 其他编程语言
if 提交{
...
}else{
....
}
1
2
3
4
if 条件 :
pass
else:
pass
1
2
3
4
if 条件:
pass
else:
pass
1
2
for i in range(xxx):
pass

2.2 is 比较

is==的区别是什么?

  • ==,用于比较两个值是否相等。
  • is,用于表示内存地址是否一致。
1
2
3
4
5
6
# 示例1
v1 = []
v2 = []

print( v1 == v2 ) # True,两个值相当
print( v1 is v2 ) # False,不属于同一块内存。
1
2
3
4
5
6
# 示例2
v1 = []
v2 = v1

print( v1 == v2 ) # True,两个值相当
print( v1 is v2 ) # True,属于同一块内存。
1
2
3
4
5
6
# 示例3
v1 = None
v2 = None

print(v1 == v2) # True,两个值相当
print(v1 is v2) # True,属于同一块内存。

2.3 位运算

计算机底层本质上都是二进制,我们平时在计算机中做的很多操作底层都会转换为二进制的操作,位运算就是对二进制的操作。

  • &,与(都为1)

    1
    2
    3
    4
    a = 60            # 60 = 0011 1100 
    b = 13 # 13 = 0000 1101

    c = a & b # 12 = 0000 1100
  • |,或(只要有一个为1)

    1
    2
    3
    4
    a = 60            # 60 = 0011 1100 
    b = 13 # 13 = 0000 1101

    c = a | b # 61 = 0011 1101
  • ^,异或(值不同)

    1
    2
    3
    4
    a = 60            # 60 = 0011 1100 
    b = 13 # 13 = 0000 1101

    c = a ^ b # 49 = 0011 0001
  • ~,取反

    1
    2
    3
    a = 60            #  60 = 0011 1100 

    c = ~a; # -61 = 1100 0011
  • <<,左移动

    1
    2
    a = 60            #  60 = 0011 1100
    c = a << 2; # 240 = 1111 0000
  • >>,右移动

    1
    2
    a = 60            # 60 = 0011 1101 
    c = a >> 2; # 15 = 0000 1111

平时在开发中,二进制的位运算几乎很好少使用,在计算机底层 或 网络协议底层用的会比较多,例如:

  • 计算 2**n

    1
    2
    3
    4
    5
    2**0    1 << 0   1     1
    2**1 1 << 1 10 2
    2**2 1 << 2 100 4
    2**3 1 << 3 1000 8
    ...
  • 计算一个数的一半【面试题】

    1
    2
    3
    4
    5
    v1 = 10 >> 1 
    print(v1) # 值为5

    v2 = 20 >> 1
    print(v2) # 值为 10
  • 网络传输数据,文件太大还未传完(websocket源码为例)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1个字节         第2个字节         ... 
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-------+-+-------------+-------------------------------+
    |F|R|R|R| opcode|M| Payload len | Extended payload length |
    |I|S|S|S| (4) |A| (7) | (16/64) |
    |N|V|V|V| |S| | (if payload len==126/127) |
    | |1|2|3| |K| | |
    +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +

    FIN位置是0,表示这是一部分数据,后续还有数据。
    FIN位置是1,表示这是最后数据,已发送完毕。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 例如:接收到的第一个字节的值为245(11110101),让v的二进制和 1000 0000 做 & 与运算。

    v = 245 # 245 11110101
    # 128 10000000
    10000000

    data = v & 128
    if data == 0:
    print("还有数据")
    else:
    print("已完毕")

3.阶段总结

可使用思维导图( xmind 软件),对阶段知识点的内容进行梳理,将知识梗概和重点写出来,也便于以后的回顾和复习。

image-20201122122813525

4.考试题

考试题的目的是让大家对自己近期知识点学习练习 以及 自测,请大家务必【独立】完成(切勿翻看笔记 & 切勿网上搜索 )。

  • 第一步:自己独立完成(闭卷)

  • 第二步:做完之后,翻看自己笔记去修改和更正。

  • 第三步:觉自己做的没问题了,最后再去看考试题的参考答案和讲解。

详情见附件《第一阶段考试题.md》文件。

day06 数据类型(下)

常见的数据类型:

  • int,整数类型(整形)
  • bool,布尔类型
  • str,字符串类型
  • list,列表类型
  • tuple,元组类型
  • dict,字典类型
  • set,集合类型
  • float,浮点类型(浮点型)

目标:掌握字典、集合、浮点类型相关知识。

课程概要:

  • set集合,一个不允许重复重复 & 可变类型(元素可哈希)。
  • dict字典,一个容器且元素必须是键值对。
  • float类型,我们生活中常见的小数。

1.集合(set)

集合是一个 无序 、可变、不允许数据重复的容器。

1.1 定义

1
v1 = { 11, 22, 33, "alex" }
  • 无序,无法通过索引取值。

  • 可变,可以添加和删除元素。

    1
    2
    3
    v1 = {11,22,33,44}
    v1.add(55)
    print(v1) # {11,22,33,44,55}
  • 不允许数据重复。

    1
    2
    3
    v1 = {11,22,33,44}
    v1.add(22)
    print(v1) # {11,22,33,44}

一般什么时候用集合呢?

就是想要维护一大堆不重复的数据时,就可以用它。比如:做爬虫去网上找图片的链接,为了避免链接重复,可以选择用集合去存储链接地址。

注意:定义空集合时,只能使用v = set(),不能使用 v={}(这样是定义一个空字典)。

1
2
3
4
5
6
7
8
9
10
v1 = []
v11 = list()

v2 = ()
v22 = tuple()

v3 = set()

v4 = {} # 空字典
v44 = dict()

1.2 独有功能

  1. 添加元素

    1
    2
    3
    data = {"刘嘉玲", '关之琳', "王祖贤"}
    data.add("郑裕玲")
    print(data)
    1
    2
    3
    4
    data = set()
    data.add("周杰伦")
    data.add("林俊杰")
    print(data)
  2. 删除元素

    1
    2
    3
    data = {"刘嘉玲", '关之琳', "王祖贤","张曼⽟", "李若彤"}
    data.discard("关之琳")
    print(data)
  3. 交集

    1
    2
    3
    4
    5
    6
    7
    8
    s1 = {"刘能", "赵四", "⽪⻓⼭"}
    s2 = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}

    s4 = s1.intersection(s2) # 取两个集合的交集
    print(s4) # {"⽪⻓⼭"}

    s3 = s1 & s2 # 取两个集合的交集
    print(s3)
  4. 并集

    1
    2
    3
    4
    5
    6
    s1 = {"刘能", "赵四", "⽪⻓⼭"}
    s2 = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}
    s4 = s1.union(s2) # 取两个集合的并集 {"刘能", "赵四", "⽪⻓⼭","刘科⻓", "冯乡⻓", }
    print(s4)
    s3 = s1 | s2 # 取两个集合的并集
    print(s3)
  5. 差集

    1
    2
    3
    4
    5
    6
    7
    8
    9
    s1 = {"刘能", "赵四", "⽪⻓⼭"}
    s2 = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}
    s4 = s1.difference(s2) # 差集,s1中有且s2中没有的值 {"刘能", "赵四"}
    s6 = s2.difference(s1) # 差集,s2中有且s1中没有的值 {"刘科⻓", "冯乡⻓"}

    s3 = s1 - s2 # 差集,s1中有且s2中没有的值
    s5 = s2 - s1 # 差集,s2中有且s1中没有的值

    print(s5,s6)

1.3 公共功能

  1. 减,计算差集

    1
    2
    3
    4
    5
    6
    7
    s1 = {"刘能", "赵四", "⽪⻓⼭"}
    s2 = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}

    s3 = s1 - s2
    s4 = s2 - s1
    print(s3)
    print(s4)
  2. &,计算交集

    1
    2
    3
    4
    s1 = {"刘能", "赵四", "⽪⻓⼭"}
    s2 = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}
    s3 = s1 & s2
    print(s3)
  3. |,计算并集

    1
    2
    3
    4
    s1 = {"刘能", "赵四", "⽪⻓⼭"}
    s2 = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}
    s3 = s1 | s2
    print(s3)
  4. 长度

    1
    2
    3
    v = {"刘能", "赵四", "尼古拉斯"}
    data = len(v)
    print(data)
  5. for循环

    1
    2
    3
    v = {"刘能", "赵四", "尼古拉斯"}
    for item in v:
    print(item)

1.4 转换

其他类型如果想要转换为集合类型,可以通过set进行转换,并且如果数据有重复自动剔除。

提示:int/list/tuple/dict都可以转换为集合。

1
2
3
v1 = "武沛齐"
v2 = set(v1)
print(v2) # {"武","沛","齐"}
1
2
3
v1 = [11,22,33,11,3,99,22]
v2 = set(v1)
print(v2) # {11,22,33,3,99}
1
2
3
v1 = (11,22,3,11)
v2 = set(v1)
print(v2) # {11,22,3}

提示:这其实也是去重的一个手段。

1
2
3
4
5
data = {11,22,33,3,99}

v1 = list(data) # [11,22,33,3,99]

v2 = tuple(data) # (11,22,33,3,99)

1.5 其他

1.5.1 集合的存储原理

image-20201120193837492

1.5.2 元素必须可哈希

因存储原理,集合的元素必须是可哈希的值,即:内部通过通过哈希函数把值转换成一个数字。

image-20201120190454120

目前可哈希的数据类型:int、bool、str、tuple,而list、set是不可哈希的。

总结:集合的元素只能是 int、bool、str、tuple 。

  • 转换成功

    1
    2
    3
    v1 = [11,22,33,11,3,99,22]
    v2 = set(v1)
    print(v2) # {11,22,33,3,99}
  • 转换失败

    1
    2
    3
    v1 = [11,22,["alex","eric"],33]
    v2 = set(v1) # 报错
    print(v2)

1.5.3 查找速度特别快

因存储原理特殊,集合的查找效率非常高(数据量大了才明显)。

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    user_list = ["武沛齐","alex","李璐"]
    if "alex" in user_list:
    print("在")
    else:
    print("不在")


    user_tuple = ("武沛齐","alex","李璐")
    if "alex" in user_tuple:
    print("在")
    else:
    print("不在")
  • 效率高

    1
    2
    3
    4
    5
    user_set = {"武沛齐","alex","李璐"}
    if "alex" in user_set:
    print("在")
    else:
    print("不在")

1.5.4 对比和嵌套

类型 是否可变 是否有序 元素要求 是否可哈希 转换 定义空
list list(其他) v=[]或v=list()
tuple tuple(其他) v=()或v=tuple()
set 可哈希 set(其他) v=set()
1
2
3
4
5
6
7
data_list = [
"alex",
11,
(11, 22, 33, {"alex", "eric"}, 22),
[11, 22, 33, 22],
{11, 22, (True, ["中国", "北京"], "沙河"), 33}
]

注意:由于True和False本质上存储的是 1 和 0 ,而集合又不允许重复,所以在整数 0、1和False、True出现在集合中会有如下现象:

1
2
3
4
5
6
7
8
9
10
11
v1 = {True, 1}
print(v1) # {True}

v2 = {1, True}
print(v2) # {1}

v3 = {0, False}
print(v3) # {0}

v4 = {False, 0}
print(v4) # {False}

练习题

  1. 写代码实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    v1 = {'alex','武sir','肖大'}
    v2 = []

    # 循环提示用户输入,如果输入值在v1中存在,则追加到v2中,如果v1中不存在,则添加到v1中。(如果输入N或n则停止循环)
    while True:
    name = input("请输入姓名(N/n退出):")
    if name.upper() == "Q":
    break
    if name in v1:
    v2.append(name)
    else:
    v1.add(name)
  2. 下面那些值不能做集合的元素

    1
    2
    3
    4
    5
    6
    ""
    0
    [11,22,33] # 不能
    [] # 不能
    (123)
    {1,2,3} # 不能
  3. 模拟用户信息录入程序,已录入则不再创建。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    user_info_set = set()

    while True:
    name = input("请输入姓名:")
    age = input("请输入年龄:")
    item = (name,age,)
    if item in user_info_set:
    print("该用户已录入")
    else:
    user_info_set.add(item)
  4. 给你个列表去重。

    1
    2
    3
    v = [11,22,11,22,44455]
    data = set(v) # {11,22,44455}
    result = list(data) # [11,22,44455]

强插:None类型

Python的数据类型中有一个特殊的值None,意味着这个值啥都不是 或 表示空。 相当于其他语言中 null作用一样。

在一定程度上可以帮助我们去节省内存。例如:

1
2
3
4
5
v1 = None
v2 = None
..
v1 = [11,22,33,44]
v2 = [111,22,43]
1
2
3
4
5
v3 = []
v4 = []
...
v3 = [11,22,33,44]
v4 = [111,22,43]

注意:暂不要考虑Python内部的缓存和驻留机制。

目前所有转换为布尔值为False的值有:

1
2
3
4
5
6
0
""
[] or list()
() or tuple()
set()
None
1
2
if None:
pass

2.字典(dict)

字典是 无序键不重复 且 元素只能是键值对可变的容器

1
data = { "k1":1,  "k2":2 }
  • 容器

  • 元素必须键值对

  • 键不重复,重复则会被覆盖

    1
    2
    data = { "k1":1, "k1":2 }
    print(data) # {"k1":2}
  • 无序(在Python3.6+字典就是有序了,之前的字典都是无序。)

    1
    2
    data = { "k1":1,  "k2":2 }
    print(data)

2.1 定义

1
2
v1 = {}
v2 = dict()
1
2
3
4
data = { 
"k1":1,
"k2":2
}
1
2
3
4
5
6
info = { 
"age":12,
"status":True,
"name":"wupeiqi",
"hobby":['篮球','足球']
}

字典中对键值得要求:

  • 键:必须可哈希。 目前为止学到的可哈希的类型:int/bool/str/tuple;不可哈希的类型:list/set/dict。(集合)
  • 值:任意类型。
1
2
3
4
5
6
data_dict = {
"武沛齐":29,
True:5,
123:5,
(11,22,33):["alex","eric"]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 不合法
v1 = {
[1, 2, 3]: '周杰伦',
"age" : 18
}
v2 = {
{1,2,3}: "哈哈哈",
'name':"alex"
}

v3 = {
{"k1":123,"k2":456}: '呵呵呵',
"age":999
}
1
2
3
4
5
data_dict = {
1: 29,
True: 5
}
print(data_dict) # {1: 5}

一般在什么情况下会用到字典呢?

当我们想要表示一组固定信息时,用字典可以更加的直观,例如:

1
2
3
# 用户列表
user_list = [ ("alex","123"), ("admin","666") ]
...
1
2
# 用户列表
user_list = [ {"name":"alex","pwd":"123"}, {"name":"eric","pwd":"123"} ]

2.2 独有功能

  1. 获取值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    info = { 
    "age":12,
    "status":True,
    "name":"武沛齐",
    "data":None
    }

    data1 = info.get("name")
    print(data1) # 输出:武沛齐

    data2 = info.get("age")
    print(data2) # 输出:12

    data = info.get("email") # 键不存在,默认返回 None
    """
    if data == None:
    print("此键不存在")
    else:
    print(data)

    if data:
    print(data)
    else:
    print("键不存在")
    """

    """
    # 字典的键中是否存在 email
    if "email" in info:
    data = info.get("email")
    print(data)
    else:
    print("不存在")
    """

    data = info.get("hobby",123)
    print(data) # 输出:123
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 案例:
    user_list = {
    "wupeiqi": "123",
    "alex": "uk87",
    }

    username = input("请输入用户名:")
    password = input("请输入密码:")
    # None,用户名不存在
    # 密码,接下来比较密码
    pwd = user_list.get(username)

    if pwd == None:
    print("用户名不存在")
    else:
    if password == pwd:
    print("登录成功")
    else:
    print("密码错误")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 案例:
    user_list = {
    "wupeiqi": "123",
    "alex": "uk87",
    }

    username = input("请输入用户名:")
    password = input("请输入密码:")
    # None,用户名不存在
    # 密码,接下来比较密码
    pwd = user_list.get(username)

    if pwd:
    if password == pwd:
    print("登录成功")
    else:
    print("密码错误")
    else:
    print("用户名不存在")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 案例:
    user_list = {
    "wupeiqi": "123",
    "alex": "uk87",
    }

    username = input("请输入用户名:")
    password = input("请输入密码:")
    # None,用户名不存在
    # 密码,接下来比较密码
    pwd = user_list.get(username)

    if not pwd:
    print("用户名不存在")
    else:
    if password == pwd:
    print("登录成功")
    else:
    print("密码错误")

    # 写代码的准则:简单的逻辑处理放在前面;复杂的逻辑放在后面。
  2. 所有的键

    1
    2
    3
    4
    5
    6
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    data = info.keys()
    print(data) # 输出:dict_keys(['age', 'status', 'name', 'email']) py2 -> ['age', 'status', 'name', 'email']

    result = list(data)
    print(result) # ['age', 'status', 'name', 'email']

    注意:在Python2中 字典.keys()直接获取到的是列表,而Python3中返回的是高仿列表,这个高仿的列表可以被循环显示。

    1
    2
    3
    4
    # 循环
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    for ele in info.keys():
    print(ele)
    1
    2
    3
    4
    5
    6
    7
    # 是否存在
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    # info.keys() # dict_keys(['age', 'status', 'name', 'email'])
    if "age" in info.keys():
    print("age是字典的键")
    else:
    print("age不是")
  3. 所有的值

    1
    2
    3
    4
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    data = info.values()

    print(data) # 输出:dict_values([12, True, 'wupeiqi', 'xx@live.com'])

    注意:在Python2中 字典.values()直接获取到的是列表,而Python3中返回的是高仿列表,这个高仿的列表可以被循环显示。

    1
    2
    3
    4
    # 循环
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    for val in info.values():
    print(val)
    1
    2
    3
    4
    5
    6
    # 是否存在
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    if 12 in info.values():
    print("12是字典的值")
    else:
    print("12不是")
  4. 所有的键值

    1
    2
    3
    4
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    data = info.items()

    print(data) # 输出 dict_items([ ('age', 12), ('status', True), ('name', 'wupeiqi'), ('email', 'xx@live.com') ])
    1
    2
    for item in info.items():
    print(item[0],item[1]) # item是一个元组 (键,值)
    1
    2
    for key,value in info.items():
    print(key,value) # key代表键,value代表值,将兼职从元组中直接拆分出来了。
    1
    2
    3
    4
    5
    6
    7
    info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
    data = info.items()

    if ('age', 12) in data:
    print("在")
    else:
    print("不在")
  5. 设置值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    data = {
    "name": "武沛齐",
    "email": 'xxx@live.com'
    }
    data.setdefault("age", 18)
    print(data) # {'name': '武沛齐', 'email': 'xxx@live.com', 'age': 18}

    data.setdefault("name", "alex")
    print(data) # {'name': '武沛齐', 'email': 'xxx@live.com', 'age': 18}
  6. 更新字典键值对

    1
    2
    3
    info = {"age":12, "status":True}
    info.update( {"age":14,"name":"武沛齐"} ) # info中没有的键直接添加;有的键则更新值
    print(info) # 输出:{"age":14, "status":True,"name":"武沛齐"}
  7. 移除指定键值对

    1
    2
    3
    4
    5
    6
    info = {"age":12, "status":True,"name":"武沛齐"}

    data = info.pop("age")

    print(info) # {"status":True,"name":"武沛齐"}
    print(data) # 12
  8. 按照顺序移除(后进先出)

    1
    2
    3
    4
    5
    info = {"age":12, "status":True,"name":"武沛齐"}
    data = info.popitem() # ("name","武沛齐" )

    print(info) # {"age":12, "status":True}
    print(data) # ("name","武沛齐")
    • py3.6后,popitem移除最后的值。
    • py3.6之前,popitem随机删除。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 练习题
"""
结合下面的两个变量 header 和 stock_dict实现注意输出股票信息,格式如下:
SH601778,股票名称:中国晶科、当前价:6.29、涨跌额:+1.92。
SH688566,股票名称:吉贝尔、当前价:... 。
...
"""
header = ['股票名称', '当前价', '涨跌额']

stock_dict = {
'SH601778': ['中国晶科', '6.29', '+1.92'],
'SH688566': ['吉贝尔', '52.66', '+6.96'],
'SH688268': ['华特气体', '88.80', '+11.72'],
'SH600734': ['实达集团', '2.60', '+0.24']
}

2.3 公共功能

  1. 并集(Python3.9新加入)

    1
    2
    3
    4
    5
    v1 = {"k1": 1, "k2": 2}
    v2 = {"k2": 22, "k3": 33}

    v3 = v1 | v2
    print(v3) # {'k1': 1, 'k2': 22, 'k3': 33}
  2. 长度

    1
    2
    3
    info = {"age":12, "status":True,"name":"武沛齐"}
    data = len(info)
    print(data) # 输出:3
  3. 是否包含

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    info = { "age":12,  "status":True,"name":"武沛齐" }
    v1 = "age" in info
    print(v1)

    v2 = "age" in info.keys()
    print(v2)

    if "age" in info:
    pass
    else:
    pass
    1
    2
    3
    info = {"age":12, "status":True,"name":"武沛齐"}
    v1 = "武佩奇" in info.values()
    print(v1)
    1
    2
    3
    4
    info = {"age": 12, "status": True, "name": "武沛齐"}
    # 输出info.items()获取到的 dict_items([ ('age', 12), ('status', True), ('name', 'wupeiqi'), ('email', 'xx@live.com') ])
    v1 = ("age", 12) in info.items()
    print(v1)
  4. 索引(键)
    字典不同于元组和列表,字典的索引是,而列表和元组则是 0、1、2等数值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    info = { "age":12,  "status":True, "name":"武沛齐"}

    print( info["age"] ) # 输出:12
    print( info["name"] ) # 输出:武沛齐
    print( info["status"] ) # 输出:True
    print( info["xxxx"] ) # 报错,通过键为索引去获取之后时,键不存在会报错(以后项目开发时建议使用get方法根据键去获取值)

    value = info.get("xxxxx") # None
    print(value)
  5. 根据键 修改值 和 添加值 和 删除键值对
    上述示例通过键可以找到字典中的值,通过键也可以对字典进行添加和更新操作

    1
    2
    3
    4
    5
    info = {"age":12, "status":True,"name":"武沛齐"}

    info["gender"] = "男"

    print(info) # 输出: {"age":12, "status":True,"name":"武沛齐","gender":"男"}
    1
    2
    3
    4
    5
    info = {"age":12, "status":True,"name":"武沛齐"}

    info["age"] = "18"

    print(info) # 输出: {"age":"18", "status":True,"name":"武沛齐"}
    1
    2
    3
    4
    info = {"age":12, "status":True,"name":"武沛齐"}
    del info["age"] # 删除info字典中键为age的那个键值对(键不存在则报错)

    print(info) # 输出: {"status":True,"name":"武沛齐"}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    info = {"age": 12, "status": True, "name": "武沛齐"}
    if "agea" in info:

    # del info["age"]
    data = info.pop("age")
    print(info)
    print(data)
    else:
    print("键不存在")
  6. for循环
    由于字典也属于是容器,内部可以包含多个键值对,可以通过循环对其中的:键、值、键值进行循环;

    1
    2
    3
    info = {"age":12, "status":True,"name":"武沛齐"}
    for item in info:
    print(item) # 所有键
    1
    2
    3
    info = {"age":12, "status":True,"name":"武沛齐"}
    for item in info.key():
    print(item)
    1
    2
    3
    info = {"age":12, "status":True,"name":"武沛齐"}
    for item in info.values():
    print(item)
    1
    2
    3
    info = {"age":12, "status":True,"name":"武沛齐"}
    for key,value in info.items():
    print(key,value)

2.4 转换

想要转换为字典.

1
2
3
v = dict( [ ("k1", "v1"), ["k2", "v2"] ] )

print(v) # { "k1":"v1", "k2":"v2" }
1
2
3
4
5
6
7
8
9
info = { "age":12, "status":True, "name":"武沛齐" }

v1 = list(info) # ["age","status","name"]

v2 = list(info.keys()) # ["age","status","name"]

v3 = list(info.values()) # [12,True,"武沛齐"]

v4 = list(info.items()) # [ ("age",12), ("status",True), ("name","武沛齐") ]

1.5 其他

1.5.1 存储原理

image-20201121131221807

1.5.2 速度快

1
2
3
4
5
6
info = {
"alex":["肝胆","铁锤"],
"老男孩":["二蛋","缺货"]
}
for "alex" in info:
print("在"
1
2
3
4
5
6
info = {
"alex":["肝胆","铁锤"],
"老男孩":["二蛋","缺货"]
}
v1 = info["alex"]
v2 = info.get("alex")

1.5.3 嵌套

我们已学了很多数据类型,在涉及多种数据类型之间的嵌套时,需注意一下几点:

  • 字典的键必须可哈希(list/set/dict不可哈希)。

    1
    2
    3
    4
    5
    6
    7
    8
    info = {
    (11,22):123
    }

    # 错误
    info = {
    (11,[11,22,],22):"alex"
    }
  • 字典的值可以是任意类型。

    1
    2
    3
    4
    info = {
    "k1":{12,3,5},
    "k2":{"xx":"x1"}
    }
  • 字典的键和集合的元素在遇到 布尔值 和 1、0 时,需注意重复的情况。

  • 元组的元素不可以被替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
dic = {
'name':'汪峰',
'age':48,
'wife':[ {'name':'国际章','age':38},{'name':'李杰','age':48} ],
'children':['第一个娃','第二个娃']
}
"""
1. 获取汪峰的妻子名字
d1 = dic['wife'][0]['name']
print(d1)
2. 获取汪峰的孩子们
d2 = dic['children']
print(d2)
3. 获取汪峰的第一个孩子
d3 = dic['children'][0]
print(d3)
4. 汪峰的媳妇姓名变更为 章子怡
dic['wife'][0]['name] = "章子怡"
print(dic)
5. 汪峰再娶一任妻子
dic['wife'].append( {"name":"铁锤","age":19} )
print(dic)

6. 给汪峰添加一个爱好:吹牛逼
dic['hobby'] = "吹牛逼"
print(dic)
7. 删除汪峰的年龄
del dic['age']

dic.pop('age')
print(dic)
"""

3.浮点型(float)

浮点型,一般在开发中用于表示小数。

1
2
v1 = 3.14
v2 = 9.89

关于浮点型的其他知识点如下:

  • 在类型转换时需要,在浮点型转换为整型时,会将小数部分去掉。

    1
    2
    3
    v1 = 3.14 
    data = int(v1)
    print(data) # 3
  • 想要保留小数点后N位

    1
    2
    3
    v1 = 3.1415926
    result = round(v1,3)
    print(result) # 3.142
  • 浮点型的坑(所有语言中)

    image-20201121190846593

    底层原理视频:https://www.bilibili.com/video/BV1354y1B7o1/

    在项目中如果遇到精确的小数计算应该怎么办?

    1
    2
    3
    4
    5
    6
    import decimal

    v1 = decimal.Decimal("0.1")
    v2 = decimal.Decimal("0.2")
    v3 = v1 + v2
    print(v3) # 0.3

总结

  1. 集合,是 无序、不重复、元素必须可哈希、可变的一个容器(子孙元素都必须是可哈希)。

  2. 集合的查找速度比较快(底层是基于哈希进行存储)

  3. 集合可以具有 交并差 的功能。

  4. 字典是 无序、键不重复 且 元素只能是键值对的可变的一个容器(键子孙元素都必须是可哈希)。

  5. py3.6+之后字典就变为有序了。

  6. py3.9 新增了一个 {} | {} 运算。

  7. 字典的常见功能。

  8. 在python2和python3中,字典的 keys() 、values()、items() 三个功能获取的数据类型不一样。

  9. None是代表内存中的一个空值。

    1
    2
    3
    4
    5
    6
    7
    0
    ""
    [] or list()
    () or tuple()
    set()
    None
    {} or dict()
  10. 浮点型用于表示小数,但是由于其内部存储原理可能会引发数据存储不够精准。

作业

  1. 根据需求写代码

    1
    2
    3
    4
    5
    6
    dic = {'k1': "v1", "k2": "v2", "k3": [11,22,33]}

    # 请在字典中添加一个键值对,"k4": "v4",输出添加后的字典
    # 请在修改字典中 "k1" 对应的值为 "alex",输出修改后的字典
    # 请在k3对应的值中追加一个元素 44,输出修改后的字典
    # 请在k3对应的值的第 1 个位置插入个元素 18,输出修改后的字典
  2. 根据需求写代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    dic1 = {
    'name':['alex',2,3,5],
    'job':'teacher',
    'oldboy':{'alex':['python1','python2',100]}
    }

    # 1,将name对应的列表追加⼀个元素’wusir’。
    # 2,将name对应的列表中的alex全变成大写。
    # 3,oldboy对应的字典加⼀个键值对’⽼男孩’:’linux’。
    # 4,将oldboy对应的字典中的alex对应的列表中的python2删除
  3. 循环提示用户输入,并将输入内容添加到字典中(如果输入N或n则停止循环)

    1
    例如:用户输入 x1|wupeiqi ,则需要再字典中添加键值对 {'x1':"wupeiqi"}
  4. 判断以下值那个能做字典的key ?那个能做集合的元素?

    • 1
    • -1
    • “”
    • None
    • [1,2]
    • (1,)
    • {11,22,33,4}
    • {‘name’:’wupeiq’,’age’:18}
  5. 将字典的键和值分别追加到 key_list 和 value_list 两个列表中,如:

    1
    2
    3
    key_list = []
    value_list = []
    info = {'k1':'v1','k2':'v2','k3':'v3'}
  6. 字典dic = {‘k1’: “v1”, “k2”: “v2”, “k3”: [11,22,33]}

    1
    2
    3
    a. 请循环输出所有的key
    b. 请循环输出所有的value
    c. 请循环输出所有的key和value
  7. 请循环打印k2对应的值中的每个元素。

    1
    2
    3
    4
    info = {
    'k1':'v1',
    'k2':[('alex'),('wupeiqi'),('oldboy')],
    }
  8. 有字符串”k: 1|k1:2|k2:3 |k3 :4” 处理成字典 {‘k’:1,’k1’:2….}

  9. 写代码

    1
    2
    3
    4
    5
    """
    有如下值 li= [11,22,33,44,55,66,77,88,99,90] ,将所有大于 66 的值保存至字典的第一个key对应的列表中,将小于 66 的值保存至第二个key对应的列表中。

    result = {'k1':[],'k2':[]}
    """
  10. 输出商品列表,用户输入序号,显示用户选中的商品

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    """
    商品列表:
    goods = [
    {"name": "电脑", "price": 1999},
    {"name": "鼠标", "price": 10},
    {"name": "游艇", "price": 20},
    {"name": "美女", "price": 998}
    ]
    要求:
    1:页面显示 序号 + 商品名称 + 商品价格,如:
    1 电脑 1999
    2 鼠标 10
    ...
    2:用户输入选择的商品序号,然后打印商品名称及商品价格
    3:如果用户输入的商品序号有误,则提示输入有误,并重新输入。
    4:用户输入Q或者q,退出程序。
    """

day06 数据类型(中)

常见的数据类型:

  • int,整数类型(整形)
  • bool,布尔类型
  • str,字符串类型
  • list,列表类型
  • tuple,元组类型
  • dict,字典类型
  • set,集合类型
  • float,浮点类型(浮点型)

目标:掌握列表和元组数据类型的各种操作(知识点应用案例)。

课程概要:

  • list,列表类型,用于存储一些数据的容器(有序 & 可修改)。【80%】
  • tuple,元组类型,用于存储一些数据的容器(有序 & 不可修改)。【20%】

1.列表(list)

列表(list),是一个有序可变的容器,在里面可以存放多个不同类型的元素。

1.1 定义

1
2
3
user_list =  ["苍老师","有坂深雪","大桥未久"]
number_list = [98,88,666,12,-1]
data_list = [1,True,"Alex","宝强","贾乃亮"]
1
2
3
4
5
user_list = []
user_list.append("铁锤")
user_list.append(123)
user_list.append(True)
print(user_list) # ["铁锤",123,True]

不可变类型:字符串、布尔、整型(已最小,内部数据无法进行修改)

可变类型:列表(内部数据元素可以修改)

1.2 独有功能

Python中为所有的列表类型的数据提供了一批独有的功能。

在开始学习列表的独有功能之前,先来做一个字符串和列表的对比:

  • 字符串,不可变,即:创建好之后内部就无法修改。【独有功能都是新创建一份数据】

    1
    2
    3
    4
    name = "alex"
    data = name.upper()
    print(name)
    print(data)
  • 列表,可变,即:创建好之后内部元素可以修改。【独有功能基本上都是直接操作列表内部,不会创建新的一份数据】

    1
    2
    3
    4
    user_list = ["车子","妹子"]
    user_list.append("嫂子")

    print(user_list) # ["车子","妹子","嫂子"]

列表中的常见独有功能如下:

  1. 追加,在原列表中尾部追加值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    data_list = []

    v1 = input("请输入姓名")
    data_list.append(v1)

    v2 = input("请输入姓名")
    data_list.append(v2)

    print(data_list) # ["alex","eric"]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 案例1
    user_list = []

    while True:
    user = input("请输入用户名(Q退出):")
    if user == "Q":
    break
    user_list.append(user)

    print(user_list)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # 案例2
    welcome = "欢迎使用NB游戏".center(30, '*')
    print(welcome)

    user_count = 0
    while True:
    count = input("请输入游戏人数:")
    if count.isdecimal():
    user_count = int(count)
    break
    else:
    print("输入格式错误,人数必须是数字。")


    message = "{}人参加游戏NB游戏。".format(user_count)
    print(message)


    user_name_list = []

    for i in range(1, user_count + 1):
    tips = "请输入玩家姓名({}/{}):".format(i, user_count)
    name = input(tips)
    user_name_list.append(name)

    print(user_name_list)
  2. 批量追加,将一个列表中的元素逐一添加另外一个列表。

    1
    2
    3
    tools = ["搬砖","菜刀","榔头"]
    tools.extend( [11,22,33] ) # weapon中的值逐一追加到tools中
    print(tools) # ["搬砖","菜刀","榔头",11,22,33]
    1
    2
    3
    4
    5
    6
    7
    8
    tools = ["搬砖","菜刀","榔头"]
    weapon = ["AK47","M6"]
    #tools.extend(weapon) # weapon中的值逐一追加到tools中
    #print(tools) # ["搬砖","菜刀","榔头","AK47","M6"]

    weapon.extend(tools)
    print(tools) # ["搬砖","菜刀","榔头"]
    print(weapon) # ["AK47","M6","搬砖","菜刀","榔头"]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 等价于(扩展)
    weapon = ["AK47","M6"]
    for item in weapon:
    print(item)

    # 输出:
    # AK47
    # M6
    tools = ["搬砖","菜刀","榔头"]
    weapon = ["AK47","M6"]
    for item in weapon:
    tools.append(item)
    print(tools) # ["搬砖","菜刀","榔头","AK47","M6"]
  3. 插入,在原列表的指定索引位置插入值

    1
    2
    3
    4
    user_list = ["苍老师","有坂深雪","大桥未久"]
    user_list.insert(0,"马蓉")
    user_list.insert(2,"李小璐")
    print(user_list)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 案例
    name_list = []
    while True:
    name = input("请输入购买火车票用户姓名(Q/q退出):")
    if name.upper() == "Q":
    break
    if name.startswith("刁"):
    name_list.insert(0, name)
    else:
    name_list.append(name)
    print(name_list)
  4. 在原列表中根据值删除(从左到右找到第一个删除)【慎用,里面没有会报错】

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    user_list.remove("Alex")
    print(user_list)


    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    if "Alex" in user_list:
    user_list.remove("Alex")
    print(user_list)


    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    while True:
    if "Alex" in user_list:
    user_list.remove("Alex")
    else:
    break
    print(user_list)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 案例:自动抽奖程序
    import random

    data_list = ["iphone12", "二手充气女友", "大保健一次", "泰国5日游", "避孕套"]

    while data_list:
    name = input("自动抽奖程序,请输入自己的姓名:")

    # 随机从data_list抽取一个值出来
    value = random.choice(data_list) # "二手充气女友"
    print( "恭喜{},抽中{}.".format(name, value) )

    data_list.remove(value) # "二手充气女友"
  5. 在原列表中根据索引踢出某个元素(根据索引位置删除)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    # 0 1 2 3 4
    user_list.pop(1)
    print(user_list) # ["王宝强","Alex","贾乃亮","Alex"]

    user_list.pop()
    print(user_list) # ["王宝强","Alex","贾乃亮"]

    item = user_list.pop(1)
    print(item) # "Alex"
    print(user_list) # ["王宝强","贾乃亮"]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 案例:排队买火车票

    # ["alex","李杰","eric","武沛齐","老妖","肝胆"]
    user_queue = []

    while True:
    name = input("北京~上海火车票,购买请输入姓名排队(Q退出):")
    if name == "Q":
    break
    user_queue.append(name)

    ticket_count = 3
    for i in range(ticket_count):
    username = user_queue.pop(0)
    message = "恭喜{},购买火车票成功。".format(username)
    print(message)

    # user_queue = ["武沛齐","老妖","肝胆"]
    faild_user = "、".join(user_queue) # "武沛齐、老妖、肝胆"
    faild_message = "非常抱歉,票已售完,以下几位用户请选择其他出行方式,名单:{}。".format(faild_user)
    print(faild_message)
  6. 清空原列表

    1
    2
    3
    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    user_list.clear()
    print(user_list) # []
  7. 根据值获取索引(从左到右找到第一个删除)【慎用,找不到报错】

    1
    2
    3
    4
    5
    6
    7
    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    # 0 1 2 3 4
    if "Alex" in user_list:
    index = user_list.index("Alex")
    print(index) # 2
    else:
    print("不存在")
  8. 列表元素排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 数字排序
    num_list = [11, 22, 4, 5, 11, 99, 88]
    print(num_list)
    num_list.sort() # 让num_list从小到大排序
    num_list.sort(reverse=True) # # 让num_list从大到小排序
    print(num_list)


    # 字符串排序
    user_list = ["王宝强", "Ab陈羽凡", "Alex", "贾乃亮", "贾乃", "1"]
    # [29579, 23453, 24378]
    # [65, 98, 38472, 32701, 20961]
    # [65, 108, 101, 120]
    # [49]
    print(user_list)
    """
    sort的排序原理
    [ "x x x" ," x x x x x " ]
    """
    user_list.sort()
    print(user_list)

    注意:排序时内部元素无法进行比较时,程序会报错(尽量数据类型统一)。

  9. 反转原列表

    1
    2
    3
    4
    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    user_list.reverse()

    print(user_list)

1.3 公共功能

  1. 相加,两个列表相加获取生成一个新的列表。

    1
    2
    3
    4
    5
    6
    7
    data = ["赵四","刘能"] + ["宋晓峰","范德彪"]
    print(data) # ["赵四","刘能","宋晓峰","范德彪"]

    v1 = ["赵四","刘能"]
    v2 = ["宋晓峰","范德彪"]
    v3 = v1 + v2
    print(v3) # ["赵四","刘能","宋晓峰","范德彪"]
  2. 相乘,列表*整型 将列表中的元素再创建N份并生成一个新的列表。

    1
    2
    3
    4
    5
    6
    7
    data = ["赵四","刘能"] * 2
    print(data) # ["赵四","刘能","赵四","刘能"]

    v1 = ["赵四","刘能"]
    v2 = v1 * 2
    print(v1) # ["赵四","刘能"]
    print(v2) # ["赵四","刘能","赵四","刘能"]
  3. 运算符in包含
    由于列表内部是由多个元素组成,可以通过in来判断元素是否在列表中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    user_list = ["狗子","二蛋","沙雕","alex"] 
    result = "alex" in user_list
    # result = "alex" not in user_list
    print(result) # True

    if "alex" in user_list:
    print("在,把他删除")
    user_list.remove("alex")
    else:
    print("不在")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    user_list = ["狗子","二蛋","沙雕","alex"] 
    if "alex" in user_list:
    print("在,把他删除")
    user_list.remove("alex")
    else:
    print("不在")

    text = "打倒小日本"
    data = "日" in text
    1
    2
    3
    4
    5
    6
    7
    # 案例
    user_list = ["狗子","二蛋","沙雕","alex"]
    if "alex" in user_list:
    print("在,把他删除")
    user_list.remove("alex")
    else:
    print("不在")
    1
    2
    3
    4
    5
    # 案例
    user_list = ["王宝强","陈羽凡","Alex","贾乃亮","Alex"]
    if "Alex" in user_list:
    index = user_list.index("Alex")
    user_list.pop(index)
    1
    2
    3
    4
    5
    6
    # 案例:敏感词替换
    text = input("请输入文本内容:") # 按时打发第三方科技爱普生豆腐啊;了深刻的房价破阿偶打飞机
    forbidden_list = ["草","欧美","日韩"]
    for item in forbidden_list:
    text = text.replace(item,"**")
    print(text)

    注意:列表检查元素是否存在时,是采用逐一比较的方式,效率会比较低。

  4. 获取长度

    1
    2
    user_list = ["范德彪","刘华强",'尼古拉斯赵四']
    print( len(user_list) )
  5. 索引,一个元素的操作

    1
    2
    3
    4
    5
    # 读
    user_list = ["范德彪","刘华强",'尼古拉斯赵四']
    print( user_list[0] )
    print( user_list[2] )
    print( user_list[3] ) # 报错
    1
    2
    3
    4
    # 改
    user_list = ["范德彪","刘华强",'尼古拉斯赵四']
    user_list[0] = "武沛齐"
    print(user_list) # ["武沛齐","刘华强",'尼古拉斯赵四']
    1
    2
    3
    4
    5
    6
    # 删
    user_list = ["范德彪","刘华强",'尼古拉斯赵四']
    del user_list[1]

    user_list.remove("刘华强")
    ele = user_list.pop(1)

    注意:超出索引范围会报错。
    提示:由于字符串是不可变类型,所以他只有索引读的功能,而列表可以进行 读、改、删

  6. 切片,多个元素的操作(很少用)

    1
    2
    3
    4
    5
    6
    # 读
    user_list = ["范德彪","刘华强",'尼古拉斯赵四']

    print( user_list[0:2] ) # ["范德彪","刘华强"]
    print( user_list[1:] )
    print( user_list[:-1] )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # 改
    user_list = ["范德彪", "刘华强", '尼古拉斯赵四']
    user_list[0:2] = [11, 22, 33, 44]
    print(user_list) # 输出 [11, 22, 33, 44, '尼古拉斯赵四']

    user_list = ["范德彪", "刘华强", '尼古拉斯赵四']
    user_list[2:] = [11, 22, 33, 44]
    print(user_list) # 输出 ['范德彪', '刘华强', 11, 22, 33, 44]

    user_list = ["范德彪", "刘华强", '尼古拉斯赵四']
    user_list[3:] = [11, 22, 33, 44]
    print(user_list) # 输出 ['范德彪', '刘华强', '尼古拉斯赵四', 11, 22, 33, 44]


    user_list = ["范德彪", "刘华强", '尼古拉斯赵四']
    user_list[10000:] = [11, 22, 33, 44]
    print(user_list) # 输出 ['范德彪', '刘华强', '尼古拉斯赵四', 11, 22, 33, 44]


    user_list = ["范德彪", "刘华强", '尼古拉斯赵四']
    user_list[-10000:1] = [11, 22, 33, 44]
    print(user_list) # 输出 [11, 22, 33, 44, '刘华强', '尼古拉斯赵四']
    1
    2
    3
    4
    # 删
    user_list = ["范德彪", "刘华强", '尼古拉斯赵四']
    del user_list[1:]
    print(user_list) # 输出 ['范德彪']
  7. 步长

    1
    2
    3
    4
    5
    6
    user_list = ["范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能"]
    # 0 1 2 3 4
    print( user_list[1:4:2] )
    print( user_list[0::2] )
    print( user_list[1::2] )
    print( user_list[4:1:-1] )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 案例:实现列表的翻转
    user_list = ["范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能"]
    new_data = user_list[::-1]
    print(new_data)


    data_list = ["范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能"]
    data_list.reverse()
    print(data_list)

    # 给你一个字符串请实现字符串的翻转?
    name = "武沛齐"
    name[::-1]
  8. for循环

    1
    2
    3
    user_list = ["范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能"]
    for item in user_list:
    print(item)
    1
    2
    3
    4
    5
    user_list = ["范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能"]

    for index in range( len(user_list) ):
    item = user_index[index]
    print(item)

    切记,循环的过程中对数据进行删除会踩坑【面试题】。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 错误方式, 有坑,结果不是你想要的。

    user_list = ["刘的话", "范德彪", "刘华强", '刘尼古拉斯赵四', "宋小宝", "刘能"]
    for item in user_list:
    if item.startswith("刘"):
    user_list.remove(item)

    print(user_list)


    1
    2
    3
    4
    5
    6
    7
    # 正确方式,倒着删除。
    user_list = ["刘的话", "范德彪", "刘华强", '刘尼古拉斯赵四', "宋小宝", "刘能"]
    for index in range(len(user_list) - 1, -1, -1):
    item = user_list[index]
    if item.startswith("刘"):
    user_list.remove(item)
    print(user_list)

1.4 转换

  • int、bool无法转换成列表

  • str

    1
    2
    3
    4
    name = "武沛齐"

    data = list(name) # ["武","沛","齐"]
    print(data)
  • 超前

    1
    2
    3
    4
    5
    v1 = (11,22,33,44) # 元组
    vv1 = list(v1) # 列表 [11,22,33,44]

    v2 = {"alex","eric","dsb"} # 集合
    vv2 = list(v2) # 列表 ["alex","eric","dsb"]

1.5. 其他

1.5.1 嵌套

列表属于容器,内部可以存放各种数据,所以他也支持列表的嵌套,如:

1
data = [ "谢广坤",["海燕","赵本山"],True,[11,22,[999,123],33,44],"宋小宝" ]

对于嵌套的值,可以根据之前学习的索引知识点来进行学习,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
data = [ "谢广坤",["海燕","赵本山"],True,[11,22,33,44],"宋小宝" ]

print( data[0] ) # "谢广坤"
print( data[1] ) # ["海燕","赵本山"]
print( data[0][2] ) # "坤"
print( data[1][-1] ) # "赵本山"

data.append(666)
print(data) # [ "谢广坤",["海燕","赵本山"],True,[11,22,33,44],"宋小宝",666]

data[1].append("谢大脚")
print(data) # [ "谢广坤",["海燕","赵本山","谢大脚"],True,[11,22,33,44],"宋小宝",666 ]


del data[-2]
print(data) # [ "谢广坤",["海燕","赵本山","谢大脚"],True,[11,22,33,44],666 ]


data[-2][1] = "alex"
print(data) # [ "谢广坤",["海燕","赵本山","谢大脚"],True,[11,"alex",33,44],666 ]


data[1][0:2] = [999,666]
print(data) # [ "谢广坤",[999,666,"谢大脚"],True,[11,"alex",33,44],666 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建用户列表
# 用户列表应该长: [ ["alex","123"],["eric","666"] ]

# user_list = [["alex","123"],["eric","666"],]
# user_list.append(["alex","123"])
# user_list.append(["eric","666"])


user_list = []
while True:
user = input("请输入用户名:")
pwd = input("请输入密码:")

data = []
data.append(user)
data.append(pwd)

user_list.append(data)
1
2
3
4
5
6
7
8
9
10
user_list = []
while True:
user = input("请输入用户名(Q退出):")
if user == "Q":
break
pwd = input("请输入密码:")
data = [user,pwd]
user_list.append(data)

print(user_list)

1.6 列表阶段作业

  1. 写代码,有如下列表,按照要求实现每一个功能。

    1
    li = ["alex", "WuSir", "ritian", "barry", "武沛齐"]
    • 计算列表的长度并输出
    • 列表中追加元素”seven”,并输出添加后的列表
    • 请在列表的第1个索引位置插入元素”Tony”,并输出添加后的列表
    • 请修改列表第2个索引位置的元素为”Kelly”,并输出修改后的列表
    • 请将列表的第3个位置的值改成 “妖怪”,并输出修改后的列表
    • 请将列表 data=[1,"a",3,4,"heart"] 的每一个元素追加到列表 li 中,并输出添加后的列表
    • 请将字符串 s = "qwert"的每一个元素到列表 li 中。
    • 请删除列表中的元素”barry”,并输出添加后的列表
    • 请删除列表中的第2个元素,并输出删除元素后的列表
    • 请删除列表中的第2至第4个元素,并输出删除元素后的列表
  2. 写代码,有如下列表,利用切片实现每一个功能

    1
    li = [1, 3, 2, "a", 4, "b", 5,"c"]
    • 通过对li列表的切片形成新的列表 [1,3,2]
    • 通过对li列表的切片形成新的列表 [“a”,4,”b”]
    • 通过对li列表的切片形成新的列表 [1,2,4,5]
    • 通过对li列表的切片形成新的列表 [3,”a”,”b”]
    • 通过对li列表的切片形成新的列表 [3,”a”,”b”,”c”]
    • 通过对li列表的切片形成新的列表 [“c”]
    • 通过对li列表的切片形成新的列表 [“b”,”a”,3]
  3. 写代码,有如下列表,按照要求实现每一个功能。

    1
    lis = [2, 3, "k", ["qwe", 20, ["k1", ["tt", 3, "1"]], 89], "ab", "adv"]
    • 将列表lis中的第2个索引位置的值变成大写,并打印列表。
    • 将列表中的数字3变成字符串”100”
    • 将列表中的字符串”tt”变成数字 101
    • 在 “qwe”前面插入字符串:”火车头”
  4. 请用代码实现循环输出元素和值:users = [“武沛齐”,”景女神”,”肖大侠”] ,如:

    1
    2
    3
    0 武沛齐
    1 景女神
    2 肖大侠
  5. 请用代码实现循环输出元素和值:users = [“武沛齐”,”景女神”,”肖大侠”] ,如:

    1
    2
    3
    1 武沛齐
    2 景女神
    3 肖大侠
  6. 写代码实现以下功能

    • 如有变量 goods = [‘汽车’,’飞机’,’火箭’] 提示用户可供选择的商品:

      1
      2
      3
      0,汽车
      1,飞机
      2,火箭
    • 用户输入索引后,将指定商品的内容拼接打印,如:用户输入0,则打印 您选择的商品是汽车。

  7. 利用for循环和range 找出 0 ~ 50 以内能被3整除的数,并追加到一个列表。

  8. 利用for循环和range 找出 0 ~ 50 以内能被3整除的数,并插入到列表的第0个索引位置,最终结果如下:

    1
    [48,45,42...]
  9. 查找列表li中的元素,移除每个元素的空格,并找出以”a”开头,并添加到一个新列表中,最后循环打印这个新列表。

    1
    li = ["alexC", "AbC ", "egon", " riTiAn", "WuSir", "  aqc"]
  10. 将以下车牌中所有 的车牌搞到一个列表中,并输出京牌车辆的数量。

    1
    data = ["京1231", "冀8899", "京166631", "晋989"]

2.元组

列表(list),是一个有序可变的容器,在里面可以存放多个不同类型的元素。

元组(tuple),是一个有序不可变的容器,在里面可以存放多个不同类型的元素。

如何体现不可变呢?
记住一句话:《”我儿子永远不能换成是别人,但我儿子可以长大”》

2.1 定义

1
2
3
4
5
v1 = (11,22,33)
v2 = ("李杰","Alex")
v3 = (True,123,"Alex",[11,22,33,44])

# 建议:议在元组的最后多加一个逗v3 = ("李杰","Alex",)
1
2
3
4
5
d1 = (1)  # 1
d2 = (1,) # (1,)

d3 = (1,2)
d4 = (1,2)

注意:建议在元组的最后多加一个逗号,用于标识他是一个元组。

1
2
3
4
# 面试题
1. 比较值 v1 = (1) 和 v2 = 1 和 v3 = (1,) 有什么区别?
2. 比较值 v1 = ( (1),(2),(3) ) 和 v2 = ( (1,) , (2,) , (3,),) 有什么区别?
(1,2,3)

2.2 独有功能

2.3 公共功能

  1. 相加,两个列表相加获取生成一个新的列表。

    1
    2
    3
    4
    5
    6
    7
    data = ("赵四","刘能") + ("宋晓峰","范德彪")
    print(data) # ("赵四","刘能","宋晓峰","范德彪")

    v1 = ("赵四","刘能")
    v2 = ("宋晓峰","范德彪")
    v3 = v1 + v2
    print(v3) # ("赵四","刘能","宋晓峰","范德彪")
  2. 相乘,列表*整型 将列表中的元素再创建N份并生成一个新的列表。

    1
    2
    3
    4
    5
    6
    7
    data = ("赵四","刘能") * 2
    print(data) # ("赵四","刘能","赵四","刘能")

    v1 = ("赵四","刘能")
    v2 = v1 * 2
    print(v1) # ("赵四","刘能")
    print(v2) # ("赵四","刘能","赵四","刘能")
  3. 获取长度

    1
    2
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',)
    print( len(user_list) )
  4. 索引

    1
    2
    3
    4
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',)
    print( user_list[0] )
    print( user_list[2] )
    print( user_list[3] )
  5. 切片

    1
    2
    3
    4
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',)
    print( user_list[0:2] )
    print( user_list[1:] )
    print( user_list[:-1] )
  6. 步长

    1
    2
    3
    4
    5
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能")
    print( user_list[1:4:2] )
    print( user_list[0::2] )
    print( user_list[1::2] )
    print( user_list[4:1:-1] )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 字符串 & 元组。
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能")
    data = user_list[::-1]

    # 列表
    user_list = ["范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能"]
    data = user_list[::-1]

    user_list.reverse()
    print(user_list)
  7. for循环

    1
    2
    3
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能")
    for item in user_list:
    print(item)
    1
    2
    3
    4
    5
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能")
    for item in user_list:
    if item == '刘华强':
    continue
    print(name)

    目前:只有 str、list、tuple 可以被for循环。 “xxx” [11,22,33] (111,22,33)

    1
    2
    3
    4
    5
    # len + range + for + 索引
    user_list = ("范德彪","刘华强",'尼古拉斯赵四',"宋小宝","刘能")
    for index in range(len(user_list)):
    item = user_list[index]
    print(item)

2.4 转换

其他类型转换为元组,使用tuple(其他类型),目前只有字符串和列表可以转换为元组。

1
2
3
data = tuple(其他)

# str / list
1
2
3
name = "武沛齐"
data = tuple(name)
print(data) # 输出 ("武","沛","齐")
1
2
3
name = ["武沛齐",18,"pythonav"]
data = tuple(name)
print(data) # 输出 ("武沛齐",18,"pythonav")

2.5 其他

2.5.1 嵌套

由于元组和列表都可以充当容器,他们内部可以放很多元素,并且也支持元素内的各种嵌套。

1
2
3
4
5
6
7
8
9
10
11
tu = ( '今天姐姐不在家', '姐夫和小姨子在客厅聊天', ('姐夫问小姨子税后多少钱','小姨子低声说道说和姐夫还提钱') )
tu1 = tu[0]
tu2 = tu[1]
tu3 = tu[2][0]
tu4 = tu[2][1]
tu5 = tu[2][1][3]

print(tu1) # 今天姐姐不在家
print(tu2) # 姐夫和小姨子在客厅聊天
print(tu3) # 姐夫问小姨子税后多少钱
print(tu4) # 小姨子低声说道说和姐夫还提钱

练习题1:判断是否可以实现,如果可以请写代码实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
li = ["alex", [11,22,(88,99,100,),33],  "WuSir",  ("ritian", "barry",),  "wenzhou"]
# 0 1 2 3 4

# 1.请将 "WuSir" 修改成 "武沛齐"
li[2] = "武沛齐"
index = li.index("Wusir")
li[index] = "武沛齐"

# 2.请将 ("ritian", "barry",) 修改为 ['日天','日地']
li[3] = ['日天','日地']

# 3.请将 88 修改为 87
li[1][2][0] = 87 # (报错,)

# 4.请将 "wenzhou" 删除,然后再在列表第0个索引位置插入 "周周"
# li.remove("wenzhou")
# del li[-1]
li.insert(0,"周周")

练习题2:记住一句话:《”我儿子永远不能换成是别人,但我儿子可以长大”》

1
2
3
4
5
6
7
8
9
10
11
12
13
data = ("123",666,[11,22,33], ("alex","李杰",[999,666,(5,6,7)]) )

# 1.将 “123” 替换成 9 报错

# 2.将 [11,22,33] 换成 "武沛齐" 报错

# 3.将 11 换成 99
data[2][0] = 99
print(data) # ("123",666,[99,22,33], ("alex","李杰",[999,666,(5,6,7)]) )

# 4.在列表 [11,22,33] 追加一个44
data[2].append(44)
print(data) # ("123",666,[11,22,33,44], ("alex","李杰",[999,666,(5,6,7)]) )

练习题3:动态的创建用户并添加到用户列表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 创建用户 5个
# user_list = [] # 用户信息
user_list = [ ("alex","132"),("admin","123"),("eric","123") ]

while True:
user = input("请输入用户名:")
if user == "Q":
brek
pwd = input("请输入密码:")
item = (user,pwd,)
user_list.append(item)

# 实现:用户登录案例
print("登录程序")
username = input("请输入用户名:")
password = input("请输入密码:")

is_success = False

for item in user_list:
# item = ("alex","132") ("admin","123") ("eric","123")
if username == item[0] and password == item[1]:
is_success = True
break

if is_success:
print("登录成功")
else:
print("登录失败")

总结

  1. 概述
    • 列表,以后写程序会用的非常多,要多些多练。
    • 元组,以后写程序用的不是很多,主要以了解其特殊和用法为主。
  2. 列表和元组的区别。
  3. 可变类型和不可变类型。
  4. 列表独有功能 & 公共功能(不用特地去记,多做题目去用,以后每天都会有相关的练习题)。
  5. 列表和元组等数据的嵌套
  6. 元组中 (1) 和 (1,) 的区别。
  7. 元组的元素不能被替换,但元组的元素如果是可变类型,可变类型内部是可以修改的。

作业

  1. 以下哪些数据类型转换为布尔值为False

    1
    2
    3
    4
    5
    6
    7
    8
    1
    ""
    -19
    []
    [11,22]
    (1)
    (1,2,3)
    ()
  2. 运算符操作

    1
    2
    v1 = [] or "alex"
    v2 = [11,22] and (1,2,)
  3. 比较:a = [1,2,3]b = [(1),(2),(3) ] 以及 c = [(1,),(2,),(3,) ] 的区别?

  4. 将字符串text = "wupeiqi|alex|eric"根据 | 分割为列表,然后列表转换为元组类型。

  5. 根据如下规则创建一副扑克牌(排除大小王)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 花色列表
    color_list = ["红桃","黑桃","方片","梅花"]

    # 牌值
    num_list = []
    for num in range(1,14):
    num_list.append(num)

    result = []
    # 请根据以上的花色和牌值创建一副扑克牌(排除大小王)
    # 最终result的结果格式为: [ ("红桃",1), ("红桃",2) ... ]

day05 数据类型(上)

接下来的3天的课程都是来讲解数据类型的知识点,常见的数据类型:

  • int,整数类型(整形)
  • bool,布尔类型
  • str,字符串类型
  • list,列表类型
  • tuple,元组类型
  • dict,字典类型
  • set,集合类型
  • float,浮点类型(浮点型)

每种数据类型都有自己的特点及应用场景,以后的开发中需要根据实际的开发情况选择合适的数据类型。

image-20201102172217820

每种数据类型的讲解,会按照以下4个维度来进行:

  1. 定义
  2. 独有功能
  3. 公共功能
  4. 类型转换
  5. 其他

今日课程目标:掌握整形、布尔类型、字符串的必备知识。

今日课程概要:

  • 整形
  • 布尔类型
  • 字符串类型

1.整型

整型其实就是十进制整数的统称,比如:1、68、999都属于整型。他一般用于表示 年龄、序号等。

1.1 定义

1
2
number = 10
age = 99

1.2 独有功能

1
2
3
4
5
6
7
8
9
10
11
v1 = 5
print(bin(v1)) # 0b101
# 调用v1(int)的独有功能,获取v1的二进制有多少个位组成。
result1 = v1.bit_length()
print(result1) # 3

v2 = 10
print(bin(10)) # 0b1010
# 调用v2(int)的独有功能,获取v2的二进制有多少个位组成。
result2 = v2.bit_length()
print(result2) # 4

1.3 公共功能

加减乘除

1
2
3
v1 = 4
v2 = 8
v3 = v1 + v2

1.4 转换

在项目开发和面试题中经常会出现一些 “字符串” 和 布尔值 转换为 整型的情况。

1
2
3
4
5
6
7
8
9
10
11
12
# 布尔值转整型
n1 = int(True) # True转换为整数 1
n2 = int(False) # False转换为整数 0

# 字符串转整型
v1 = int("186",base=10) # 把字符串看成十进制的值,然后再转换为 十进制整数,结果:v1 = 186
v2 = int("0b1001",base=2) # 把字符串看成二进制的值,然后再转换为 十进制整数,结果:v1 = 9 (0b表示二进制)
v3 = int("0o144",base=8) # 把字符串看成八进制的值,然后转换为 十进制整数,结果:v1 = 100 (0o表示八进制)
v4 = int("0x59",base=16) # 把字符串看成十六进制的值,然后转换为 十进制整数,结果:v1 = 89 (0x表示十六进制)

# 浮点型(小数)
v1 = int(8.7) # 8

所以,如果以后别人给你一个按 二进制、八进制、十进制、十六进制 规则存储的字符串时,可以轻松的通过int转换为十进制的整数。

1.5 其他

1.5.1 长整型

  • Python3:整型(无限制)
  • Python2:整型、长整形

在python2中跟整数相关的数据类型有两种:int(整型)、long(长整型),他们都是整数只不过能表示的值范围不同。

image-20201102190227431
  • int,可表示的范围:-9223372036854775808~9223372036854775807
  • long,整数值超出int范围之后自动会转换为long类型(无限制)。

在python3中去除了long只剩下:int(整型),并且 int 长度不在限制。

1.5.2 地板除

  • Py3:

    1
    2
    v1 = 9/2 
    print(v1) # 4.5
  • py2:

    1
    2
    v1 = 9/2 
    print(v1) # 4
    1
    2
    3
    4
    from __future__ import division 

    v1 = 9/2
    print(v1) # 4.5

2. 布尔类型

布尔值,其实就是 “真”、“假” 。

2.1 定义

1
2
data = False
alex_is_sb = True

2.2 独有功能

2.3 公共功能

1
2
v1 = True + True
print(v1) # 2

2.4 转换

在以后的项目开发中,会经常使用其他类型转换为布尔值的情景,此处只要记住一个规律即可。

1
2
整数0、空字符串、空列表、空元组、空字典转换为布尔值时均为False
其他均为True
1
2
3
4
5
6
7
8
9
10
11
# 练习题:查看一些变量为True还是False
v1 = bool(0)
v2 = bool(-10)
v3 = bool(10)
v4 = bool("武沛齐")
v5 = bool("")
v6 = bool(" ")
v7 = bool([]) # [] 表示空列表
v8 = bool([112233]) # [11,22,33] 表示非空列表
v9 = bool({}) # {} 表示空字典
v10 = bool({"name":"武沛齐","age":18}) # {"name":"武沛齐","age":18} 表示非空字典

2.5 其他

2.5.1 做条件自动转换

如果在 ifwhile 条件后面写一个值当做条件时,他会默认转换为布尔类型,然后再做条件判断。

1
2
3
4
5
6
7
8
9
10
11
12
if 0:
print("太六了")
else:
print(999)

if "武沛齐":
print("你好")

if "alex":
print("你是傻逼?")
else:
print("你是逗比?")
1
2
while 1>9:
pass
1
2
3
4
5
if 值:
pass

while 值:
pass

3.字符串类型

字符串,我们平时会用他来表示文本信息。例如:姓名、地址、自我介绍等。

3.1 定义

1
2
3
4
5
6
7
8
9
v1 = "包治百病"
v2 = '包治百病'
v3 = "包'治百病"
v4 = '包"治百病'
v5 = """
吵架都是我的错,
因为大家打不过。
"""
# 三个引号,可以支持多行/换行表示一个字符串,其他的都只能在一行中表示一个字符串。

3.2 独有功能(18/48)

1
2
3
4
"xxxxx".功能(...)

v1 = "xxxxx"
v1.功能(...)
  1. 判断字符串是否以 XX 开头?得到一个布尔值

    1
    2
    3
    4
    5
    6
    v1 = "叨逼叨的一天,烦死了"

    # True
    result = v1.startswith("叨逼叨的一天")

    print(result) # 值为True
    1
    2
    3
    4
    5
    6
    7
    # 案例
    v1 = input("请输入住址:")

    if v1.startswith("北京市"):
    print("北京人口")
    else:
    print("非北京人口")
  2. 判断字符串是否以 XX 结尾?得到一个布尔值

    1
    2
    3
    4
    5
    v1 = "叨逼叨的一天,烦死了"

    result = v1.endswith("烦死了")

    print(result) # 值为True
    1
    2
    3
    4
    5
    6
    7
    # 案例
    address = input("请输入地址:")

    if address.endswith('村'):
    print("农业户口")
    else:
    print("非农户口")
  3. 判断字符串是否为十进制数?得到一个布尔值

    1
    2
    3
    v1 = "1238871"
    result = v1.isdecimal()
    print(result) # True
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 案例,两个数相加。

    v1 = input("请输入值:") # ”666“
    v2 = input("请输入值:") # ”999“
    if v1.isdecimal() and v2.isdecimal():
    data = int(v1) + int(v2)
    print(data)
    else:
    print("请正确输入数字")
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    v1 = "123"
    print(v1.isdecimal()) # True

    v2 = "①"
    print(v2.isdecimal()) # False

    v3 = "123"
    print(v3.isdigit()) # True

    v4 = "①"
    print(v4.isdigit()) # True
  4. 去除字符串两边的 空格、换行符、制表符,得到一个新字符串

    1
    2
    data = input("请输入内容:") #武沛齐,武沛齐   
    print(data)
    1
    2
    3
    msg = " H e ll o啊,树哥 "
    data = msg.strip()
    print(data) # 将msg两边的空白去掉,得到"H e ll o啊,树哥"
    1
    2
    3
    msg = " H e ll o啊,树哥 "
    data = msg.lstrip()
    print(data) # 将msg两边的空白去掉,得到"H e ll o啊,树哥 "
    1
    2
    3
    msg = " H e ll o啊,树哥 "
    data = msg.rstrip()
    print(data) # 将msg两边的空白去掉,得到" H e ll o啊,树哥"

    补充:去除 空格、换行符、制表符。

    1
    2
    3
    4
    5
    6
    7
    # 案例
    code = input("请输入4位验证码:") # FB87
    data = code.strip()
    if data == "FB87":
    print('验证码正确')
    else:
    print("验证码错误")

    再补充:去除字符串两边指定的内容

    1
    2
    3
    msg = "哥H e ll o啊,树哥"
    data = msg.strip("哥")
    print(data) # 将msg两边的空白去掉,得到"H e ll o啊,树"
    1
    2
    3
    msg = "哥H e ll o啊,树哥"
    data = msg.lstrip("哥")
    print(data) # 将msg两边的空白去掉,得到"H e ll o啊,树哥"
    1
    2
    3
    msg = "哥H e ll o啊,树哥"
    data = msg.rstrip("哥")
    print(data) # 将msg两边的空白去掉,得到"哥H e ll o啊,树"
  5. 字符串变大写,得到一个新字符串

    1
    2
    3
    4
    5
    msg = "my name is oliver queen"
    data = msg.upper()

    print(msg) # my name is oliver queen
    print(data) # 输出为:MY NAME IS OLIVER QUEEN
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 案例
    code = input("请输入4位验证码:") # FB88 fb88
    value = code.upper() # FB88
    data = value.strip() # FB88

    if data == "FB87":
    print('验证码正确')
    else:
    print("验证码错误")

    # 注意事项
    """
    code的值"fb88 "
    value的值"FB88 "
    data的值"FB88"
    """
  6. 字符串变小写,得到一个新字符串

    1
    2
    3
    4
    msg = "My Name Is Oliver Queen"
    data = msg.lower()

    print(data) # 输出为:my name is oliver queen
    1
    2
    3
    4
    5
    6
    7
    # 案例
    code = input("请输入4位验证码:")
    value = code.strip().lower()
    if value == "fb87":
    print('验证码正确')
    else:
    print("验证码错误")
  7. 字符串内容替换,得到一个新的字符串

    1
    2
    3
    4
    data = "你是个好人,但是好人不合适我"
    value = data.replace("好人","贱人")
    print(data) # "你是个好人,但是好人不合适我"
    print(value) # "你是个贱人,但是贱人不合适我"
    1
    2
    3
    4
    5
    6
    7
    8
    # 案例
    video_file_name = "高清无码爱情动作片.mp4"

    new_file_name = video_file_name.replace("mp4","avi") # "高清无码爱情动作片.avi"

    final_file_name = new_file_name.replace("无码","步兵") # "高清步兵爱情动作片.avi"

    print(final_file_name)
    1
    2
    3
    4
    5
    6
    7
    8
    # 案例
    video_file_name = "高清无码爱情动作片.mp4"

    new_file_name = video_file_name.replace("mp4","avi") # "高清无码爱情动作片.avi"

    final_file_name = video_file_name.replace("无码","步兵") # "高清步兵爱情动作片.mp4"

    print(final_file_name)
    1
    2
    3
    4
    5
    # 案例
    content = input("请输入评论信息") # alex是一个草包
    content = content.replace("草","**") # alex是一个**包
    content = content.replace("泥马","***") # alex是一个**包
    print(content) # alex是一个**包
    1
    2
    3
    4
    5
    6
    7
    char_list = ["草拟吗","逗比","二蛋","钢球"]

    content = input("请输入评论信息")
    for item in char_list:
    content = content.repalce(item,"**")

    print(content)
  8. 字符串切割,得到一个列表

    1
    2
    3
    4
    data = "武沛齐|root|wupeiqi@qq.com"
    result = data.split('|') # ["武沛齐","root","wupeiqi@qq.com"]
    print(data) # "武沛齐|root|wupeiqi@qq.com"
    print(result) # 输出 ["武沛齐","root","wupeiqi@qq.com"] 根据特定字符切开之后保存在列表中,方便以后的操作
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 案例:判断用户名密码是否正确
    info = "武沛齐,root" # 备注:字符串中存储了用户名和密码
    user_list = info.split(',') # 得到一个包含了2个元素的列表 [ "武沛齐" , "root" ]

    # user_list[0]
    # user_list[1]

    user = input("请输入用户名:")
    pwd = input("请输入密码:")

    if user == user_list[0] and pwd == user_list[1]:
    print("登录成功")
    else:
    print("用户名或密码错误")

    扩展

    1
    2
    3
    4
    5
    6
    data = "武沛齐|root|wupeiqi@qq.com"
    v1 = data.split("|") # ['武沛齐', 'root', 'wupeiqi@qq.com']
    print(v1)

    v2 = data.split("|", 2) # ['武沛齐', 'root|wupeiqi@qq.com']
    print(v2)

    再扩展

    1
    2
    3
    4
    5
    6
    7
    data = "武沛齐,root,wupeiqi@qq.com"

    v1 = data.rsplit(',')
    print(v1) # ['武沛齐', 'root', 'wupeiqi@qq.com']

    v2 = data.rsplit(',',1)
    print(v2) # ['武沛齐,root', 'wupeiqi@qq.com']

    应用场景:

    1
    2
    3
    4
    5
    file_path = "xxx/xxxx/xx.xx/xxx.mp4"

    data_list = file_path.rsplit(".",1) # ["xxx/xxxx/xx.xx/xxx","mp4"]
    data_list[0]
    data_list[1]
  9. 字符串拼接,得到一个新的字符串

    1
    2
    3
    data_list = ["alex","是","大烧饼"]
    v1 = "_".join(data_list) # alex_是_大烧饼
    print(v1)
  10. 格式化字符串,得到新的字符串

    1
    2
    3
    4
    name = "{0}的喜欢干很多行业,例如有:{1}、{2} 等"
    data = name.format("老王","护士","嫩模")
    print(data) # 老王的喜欢干很多行业,例如有:护士、嫩模 等
    print(name) # "{0}的喜欢干很多行业,例如有:{1}、{2} 等"
    1
    2
    3
    name = "{}的喜欢干很多行业,例如有:{}、{} 等"
    data = name.format("老王","护士","嫩模")
    print(data) # 老王的喜欢干很多行业,例如有:护士、嫩模 等
    1
    2
    3
    name = "{name}的喜欢干很多行业,例如有:{h1}、{h2} 等"
    data = name.format(name="老王",h1="护士",h2="嫩模")
    print(data) # 老王的喜欢干很多行业,例如有:护士、嫩模 等
  11. 字符串转换为字节类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    data = "嫂子"  # unicode,字符串类型

    v1 = data.encode("utf-8") # utf-8,字节类型
    v2 = data.encode("gbk") # gbk,字节类型

    print(v1) # b'\xe5\xab\x82 \xe5\xad\x90'
    print(v2) # b'\xc9\xa9 \xd7\xd3'

    s1 = v1.decode("utf-8") # 嫂子
    s2 = v2.decode("gbk") # 嫂子
    print(s1)
    print(s2)
  12. 将字符串内容居中、居左、居右展示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    v1 = "王老汉"
    # data = v1.center(21, "-")
    # print(data) #---------王老汉---------

    # data = v1.ljust(21, "-")
    # print(data) # 王老汉------------------

    # data = v1.rjust(21, "-")
    # print(data) # ------------------王老汉
  13. 帮助你填充0

    1
    2
    3
    data = "alex"
    v1 = data.zfill(10)
    print(v1) # 000000alex
    1
    2
    3
    4
    # 应用场景:处理二进制数据
    data = "101" # "00000101"
    v1 = data.zfill(8)
    print(v1) # "00000101"

练习题

  1. 写代码实现判断用户输入的值否以 “al”开头,如果是则输出 “是的” 否则 输出 “不是的”

  2. 写代码实现判断用户输入的值否以”Nb”结尾,如果是则输出 “是的” 否则 输出 “不是的”

  3. 将 name 变量对应的值中的 所有的”l”替换为 “p”,并输出结果

  4. 写代码实现对用户输入的值判断,是否为整数,如果是则转换为整型并输出,否则直接输出”请输入数字”

  5. 对用户输入的数据使用”+”切割,判断输入的值是否都是数字?
    提示:用户输入的格式必须是以下+连接的格式,如 5+9 、alex+999

  6. 写代码实现一个整数加法计算器(两个数相加)
    需求:提示用户输入:5+9或5+9或5+9,计算出两个值的和(提示:先分割再转换为整型,再相加)

  7. 写代码实现一个整数加法计算器(两个数相加)
    需求:提示用户输入:5 +9或5+ 9或5 + 9,计算出两个值的和(提示:先分割再去除空白、再转换为整型,再相加)

  8. 补充代码实现用户认证。
    需求:提示用户输入手机号、验证码,全都验证通过之后才算登录成功(验证码大小写不敏感)

    1
    2
    3
    4
    5
    import random
    code = random.randrange(1000,9999) # 生成动态验证码
    msg = "欢迎登录PythonAV系统,您的验证码为:{},手机号为:{}".format(code,"15131266666")
    print(msg)
    # 请补充代码
  9. 补充代码实现数据拼接

    1
    2
    3
    4
    5
    6
    7
    8
    data_list = []
    while True:
    hobby = input("请输入你的爱好(Q/q退出):")
    if hobby.upper() == 'Q':
    break
    # 把输入的值添加到 data_list 中,如:data_list = ["小姨子","哥们的女朋友"]
    data_list.append(hobby)
    # 将所有的爱好通过符号 "、"拼接起来并输出

3.3 公共功能

  1. 相加:字符串 + 字符串

    1
    2
    v1 = "alex" + "大sb"
    print(v1)
  2. 相乘:字符串 * 整数

    1
    2
    data = "嫂子" * 3
    print(data) # 嫂子嫂子嫂子
  3. 长度

    1
    2
    3
    data = "嫂子满身大汉"
    value = len(data)
    print(value) # 6
  4. 获取字符串中的字符,索引

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    message = "来做点py交易呀"
    # 0 1 2345 6 7
    # ... -3 -2 -1
    print(message[0]) # "来"
    print(message[1]) # "做"
    print(message[2]) # "点"

    print(message[-1]) # 呀
    print(message[-2]) # 呀
    print(message[-3]) # 呀

    注意:字符串中是能通过索引取值,无法修改值。【字符串在内部存储时不允许对内部元素修改,想修改只能重新创建。】

    1
    2
    3
    4
    5
    6
    message = "来做点py交易呀"
    index = 0
    while index < len(message):
    value = message[index]
    print(value)
    index += 1
    1
    2
    3
    4
    5
    6
    message = "来做点py交易呀"
    index = len(message) - 1
    while index >=0:
    value = message[index]
    print(value)
    index -= 1
  5. 获取字符串中的子序列,切片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    message = "来做点py交易呀"

    print(message[0:2]) # "来做"
    print(message[3:7]) # "py交易"
    print( message[3:] ) # "py交易呀"
    print( message[:5] ) # "来做点py"

    print(message[4:-1]) # "y交易"
    print(message[4:-2]) # "y交"

    print( message[4:len(message)] ) # "y交易呀"

    注意:字符串中的切片只能读取数据,无法修改数据。【字符串在内部存储时不允许对内部元素修改,想要修改只能重新创建】

    1
    2
    3
    4
    message = "来做点py交易呀"

    value = message[:3] + "Python" + message[5:]
    print(value)
  6. 步长,跳着去字符串的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    name = "生活不是电影,生活比电影苦"

    print( name[ 0:5:2 ] ) # 输出:生不电 【前两个值表示区间范围,最有一个值表示步长】
    print( name[ :8:2 ] ) # 输出:生不电, 【区间范围的前面不写则表示起始范围为0开始】、
    # 此处老师讲解时,错把 name[ 2::3 ]看成了name[ 2::2 ],更正下。(感谢 B站 放酱啊噗啊噗 同学的反馈)
    # print( name[ 2::2 ] ) # 输出:不电,活电苦
    # print( name[ 2::3 ] ) # 输出:不影活影

    print( name[ 2::3 ] ) # 输出:不电,活电苦 【区间范围的后面不写则表示结束范围为最后】
    print( name[ ::2 ] ) # 输出:生不电,活电苦 【区间范围不写表示整个字符串】
    print( name[ 8:1:-1 ] ) # 输出:活生,影电是不 【倒序】
    1
    2
    3
    4
    5
    6
    7
    8
    name = "生活不是电影,生活比电影苦"

    print(name[8:1:-1]) # 输出:活生,影电是不 【倒序】
    print(name[-1:1:-1]) # 输出:苦影电比活生,影电是不 【倒序】

    # 面试题:给你一个字符串,请将这个字符串翻转。
    value = name[-1::-1]
    print(value) # 苦影电比活生,影电是不活生
  7. 循环

    • while循环

      1
      2
      3
      4
      5
      6
      message = "来做点py交易呀"
      index = 0
      while index < len(message):
      value = message[index]
      print(value)
      index += 1
    • for循环

      1
      2
      3
      message = "来做点py交易呀"
      for char in message:
      print(char)
    • range,帮助我们创建一系列的数字

      1
      2
      3
      4
      range(10) # [0,1,2,3,4,5,6,7,8,9]
      range(1,10) # [1,2,3,4,5,6,7,8,9]
      range(1,10,2) # [1,3,5,7,9]
      range(10,1,-1) # [10,9,8,7,6,5,4,3,2]
    • For + range

      1
      2
      for i in range(10):
      print(i)
      1
      2
      3
      4
      message = "来做点py交易呀"

      for i in range(5): # [0,1,2,3,4]
      print(message[i])
      1
      2
      3
      message = "来做点py交易呀"
      for i in range( len(message) ): # [0,1,2,3,4,5,6,7]
      print(message[i])

    一般应用场景:

    • while,一般在做无限制(未知)循环此处时使用。

      1
      2
      while True:
      ...
      1
      2
      3
      4
      5
      6
      7
      8
      9
      # 用户输入一个值,如果不是整数则一直输入,直到是整数了才结束。
      num = 0
      while True:
      data = input("请输入内容:")
      if data.isdecimal():
      num = int(data)
      break
      else:
      print("输入错误,请重新输入!")
    • for循环,一般应用在已知的循环数量的场景。

      1
      2
      3
      message = "来做点py交易呀"
      for char in message:
      print(char)
      1
      2
      for i in range(30):
      print(message[i])
    • break和continue关键字

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      message = "来做点py交易呀"
      for char in message:
      if char == "p":
      continue
      print(char)

      # 输出:



      y



      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      message = "来做点py交易呀"
      for char in message:
      if char == "p":
      break
      print(char)

      # 输出:



      1
      2
      3
      4
      5
      for i in range(5):
      print(i)# 0 1 2 3 4
      for j in range(3):
      break
      print(j) # 0 1 2 # 0 1 2 # 0 1 2 # 0 1 2 # 0 1 2

3.4 转换

1
2
3
num = 999
data = str(num)
print(data) # "999"
1
2
3
data_list = ["alex","eric",999]
data = str(data_list)
print(data) # '["alex","eric",999]'

一般情况下,只有整型转字符串才有意义。

3.5 其他

3.5.1 字符串不可被修改

1
2
3
4
name = "武沛齐"

name[1]
name[1:2]
1
2
3
4
num_list = [11,22,33]

num_list[0]
num_list[0] = 666

总结

  1. 整型在Python2和Python3中的区别?

  2. 进制之间的转换。

  3. 其他类型转换为布尔类型时,空和0为False,其他均为True。

  4. 条件语句中可自动化转换布尔类型来做判断。

    1
    2
    3
    4
    if "武沛齐":
    print(666)
    else:
    print(999)
  5. 字符串中常见的独有功能。

  6. 字符串中常见的公共功能。

  7. 字符串创建之后是不可以被修改的。

作业

  1. 请用代码实现如下进制的转换。

    1
    2
    3
    4
    5
    v1 = 675          # 请将v1转换为二进制(字符串类型)。

    v2 = "0b11000101" # 请将二进制v2转换为十进制(整型)

    v3 = "11000101" # 请将二进制v3转换为十进制(整型)
  2. 按要求实现

    现有 v1=123v2=456,请将这两个值转换为二进制,并将其二进制中的前缀 0b 去掉,然后将两个二进制拼接起来,最终再转换为整型(十进制)。

    例如:

    ​ 123 对应二进制为 “0b1111011” ,去除前缀0b之后的二进制为 “1111011”

    ​ 456 对应二进制为 “0b111001000” ,去除前缀0b之后的二进制为 “111001000”

    ​ 将两个二进制拼接起来的值为:”1111011111001000”,再将此值转换为整型为:63432

  3. 按要求实现

    现有 v1=123v2=456,请将这两个值转换为二进制,并将其二进制中的前缀 0b 去掉,再补足为2个字节(16位),然后将两个二进制拼接起来,最终再转换为整型(十进制)。

    例如:

    ​ 123 对应二进制为 “0b1111011” ,去除前缀0b之后的二进制为 “1111011” ,补足16位为 “00000000 01111011”

    ​ 456 对应二进制为 “0b111001000” ,去除前缀0b之后的二进制为 “111001000”,,补足16位为 “00000001 11001000”

    ​ 将两个二进制拼接起来的值为:”00000000 0111101100000001 11001000”,再将此值转换为整型为:8061384

  4. 列举你了解的那些数据类型的值转换为布尔值为False。

  5. 看代码写结果:

    1
    2
    3
    4
    if "":
    print(123)
    else:
    print(456)
    1
    2
    3
    4
    if 0:
    print(999)
    else:
    print(666)
    1
    2
    3
    4
    if "武沛齐":
    print(345)
    else:
    print(110)
  6. 让用户输入一段文本,请实现将文本中的敏感词 苍老师波波老师替换为 ***,最后并输入替换后的文本。

  7. 有变量name = “aleX leNb “ 完成如下操作:

    • 移除 name 变量对应的值两边的空格,并输出处理结果
    • 判断 name 变量是否以 “al” 开头,并输出结果(用切片 或 startswith实现)
    • 判断name变量是否以”Nb”结尾,并输出结果(用切片 或 endswith实现)
    • 将 name 变量对应的值中的 所有的”l” 替换为 “p”,并输出结果
    • 将 name 变量对应的值根据 所有的”l” 分割,并输出结果
    • 将name变量对应的值根据第一个”l”分割,并输出结果
    • 将 name 变量对应的值变大写,并输出结果
    • 将 name 变量对应的值变小写,并输出结果
  8. 如何实现字符串的翻转?

  9. 有字符串s = “123a4b5c”

    • 通过对s切片形成新的字符串 “123”
    • 通过对s切片形成新的字符串 “a4b”
    • 通过对s切片形成字符串 “c”
    • 通过对s切片形成字符串 “ba2”
  10. 使用while循环实现对字符串 message = “伤情最是晚凉天,憔悴厮人不堪言” 中每个字符进行输出。

  11. 使用for循环实现对字符串 message = “伤情最是晚凉天,憔悴厮人不堪言” 中每个字符进行输出。

  12. 使用for循环和range实现对字符串 message = “伤情最是晚凉天,憔悴厮人不堪言” 中每个字符进行倒叙输出。

  13. 使用for循环实现输出倒计时效果,例如:输出内容依次是:”倒计时3秒”,”倒计时2秒”,”倒计时1秒”。

  14. 让用户输入一段文本,请计算文本中 “浪” 出现的次数,并输入结果。

  15. 获取用户两次输入的内容,并提取其中的数字,然后实现数字的相加(转换为整型再相加):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    """
    要求:
    将num1中的的所有数字找到并拼接起来:1232312
    将num1中的的所有数字找到并拼接起来:1218323
    然后将两个数字进行相加。
    """
    num1 = input("请输入:") # asdfd123sf2312
    num2 = input("请输入:") # a12dfd183sf23
    # 请补充代码

day04 进制和编码

课程目标:讲解计算机中一些必备的常识知识,让学员了解一些常见名词背后的含义(重在理解)。

课程概要:

  • python代码的运行方式
  • 进制
  • 计算机中的单位
  • 编码

1.Python代码运行方式

  • 脚本式

    1
    python3 ~/PycharmProjects/day03/6.作业题讲解.py
  • 交互式

    1
    python3
    截屏2020-10-25 下午5.15.51

2.进制

计算机中底层所有的数据都是以 010101的形式存在(图片、文本、视频等)。

  • 二进制

    1
    2
    3
    0
    1
    10

    ![截屏2020-10-25 下午5.36.39](assets/截屏2020-10-25 下午5.36.39.png)

  • 八进制

  • 十进制

  • 十六进制

image-20201025174321969

2.1 进制转换

image-20201025180124802
1
2
3
4
5
6
7
8
v1 = bin(25) # 十进制转换为二进制
print(v1) # "0b11001"

v2 = oct(23) # 十进制转换为八进制
print(v2) # "0o27"

v3 = hex(28) # 十进制转换为十六进制
print(v3) # "0x1c"
1
2
3
4
5
i1 = int("0b11001",base=2) # 25

i2 = int("0o27",base=8) # 23

i3 = int("0x1c",base=16) # 28

3. 计算机中的单位

由于计算机中本质上所有的东西以为二进制存储和操作的,为了方便对于二进制值大小的表示,所以就搞了一些单位。

  • b(bit),位

    1
    2
    3
    4
    1,1位
    10,2位
    111,3位
    1001,4位
  • B(byte),字节

    1
    2
    3
    4
    8位是一个字节。

    10010110,1个字节
    10010110 10010110,2个字节
  • KB(kilobyte),千字节

    1
    2
    3
    4
    1024个字节就是1个千字节。

    10010110 11010110 10010111 .. ,1KB
    1KB = 1024B= 1024 * 8 b
  • M(Megabyte),兆

    1
    2
    1024KB就是1M
    1M= 1024KB = 1024 * 1024 B = 1024 * 1024 * 8 b
  • G(Gigabyte),千兆

    1
    2
    1024M就是1G
    1 G= 1024 M= 1024 *1024KB = 1024 * 1024 * 1024 B = 1024 * 1024 * 1024 * 8 b
  • T(Terabyte),万亿字节

    1
    1024个G就是1T
  • …其他更大单位 PB/EB/ZB/YB/BB/NB/DB 不再赘述。

做个小练习

  • 假设1个汉字需要2个字节(2B=16位来表示,如:1000101011001100),那么1G流量可以通过网络传输多少汉字呢?(计算机传输本质上也是二进制)

    1
    2
    3
    1G = 1024M = 1024 * 1024KB = 1024 * 1024 * 1024 B
    每个汉字需要2个字节表示
    1024 * 1024 * 1024/2 = ?
  • 假设1个汉字需要2个字节(2B=16位来表示,如:1000101011001100),那么500G硬盘可以存储多少个汉字?

    1
    2
    500G = 500 * 1024M = 500 * 1024 * 1024KB = 500 * 1024 * 1024 * 1024 B
    500 * 1024 * 1024 * 1024 / 2 = ?

4.编码

编码,文字和二进制之间的一个对照表。

4.1 ascii编码

ascii规定使用1个字节来表示字母与二进制的对应关系。

1
2
3
4
5
6
7
8
00000000
00000001 w
00000010 B
00000011 a
...
11111111

2**8 = 256

image-20201026111741235

image-20201026111752410

4.2 gb-2312编码

gb-2312编码,由国家信息标准委员会制作(1980年)。

gbk编码,对gb2312进行扩展,包含了中日韩等文字(1995年)。

在与二进制做对应关系时,由如下逻辑:

  • 单字节表示,用一个字节表示对应关系。2**8 = 256
  • 双字节表示,用两个字节表示对应关系。2**16 = 65536中可能性。

4.3 unicode

unicode也被称为万国码,为全球的每个文字都分配了一个码位(二进制表示)。

  • ucs2

    1
    2
    3
    4
    5
    6
    用固定的2个字节去表示一个文字。

    00000000 00000000 悟
    ...

    2**16 = 65535
  • ucs4

    1
    2
    3
    4
    用固定的4个字节去表示一个文字。
    00000000 00000000 00000000 00000000 无
    ...
    2**32 = 4294967296
1
2
3
4
5
6
7
8
9
10
11
文字     十六进制            二进制 
ȧ 0227 1000100111
ȧ 0227 00000010 00100111 ucs2
ȧ 0227 00000000 00000000 00000010 00100111 ucs4

乔 4E54 100111001010100
乔 4E54 01001110 01010100 ucs2
乔 4E54 00000000 00000000 01001110 01010100 ucs4

😆 1F606 11111011000000110
😆 1F606 00000000 00000001 11110110 00000110 ucs4

无论是ucs2和ucs4都有缺点:浪费空间?

1
2
3
4
文字     十六进制     二进制
A 0041 01000001
A 0041 00000000 01000001
A 0041 00000000 00000000 00000000 01000001

unicode的应用:在文件存储和网络传输时,不会直接使用unicode,而在内存中会unicode。

4.4 utf-8编码

包含所有文字和二进制的对应关系,全球应用最为广泛的一种编码(站在巨人的肩膀上功成名就)。

本质上:utf-8是对unicode的压缩,用尽量少的二进制去与文字进行对应。

1
2
3
4
5
unicode码位范围            utf-8      
0000 ~ 007F 用1个字节表示
0080 ~ 07FF 用2个字节表示
0800 ~ FFFF 用3个字节表示
10000 ~ 10FFFF 用4个字节表示

具体压缩的流程:

  • 第一步:选择转换模板

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
      码位范围(十六进制)                转换模板
    0000 ~ 007F 0XXXXXXX
    0080 ~ 07FF 110XXXXX 10XXXXXX
    0800 ~ FFFF 1110XXXX 10XXXXXX 10XXXXXX
    10000 ~ 10FFFF 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX

    例如:
    "B" 对应的unicode码位为 0042,那么他应该选择的一个模板。
    "ǣ" 对应的unicode码位为 01E3,则应该选择第二个模板。
    "武" 对应的unicode码位为 6B66,则应该选择第三个模板。
    "沛" 对应的unicode码位为 6C9B,则应该选择第三个模板。
    "齐" 对应的unicode码位为 9F50,则应该选择第三个模板。
    😆 对应的unicode码位为 1F606,则应该选择第四个模板。

    注意:一般中文都使用第三个模板(3个字节),这也就是平时大家说中文在utf-8中会占3个字节的原因了。
  • 第二步:在模板中填入数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    - "武"  ->  6B66  ->  110 101101 100110
    - 根据模板去套入数据
    1110XXXX 10XXXXXX 10XXXXXX
    1110XXXX 10XXXXXX 10100110
    1110XXXX 10101101 10100110
    11100110 10101101 10100110
    在UTF-8编码中 ”武“ 11100110 10101101 10100110

    - 😆 -> 1F606 -> 11111 011000 000110
    - 根据模板去套入数据
    11110000 10011111 10011000 10000110

4.5 Python相关的编码

1
2
字符串(str)     "alex媳妇叫铁锤"             unicode处理               一般在内存
字节(byte) b"alexfdsfdsdfskdfsd" utf-8编码 or gbk编码 一般用于文件或网络处理
1
2
3
4
v1 = "武"

v2 = "武".encode("utf-8")
v2 = "武".encode("gbk")

将一个字符串写入到一个文件中。

1
2
3
4
5
6
7
8
9
name = "嫂子热的满身大汗"
data = name.encode("utf-8")

# 打开一个文件
file_object = open("log.txt",mode="wb")
# 在文件中写内容
file_object.write(data)
# 关闭文件
file_object.close()

总结

本章的知识点属于理解为主,了解这些基础之后有利于后面知识点的学习,接下来对本节所有的知识点进行归纳总结:

  1. 计算机上所有的东西最终都会转换成为二进制再去运行。

  2. ascii编码、unicode字符集、utf-8编码本质上都是字符与二进制的关系。

    • ascii,字符和二进制的对照表。
    • unicode,字符和二进制(码位)的对照表。
    • utf-8,对unicode字符集的码位进行压缩处理,间接也维护了字符和二进制的对照表。
  3. ucs2和ucs4指的是使用多少个字节来表示unicode字符集的码位。

  4. 目前最广泛的编码为:utf-8,他可以表示所有的字符且存储或网络传输也不会浪费资源(对码位进行压缩了)。

  5. 二进制、八进制、十进制、十六进制其实就是进位的时机不同。

  6. 基于Python实现二进制、八进制、十进制、十六进制之间的转换。

  7. 一个字节8位

  8. 计算机中常见单位b/B/KB/M/G的关系。

  9. 汉字,用gbk编码需要用2个字节;用utf-8编码需要用3个字节。

  10. 基于Python实现将字符串转换为字节(utf-8编码)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 字符串类型
    name = "武沛齐"

    print(name) # 武沛齐
    # 字符串转换为字节类型
    data = name.encode("utf-8")
    print(data) # b'\xe6\xad\xa6\xe6\xb2\x9b\xe9\xbd\x90'

    # 把字节转换为字符串
    old = data.decode("utf-8")
    print(old)
  11. 基于Python实现将字符串转换为字节(gbk编码)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 字符串类型
    name = "武沛齐"
    print(name) # 武沛齐
    # 字符串转换为字节类型
    data = name.encode("gbk")
    # print(data) # b'\xe6\xad\xa6\xe6\xb2\x9b\xe9\xbd\x90' utf8,中文3个字节
    print(data) # b'\xce\xe4\xc5\xe6\xc6\xeb' gbk,中文2个字节

    # 把字节转换为字符串
    old = data.decode("gbk")
    print(old)