分类: Python技术

Python技术

使用 Docker 打包 Python 项目

使用 Docker 打包 Python 项目

1. 获取 Python 的镜像文件
项目的封装可以建立在已有镜像的基础上,在 Ubuntu 中可通过
docker pull python:3.6.8-slim-stretch # 这里选取了3.6版本
获取 Python 镜像

2. 配置 Dockerfile 文件
在 Python 项目的根目录新建 Dockerfile 文件,在 Dockerfile 文件中写入下面内容:

FROM python:3.6.8-slim-stretch

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install –no-cache-dir -r requirements.txt

COPY . .
ENTRYPOINT [“python”]
CMD [“./run.py”]

3. 创建镜像
创建镜像的命令为:
docker build -t python-project:1.0 .
需要注意的是*后面的 “.” 不能省略

4. 运行镜像
运行镜像的命令为:

docker run –rm -p 5000:5000 –name pyproject python-project:1.0
1
这行命令中的几个参数的含义分别如下

–rm:表示关闭命令行窗口时,运行该镜像的进程会同时关闭;
-p:用来设置端口映射,即把电脑主机的端口映射到 docker 容器中的端口,如何封装的是一个 web 服务,那么必须要设定端口映射;
–name:用来为运行的镜像设置别名,方便后面的调用
此外,可能会经常用到的参数还有:

-e:为镜像添加环境变量
-d:使 web 在后台持续运行
5. 常用命令总结
docker build -t pflask:1.0 . 创建镜像

docker images | grep python 查看镜像

docker run –rm -p 5000:5000 pflask:1.0 运行镜像

docker run –rm -p 5000:5000 -e env1=evn1 pflask:1.0 加入环境变量

docker run -d pflask:1.0 运行docker并守护进程

docker ps -a 查看当前正在运行的所有镜像

docker stop IMAGE_ID 根据 IMAGE_ID 停止镜像进程

docker rm -f IMAGE_ID 根据 IMAGE_ID 删除镜像进程

docker rmi IMAGE_ID 根据 IMAGE_ID 删除镜像

docker logs -f tname 根据助记符查看日志

ss -anp | grep 5000 从所有端口中过滤出 5000

curl -v “http://192.168.195.100:5000” 测试连接

cat hello.py 查看文件

a256sum hello.py 散列算法

Dockerfile内容
FROM python:3.6.8-slim-stretch
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install –no-cache-dir -r requirements.txt
COPY . .
ENTRYPOINT [“python”]
CMD [“/run.py”]

python项目打包部署

python项目打包部署

浏览了以上所有人的答案,结合我平常在项目中的实际经验,谈谈我们团队的Python部署与发布流程。
目前很多公司还是用着石器时代的部署方式,怎么做呢?

  1. 1. 本地写代码,可能还没有virtualenv环境,是的其实我的老东家就是这样的。
  2. 2. 写一个脚本,安装需要的依赖到系统global环境,比如说 MySQLdb,
  3. 可能还要用apt-get 或者 yum 安装 python-dev 等等系统依赖,然后用pip 安装Python依赖。
  4. 3. 提交到svn/git,然后在测试机器上拉代码下来,运行脚本安装完依赖后,
  5. 如果是一个web项目,那么可能会直接 python web.py 8080 测试一下会不会报错,
  6. 测试完几个接口发现没问题,关掉测试机器。
  7. 4. 在生产环境把代码拉下来,或者通过部署系统,这里的部署系统一般是一个web页面,
  8. 能够将svn/git 上的代码打包后执行某一个脚本,来完成相应的部署,
  9. 也有可能是直接在机器上执行:
  10. nohup python /path/to/python/main.py 2&1 > /dev/null &
  11. 就启动来这个进程,然后自己可能还有一些业务监控来定时的监控这个脚本的存活状态。
  12. 5. 这里可能nginx已经配置好,你发布的是一个Django应用,那么打开浏览器,
  13. 查看网页无误。

ok,大功告成,我已经是一位合格的工程师了,我所理解的Python发布或者所有的发布不都是这样么,大家都是这样的
如果你躺枪了,很好,我喜欢。
让我们看看这里的步骤缺少什么,我不仅仅从发布部署来说,我们谈谈一个理想的开发测试部署流程应该是怎样的。
1. 你应该有一个与线上环境一模一样的测试/开发机器,这里说的是系统环境而不是物理环境,比如说内核版本,Python版本,libc 版本,gcc 版本,shell 的环境等等都应该跟线上环境一样,这是保证代码质量的*关,或许不应该叫做代码质量而是工程质量。有人可能会用eclipse或者其他的云云开发IDE,OK,没问题,保证系统是一样的,这里有点难。
2. 你应该有一个virtualenv环境,因为你的开发机器可能有多个项目,而且可能因为有些依赖版本问题,导致你发现不同的项目可能对同一个模块有不同版本的依赖,那么请你准备一个virtualenv环境,这是Python开发人员必备的。
3. 你应该把代码提交到git, 但是提交之前,你应该运行一般单元测试,单元测试包含两个部分,一是对整个项目里的所有代码有一个代码静态检查,例如pylint和pep8,第二部分是自动运行你的测试用例,因为你的一个小改动可能会影响到其他模块,而这一点你开发的时候没有意识到或者说你影响的模块不是你写的,这一点会让你写的代码更健壮,同时你更有信心对现有代码做新需求开发或者变动,这里,你可以把你的测试用例启动脚本活着命令加到git hook,这样每次commit的时候都会启动测试程序。
4. OK,保证测试用例通过后,你应该对这次写的代码很有信心了,那接下来就是把代码发布到测试环境。怎么做呢?

一个起码看起来合格的Python项目,大体上代码构建的目录应该是下面这样的,请参考《以正确的方式开源Python项目》oschina.net/translate/o
所有的代码文件都在pro中,其他都是项目发布于部署使用到的

  1. -rwxr-xr-x 8 root root 4096 Sep 16 22:06 .git/
  2. -rw-r–r– 1 root root 434 Aug 10 16:00 .gitignore
  3. -rw-r–r– 1 root root 166 Jul 26 11:49 AUTHORS.md
  4. -rw-r–r– 1 root root 149 Aug 10 16:49 AUTHORS.rst
  5. -rw-r–r– 1 root root 0 Aug 10 16:49 CONTRIBUTING.rst
  6. -rw-r–r– 1 root root 245 Jul 26 11:59 HISTORY.md
  7. -rw-r–r– 1 root root 100 Aug 10 16:49 HISTORY.rst
  8. -rw-r–r– 1 root root 1453 Aug 10 16:49 LICENSE
  9. -rw-r–r– 1 root root 221 Aug 10 16:49 MANIFEST.in
  10. -rw-r–r– 1 root root 2964 Sep 12 11:19 Makefile
  11. -rw-r–r– 1 root root 239 Jul 26 11:49 README.md
  12. -rw-r–r– 1 root root 161 Aug 10 16:49 README.rst
  13. drwxr-xr-x 2 root root 4096 Sep 16 22:06 conf/
  14. drwxr-xr-x 2 root root 4096 Jul 26 11:59 deb-scripts/
  15. drwxr-xr-x 2 root root 4096 Aug 23 15:52 doc/
  16. drwxr-xr-x 8 root root 4096 Jan 16 13:12 pro/
  17. -rw-r–r– 1 root root 67 Aug 10 16:49 requirements-dev.txt
  18. -rw-r–r– 1 root root 284 Sep 2 15:34 requirements.txt
  19. -rw-r–r– 1 root root 22 Aug 10 16:49 setup.cfg
  20. -rwxr-xr-x 1 root root 1406 Aug 10 16:49 setup.py*
  21. drwxr-xr-x 4 root root 4096 Sep 2 17:30 utils/

我来解释一下这里的几个主要文件的作用. 这里的目录结构可能也跟我们团队的命名习惯有关.

  1. conf/
  2. conf/api.conf // 项目配置
  3. conf/logrotate.conf // 日志轮转配置
  4. conf/uwsgi.ini // uwsgi 配置
  5. conf/pro.upstart // upstart 文件
  6. conf/paste.ini // paste 是用来部署uwsgi的一个中间件
  7. conf/pro.cron // 这里是crontab配置
  8. conf/pro // 其他配置,可能是允许执行的sudo命令等

deb-scripts/ 包含三个文件,这里我们说debian系统打包,Redhat 打 rpm 也同理。

  1. eb-scripts/before-remove.sh // 卸载前执行的脚本
  2. deb-scripts/before-install.sh // 安装前执行的脚本
  3. deb-scripts/after-install.sh // 安装后执行的脚本

doc/ 应该是项目的文档,这里推荐用sphinx 生成文档或者你自己写markdown也可以。

utils/ 下面包含了你可能需要用到的启动依赖,但是又不想每次都远程下载,且不是Python本身的依赖而是环境依赖,好吧,我们在utils下面放了一个virtualenv,执行virtualenv 就可以在本地生成一个virtualenv 环境了, 还有打包deb的脚本

Makefile 文件包含了很多命令,比如:

  1. make test // 执行单元测试和静态检查
  2. make lint // 执行 pylint
  3. make pep // 执行pep8 检查

一系列你经常用到的功能,都可以放到Makefile

2. 你应该把你的代码打成一个安装包,而不是一个压缩包,因为你要发布的是一个服务而不是一个模块,那么请你打成deb或者rpm包。
让我们看下打包代码:

  1. #!/bin/sh
  2. set -e
  3. … // 省略了变量部分
  4. if [ ! -d wheelhouse ]; then
  5. make wheel
  6. fi
  7. fpm -t deb -s dir -n “$PKG_NAME” -v “$VERSION” –prefix “$DEST_DIR” -f \
  8. –depends make \
  9. -x ‘*__pycache__’ \
  10. -x ‘*.pyc’ \
  11. -x ‘*.pyo’ \
  12. -x ‘*.deb’ \
  13. –before-install deb-scripts/before-install.sh \
  14. –after-install deb-scripts/after-install.sh \
  15. –before-remove deb-scripts/before-remove.sh \
  16. Makefile HISTORY.rst LICENSE AUTHORS.rst CONTRIBUTING.rst setup.cfg \
  17. MANIFEST.in README.rst setup.py utils requirements-dev.txt requirements.txt wheelhouse conf \
  18. $PYTHON_MODULES

一目了然,我们会把依赖打到 wheelhouse 里面,然后把 wheelhouse 一同打包到 deb 包,这里使用了 fpm 这个打包工具,需要安装ruby gem 来安装。
然后在你的 make install 命令可以包含下面这个:

pip install --use-wheel --no-index --find-links=wheelhouse -r requirement.txt

在你的 deb-scirpt/after-install.sh 里面,这个脚本会在deb包安装完成后执行,你应该在这里完成你的环境依赖安装还有你配置文件的加载,crontab的配置等,一个简单的脚本应该像下面这样:

  1. #!/bin/sh
  2. set -e
  3. PREFIX=${PREFIX:-/opt/pro}
  4. REPODIR=${REPODIR:-/data2/pro}
  5. LOGDIR=${LOGDIR:-/data2/log/pro}
  6. IMAGE_CACHE=${IMAGE_CACHE:-/data2/image/cache}
  7. RUN_AS_USER=www-data
  8. mkdir -p $REPODIR
  9. mkdir -p $LOGDIR
  10. mkdir -p $IMAGE_CACHE
  11. chown -R “$RUN_AS_USER”:”$RUN_AS_USER” $REPODIR
  12. chown -R “$RUN_AS_USER”:”$RUN_AS_USER” $LOGDIR
  13. chown -R “$RUN_AS_USER”:”$RUN_AS_USER” $IMAGE_CACHE
  14. cd “$PREFIX”
  15. # this project does not require install.
  16. # make bootstrap install
  17. make bootstrap
  18. # install crontab, upstart job, logrotate config etc
  19. install conf/pro.upstart /etc/init/pro.conf
  20. install conf/logrotate.conf /etc/logrotate.d/pro
  21. install -o root -m 0440 conf/pro /etc/sudoers.d/pro
  22. install -o root -m 0644 conf/pro.cron /etc/cron.d/pro
  23. start pro || true

3. *后一步就是 start pro
这里使用upstart启动你的应用,你应该把你的应用交给系统而不是你自己
所以在 after-install 中,你需要把pro.conf这个文件安装到 upstart 目录.
4. 以上的所有步骤,还在你的本地,你需要做的是把代码发布到生产环境。这里你需要把你的deb包上传到私有apt源,然后就是发布到正式环境了。
5. 发布有几种方式:

  1. 1. 在机器上直接执行 apt-get install pro(不推荐)
  2. 2. 利用fabric执行远程命令发布(次不推荐)
  3. 3. 利用puppet发布(推荐)

前两者无需多说,利用puppet发布,可以使你的发布更佳规范,同时也可以对配置做更规范的管理,一些系统依赖,不是Python的而是系统本身的,比如有时候出现libpcre 这样的二进制系统依赖的时候,你应该利用puppet安装这些依赖,而不是手动去执行安装, 具体的 puppet 相关就不细说了。

Linux部署Python项目

一、LNM+Python Djiango +uwsgi +redis 部署Python项目
(一)导入项目以及项目文件修改
上传压缩文件以及数据库到/opt (注意要把数据库建成sql文件上传)

然后解压上传项目文件

进入核心目录(两次cd mybbs) 注意:自己的项目名

进入设置文件(vim settings)%title插图%num

进入根目录下面,配置文件(注意:配置文件的信息要与自己的项目一致)

vim /etc/nginx/conf.d/py.conf
server {
listen 80;
server_name 10.0.0.100;
client_max_body_size 100M;

location /static {
alias /code/BBS/static/;
}

location /media {
alias /code/BBS/media;
}

location / {
index index.html;
include uwsgi_params;
uwsgi_pass 127.0.0.1:9090;
uwsgi_param UWSGI_SCRIPT BBS.wsgi;
uwsgi_param UWSGI_CHDIR /code/BBS;
}

(二)数据库的操作
/etc/init.d/mysqld restart 启动数据库
systemctl start mysqld
systemctl restart mysqld 重启数据库
netstat -tulnp |grep 3306 查看数据库是否启动

注意:如果还是进不去就用数据库登录的账户名和密码

grant all on *.* to root@’10.0.0.%’ identified by ‘123’; mysql -uroot -p123
1
进入数据库以后腰创建一个bbs用户:

5.8版本下创建和授予权限可以一起,用户不在自动创建

5.7下要先创建用户,后授予权限

grant select,update,delete ,insert on bbs.* to bbs@’10.0.0.%’ identified by ‘123’;
mysql -ubbs -p123 -h10.0.0.100 bbs用户登录

drop database bbs; 删除数据库里面的表
create database bbs charset utf8mb4; 再创建一个bbs数据库,注意编码格式要和数据库文件的编码格式一致
use bbs; 使用创建库
use bbs; 导入指定目录下的项目数据库
show tables; 查看导入结果

二MySQL用户操作
用户定义 : USERNAME@‘白名单’
白名单:主机域IP地址
root@‘localhost’ 只允许本机的root用户进行访问
root@‘10.0.0.110’ 只允许root用户通过10.0.0.110地址进行访问
root@‘10.0.0.%’ 允许10.0.0.N网段的root用户进行访问
root@‘10.0.0.0/255.255.240.0’
root@‘10.0.0.5%’ 允许10.0.0.5N ip地址的root用户进行访问
root@‘%’ 允许所有root用户进行访问

1.权限操作介绍
grant all 除root用户外的*高权限
grant selent,update,insert 生产环境下,通常的项目权限
将del操作,替换成update操作 – 使用状态链,1,0表示可否可视
注意:也就是新创建一个新的字段,在查询的时候根据这个新的字段进行查询,需要定期清理字段的固定属性
grant select,update,delete ,insert on bbs.* to bbs@’10.0.0.%’ identified by ‘123’;
bbs.*库的增删改查权限,给予bbs@’10.0.0.%’ 进行链接,并创建用户(创建用户并授权操作,仅限mysql5.7版本);密码为123
1
2
三.Nginx的配置
查看nginx是否启动:systemctl status nginx
启动nginx:systemctl restart nginx
在项目的一层目录下面配置:

vim /etc/nginx/conf.d/py.conf
server {
listen 80;
server_name 10.0.0.100;
client_max_body_size 100M;
location /static {
alias /opt/mybbs/static/;
}
location /media {
alias /opt/mybbs/media;
}
location / {
index index.html;
include uwsgi_params;
uwsgi_pass 127.0.0.1:9090;
uwsgi_param UWSGI_SCRIPT mybbs.wsgi;
uwsgi_param UWSGI_CHDIR /opt/mybbs;
}

*后启动uginx即可:uwsgi –ini uwsgi.ini &

注意:文件uwsgi.ini文件目录

四 uwsgi的配置
在项目的一层目录下面配置:

ps -ef |grep uwsgi 查看所有uwsgi的进程
kill -9 ps -ef |grep uwsgi|awk {‘print $2’} 强制杀死已有uwsgi进程
vim uwsgi.ini 在项目目录内生成配置文件
[uwsgi]
socket = 127.0.0.1:9090
master = true
workers = 2
reload-mercy = 10
vacuum = true
max-requests = 1000
limit-as = 512
buffer-size = 30000
uwsgi –ini /opt/mybbs/uwsgi.ini & 后台启动uwsgi进程,注意配置文件路径
systemctl restart nginx 重启nginx

python项目.gitignore配置

python项目.gitignore配置

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

python–RGB转HSV

python–RGB转HSV

RGB:颜色空间相对简单,也*为普遍,就分为三个颜色通道,分别为红色,绿色,蓝色这三种基本色调的值,然后将这三个颜色融合在一起,也就成为一种颜色。

HSV:是个六棱锥模型,这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)。

为什么使用HSV去判断色差:

用RGB比较颜色之间的相似度时,往往一个通道的一点改变,会导致*后融合在一起的颜色发生巨大变化,而如果三个通道的同时改变,却只会使*后的明暗发生变化,色调并不会产生巨大变化。
RGB TO HSV
def rgb2hsv(r, g, b):
r, g, b = r/255.0, g/255.0, b/255.0
mx = max(r, g, b)
mn = min(r, g, b)
df = mx-mn
if mx == mn:
h = 0
elif mx == r:
h = (60 * ((g-b)/df) + 360) % 360
elif mx == g:
h = (60 * ((b-r)/df) + 120) % 360
elif mx == b:
h = (60 * ((r-g)/df) + 240) % 360
if mx == 0:
s = 0
else:
s = df/mx
v = mx
return h, s, v

计算HSV的距离

def HSVDistance(hsv_1,hsv_2):
H_1,S_1,V_1 = hsv_1
H_2,S_2,V_2 = hsv_2
R=100
angle=30
h = R * math.cos(angle / 180 * math.pi)
r = R * math.sin(angle / 180 * math.pi)
x1 = r * V_1 * S_1 * math.cos(H_1 / 180 * math.pi);
y1 = r * V_1 * S_1 * math.sin(H_1 / 180 * math.pi);
z1 = h * (1 – V_1);
x2 = r * V_2 * S_2 * math.cos(H_2 / 180 * math.pi);
y2 = r * V_2 * S_2 * math.sin(H_2 / 180 * math.pi);
z2 = h * (1 – V_2);
dx = x1 – x2;
dy = y1 – y2;
dz = z1 – z2;
return math.sqrt(dx * dx + dy * dy + dz * dz)

HSV To RGB

def hsv2rgb(h, s, v):
h = float(h)
s = float(s)
v = float(v)
h60 = h / 60.0
h60f = math.floor(h60)
hi = int(h60f) % 6
f = h60 – h60f
p = v * (1 – s)
q = v * (1 – f * s)
t = v * (1 – (1 – f) * s)
r, g, b = 0, 0, 0
if hi == 0: r, g, b = v, t, p
elif hi == 1: r, g, b = q, v, p
elif hi == 2: r, g, b = p, v, t
elif hi == 3: r, g, b = p, q, v
elif hi == 4: r, g, b = t, p, v
elif hi == 5: r, g, b = v, p, q
r, g, b = int(r * 255), int(g * 255), int(b * 255)
return r, g, b

线程共享全局变量出错

线程共享全局变量出错

解决办法
多任务编程
线程同步: 保证同一时刻只能有一个线程去操作全局变量 。
同步: 就是协同步调,按预定的先后次序进行运行。
线程同步的两种方式:
1、线程等待(join)
2、互斥锁

线程共享全局变量出错的两种解决办法:

方法一:线程等待(join)
利用线程等待,即子线程.join()的方法让当前线程(主线程)等待添加数据的线程执行完成后代码在继续执行

import threading

# 定义一个全局变量
g_num = 0

def first_data():
for i in range(1000000):
# 声明全局变量
global g_num
g_num += 1

print(‘*个:’, g_num)

def second_data():
for i in range(1000000):
# 声明全局变量
global g_num
g_num += 1

print(‘第二个:’, g_num)

if __name__ == ‘__main__’:
# 创建*个子线程
first_thread = threading.Thread(target=first_data)

# 创建第二个子线程
second_thread = threading.Thread(target=second_data)

first_thread.start()

# 让当前线程(主线程)等待添加数据的线程执行完成后代码再继续执行
first_thread.join()
second_thread.start()

*个: 1000000
第二个: 2000000

方法二:互斥锁
import threading

# 创建锁, Lock 本质上是一个函数,通过调用这个函数可以获取一把互斥锁
lock = threading.Lock()
# 定义一个全局变量
g_num = 0

def first_data():
# 上锁
lock.acquire()
for i in range(1000000):
# 声明全局变量
global g_num
g_num += 1

print(‘*个:’, g_num)
# 释放锁
lock.release()

def second_data():
# 上锁
lock.acquire()
for i in range(1000000):
# 声明全局变量
global g_num
g_num += 1

print(‘第二个:’, g_num)
# 释放锁
lock.release()

if __name__ == ‘__main__’:
# 创建*个子线程
first_thread = threading.Thread(target=first_data)
# 创建第二个子线程
second_thread = threading.Thread(target=second_data)

first_thread.start()
second_thread.start()

# 线程等待和互斥锁都是把多任务改成单任务去执行,保证了数据的准确性,但是执行性能会下降.

拓展:使用互斥锁的时候要注意死锁问题。
死锁:等待对方释放锁的状态称为死锁。后面的代码无法正常执行。
下面举个例子:

# 目的: 根据下标在列表中取值, 保证同一时刻只能有一个线程去取值
import threading

# 创建锁
lock = threading.Lock()

def get_value(index):
# 上锁
lock.acquire()
list1 = [1, 3, 5]
# 判断下标是否越界
if index >= len(list1):
print(‘下标越界’, index)
# return 会退出当前函数, 退出前需要释放锁
# lock.release() # 注意要释放锁
return
value = list1[index]
print(value)
# 释放锁
lock.release()

if __name__ == ‘__main__’:
# 循环创建多个子线程
for i in range(10):
sub_thread = threading.Thread(target=get_value, args=(i,))
sub_thread.start()

return前未释放锁:

下标越界 3
return前释放锁:

下标越界 3
下标越界 4
下标越界 5
下标越界 6
下标越界 7
下标越界 8
下标越界 9

python计算运行时间和使用内存

python计算运行时间和使用内存
python计算运行时间
from time import time

start_time = time()
algorithm#需要计算的算法步骤
end_time=time()
elapsed=end_time-start_time
print(elapsed)

python计算运行内存
import os
import psutil

def show_info(self):
#计算消耗内存
pid = os.getpid()
# 模块名比较容易理解:获得当前进程的pid
p = psutil.Process(pid)
# 根据pid找到进程,进而找到占用的内存值
info = p.memory_full_info()
memory = info.uss / 1024 / 1024
return memory
# print(f'{start} 一共占用{memory:.2f}MB’)

start_memory=l.show_info()
algorithm#需要计算的算法步骤
end_memory=l.show_info()
print(f’一共占用{end_memory – start_memory}MB’)

python之闭包函数

python之闭包函数

一、大前提
闭包函数 = 名称空间与作用域+函数嵌套+函数对象
核心点:名字的查找关系是以函数定义阶段为准

二、什么是闭包函数
‘闭’函数指的是该函数是内嵌函数
‘包’函数指的是该函数包含对外层作用域名称的引用(不是对全局作用域)

闭包函数之名称空间与作用域的应用+函数嵌套

def f1():
def f2():
pass
1
2
3
#闭包函数之名称空间与作用域的应用+函数嵌套
def f1():
x = 3333
def f2():
print(x)
f2()

x = 111
def bar():
x = 4444
f1()

def foo():
x = 2222
bar()

foo() # 结果为3333,名称空间!!要一眼看出答案
#该函数仅做到了‘闭’

闭包函数之函数对象

def f1():
x = 333
def f2():
print(‘函数f2’,x)
return f2

f = f1()
print(f)
f()

def foo():
x = 555
f()

foo()

三、闭包函数的应用场景
两种为函数体传参的方式
方式一:直接把函数体需要的参数定义成形参

def f2(x):
print(x)

f2(1)
f2(2)
f2(3)

方式二:

def f1(x):
#x = 3
def f2():
print(x)

return f2
x = f1(1)
print(x)
x()

基础语法练习2

基础语法练习2

实验3-1
编写程序,输入一个大于2的自然数,输出小于该数字的所有素数组成的集合。
(素数,即质数,指除了1和它本身以外不再有其他因数的自然数。)

import math
n = int(input())
a = set()
for i in range(2, n):
flag = 0
for j in range(2, int(math.sqrt(i)+1)):
if i % j == 0:
flag = 1
break
if flag == 0:
a.add(i)
print(a)

可以使用大括号 { } 或者 set() 函数创建集合。注意k:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
range(2,n),左闭右开,默认步长为1。
判断一个数n是否为素数,只需找因数到√n即可,无需全部遍历。
运行结果
20
{2, 3, 5, 7, 11, 13, 17, 19}

实验3-2
编写程序,输入一个字符串,输出其中出现次数*大的字符及其出现的次数。

s = input()
result = []
mark = {}
for i in s:
if i not in mark:
mark[i] = 1
else:
mark[i] += 1
for key,value in mark.items():
if value == max(mark.values()):
result.append(key)
print(‘出现次数*多的字符 :’,result)
print(‘出现次数 :’,max(mark.values()))

可能存在多个字符出现的*大次数相同,于是用列表result[]存储结果。
用字典mark{}记录出现次数,键为字符,值为出现次数。
items() 方法以列表返回可遍历的(键, 值) 元组数组。values()方法以列表返回字典中的所有值,keys()方法以列表返回字典中的所有键。
运行结果
hello python
出现次数*多的字符 : [‘h’, ‘l’, ‘o’]
出现次数 : 2

实验3-3
制作一个“通讯簿”,其可以存储姓名、电话、邮箱,请编写程序完成这个“通讯簿”的增删改查功能,并且实现文件存储功能。
(仅实现了基础的增删改查功能,未进行输入判断等具体功能)

import json
import os
#用json文件存储字典数据
#以姓名作为键,列表([电话,邮箱])作为值
print(‘>>>添加-1 删除-2 修改-3 查询-4’)
while True:
x = input(‘>>>请输入要进行的操作:’)
#没有文件则新建
if not os.path.exists(‘phonebook.json’):
with open(‘phonebook.json’, ‘w’, encoding=’utf-8′) as file:
phonebook = {}
json.dump(phonebook, file, indent=4, ensure_ascii=False)
#将文件中的数据读到字典phonebook中
with open(‘phonebook.json’, ‘r’, encoding=’utf-8′) as file:
phonebook = dict(json.load(file))
#添加
if x == ‘1’:
name = input(‘姓名:’)
tel = input(‘电话:’)
email = input(‘邮箱:’)
phonebook[name] = [tel, email]
print(‘添加成功!’)
#删除
elif x == ‘2’:
name = input(‘请输入要删除的联系人:’)
if name in phonebook.keys():
del phonebook[name]
print(‘删除成功!’)
else:
print(‘查无此人!’)
#修改
elif x == ‘3’:
name = input(‘请输入要修改的联系人:’)
if name in phonebook.keys():
tel = input(‘电话:’)
email = input(‘邮箱:’)
phonebook[name] = [tel, email]
print(‘修改成功!’)
else:
print(‘查无此人!’)
#查找
elif x == ‘4’:
name = input(‘请输入要查找的联系人:’)
if name in phonebook.keys():
print(‘电话:’ + phonebook[name][0])
print(‘邮箱:’ + phonebook[name][1])
else:
print(‘查无此人!’)
else:
print(‘命令错误!请重新输入’)
print(‘>>>添加-1 删除-2 修改-3 查询-4’)
#将phonebook中的数据写入文件中
with open(‘phonebook.json’, ‘w’, encoding=’utf-8′) as file:
json.dump(phonebook, file, indent=4, ensure_ascii=False)

indent = 4:对json进行数据格式化输出。
json.dumps序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False。
运行数据
1
张三
1321234567
13212345678@qq.com
3
张三
1321234555
13212345555@qq.com
4
张三
2
张三
4
张三
5

运行结果
>>>添加-1 删除-2 修改-3 查询-4
>>>请输入要进行的操作:1
姓名:张三
电话:1321234567
邮箱:13212345678@qq.com
添加成功!
>>>请输入要进行的操作:3
请输入要修改的联系人:张三
电话:1321234555
邮箱:13212345555@qq.com
修改成功!
>>>请输入要进行的操作:4
请输入要查找的联系人:张三
电话:1321234555
邮箱:13212345555@qq.com
>>>请输入要进行的操作:2
请输入要删除的联系人:张三
删除成功!
>>>请输入要进行的操作:4
请输入要查找的联系人:张三
查无此人!
>>>请输入要进行的操作:5
命令错误!请重新输入
>>>添加-1 删除-2 修改-3 查询-4
>>>请输入要进行的操作:

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速