Python模块学习 - fabric
简介
fabric是一个Python的库,同时它也是一个命令行工具。使用fabric提供的命令行工具,可以很方便地执行应用部署和系统管理等操作。
fabric依赖于paramiko进行ssh交互,fabric的设计思路是通过几个API接口来完成所有的部署,因此fabric对系统管理操作进行了简单的封装,比如执行命令,上传文件,并行操作和异常处理等。
#安装
# fabric3支持python3
pip3 install fabric3
由于fabric比较特殊它还是一个命令行工具,可以通过help进行命令的了解
pyvip@Vip:~/utils$ fab --help
Usage: fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ... Options:
-h, --help show this help message and exit
-d NAME, --display=NAME
print detailed info about command NAME
-F FORMAT, --list-format=FORMAT
formats --list, choices: short, normal, nested
-I, --initial-password-prompt
Force password prompt up-front
--initial-sudo-password-prompt
Force sudo password prompt up-front
-l, --list print list of possible commands and exit
--set=KEY=VALUE,... comma separated KEY=VALUE pairs to set Fab env vars
……
错误的提示
# fab -help
Traceback (most recent call last):
File "/usr/local/python3/bin/fab", line 11, in <module>
load_entry_point('Fabric==1.14.0', 'console_scripts', 'fab')()
File "/usr/local/python3/lib/python3.6/site-packages/pkg_resources/__init__.py", line 480, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/local/python3/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2693, in load_entry_point
return ep.load()
File "/usr/local/python3/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2324, in load
return self.resolve()
File "/usr/local/python3/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2330, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
File "/usr/local/python3/lib/python3.6/site-packages/fabric/main.py", line 13, in <module>
from operator import isMappingType
ImportError: cannot import name 'isMappingType' # 说明你使用的python版本可fabric版本不同,python3 安装时使用的是fabric3
入门使用
fabric的典型使用方式就是,创建一个Python文件,该文件包含一到多个函数,然后使用fab命令调用这些函数。这些函数在fabric中成为task,下面是一个例子
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.utils import abort
from fabric.colors import * env.hosts = ['192.168.5.128']
env.port = 22
env.user = 'root'
env.password = 'mysql123' def hostname():
run('hostname') def ls(path='.'):
run('ls {0}'.format(path)) def tail(path='/etc/pas', line=10):
run('tail -n {0} {1}'.format(line, path)) def hello():
with settings(hide('everything'),warn_only=True): # 关闭显示
result = run('anetstat -lntup|grep -w 25')
print(result) # 命令执行的结果
print(result.return_code) # 返回码,0表示正确执行,1表示错误
print(result.failed)
PS:fab命令执行时,默认引用一个名为fabfile.py的文件,我们也可以通过-f来进行指定(文件名不能为abc.py,会冲突).
这里使用了三个fabric的封装:
- run:用于执行远程命令的封装
- sudo:以sudo权限执行远程命令
- env:保存用户配置的字典(保存了相关的配置,比如登录用户名env.user,密码env.password,端口env.port等,如果没有指定用户名那么默认使用当前用户,端口使用22)
1、获取任务列表
pyvip@Vip:~/utils$ fab -f fab_utils.py --list
Available commands: hello
hostname
ls
tail pyvip@Vip:~/utils$ fab -f fab_utils.py --list
Available commands: hello
hostname
ls
tail
# 2、执行hostname函数
pyvip@Vip:~/utils$ fab -f fab_utils.py hostname
[192.168.5.128] Executing task 'hostname'
[192.168.5.128] run: hostname
[192.168.5.128] out: china
[192.168.5.128] out: Done.
Disconnecting from 192.168.5.128... done.
# 3、多个参数的情况
pyvip@Vip:~/utils$ fab -f fab_utils.py ls:/
[192.168.5.128] Executing task 'ls'
[192.168.5.128] run: ls /
[192.168.5.128] out: bin boot data dev etc home lib lib64 lost+found media misc mnt net opt proc root sbin selinux srv sys tmp usr var
[192.168.5.128] out: Done.
Disconnecting from 192.168.5.128... done.
需要注意的是:
- 一次可以多个task,按照顺序执行: fab -f fab_util.py hostname ls
- 给task传递参数使用task:参数,多个参数按照位置进行传递(和Python相同,对于关键字的参数可以,在命令行中指定:fab ls:path=/home)
fabric的命令行参数
fab命令作为fabric程序的入口提供了,丰富的参数调用.
# -l:查看task列表 # -f:指定fab的入口文件,默认是fabfile.py
# -g:指定网管设备,比如堡垒机环境下,填写堡垒机的IP
# -H:在命令行指定目标服务器,用逗号分隔多个服务器
# -P:以并行方式运行任务,默认为串行
# -R:以角色区分不同的服务
# -t:连接超时的时间,以秒为单位
# -w:命令执行失败时的警告,默认是终止任务
# -- Fabric参数,其他包含fabric脚本的中的参数的快捷操作,比如--user,--port,或者直接跟要执行的Linux命令
如下例子,不写一行代码获取所有主机的ip地址
pyvip@Vip:~/utils$ fab -H 192.168.5.128 --port 22 --user='root' --password='mysql123' -- 'ip a '
[192.168.5.128] Executing task '<remainder>'
[192.168.5.128] run: ip a
[192.168.5.128] out: 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
[192.168.5.128] out: link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
[192.168.5.128] out: inet 127.0.0.1/8 scope host lo
[192.168.5.128] out: inet6 ::1/128 scope host
[192.168.5.128] out: valid_lft forever preferred_lft forever
[192.168.5.128] out: 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
[192.168.5.128] out: link/ether 00:0c:29:96:0a:a0 brd ff:ff:ff:ff:ff:ff
[192.168.5.128] out: inet 192.168.5.128/24 brd 192.168.5.255 scope global eth0
[192.168.5.128] out: inet6 fe80::20c:29ff:fe96:aa0/64 scope link
[192.168.5.128] out: valid_lft forever preferred_lft forever
[192.168.5.128] out: 3: pan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN
[192.168.5.128] out: link/ether 7a:4d:51:6c:c2:cd brd ff:ff:ff:ff:ff:ff
常用的对象和方法介绍
介绍fabric中的env对象,以及其他的比如执行命令模块,上传文件等。
fabric中的env
env是一个全局唯一的字典,保存了Fabric所有的配置,在Fabric的实现中,他是一个_AttributeDict()对象,之所以封装成_AttributeDict()对象,是覆盖了__getattr__和__setattr__,使我们可以使用“对象.属性=值”的方式,操作字典。
我们可以通过源码的方式,查看env的配置参数,或者使用如下方式查看:
import json
from fabric.api import env print(json.dumps(env, indent=3)) def hell(name='world'):
print('hello %s' % name) -----------------------------------------------
结果 pyvip@Vip:~/utils$ fab -f fab_utils.py -l
{
"show": null,
"": true,
"sudo_user": null,
"default_port": "22",
"key_filename": null,
"path": "",
"hosts": [
"192.168.5.128"
],
"host_string": null,
"ok_ret_codes": [
0
],
"always_use_pty": true,
"fabfile": "fab_utils.py",
"echo_stdin": true,
"again_prompt": "Sorry, try again.",
"command": null,
"forward_agent": false,
"command_prefixes": [],
"cwd": "",
"connection_attempts": 1,
"linewise": false,
"gateway": null,
"use_exceptions_for": {
"network": false
……
常用的env配置如下:
- env.hosts:定义目标服务器列表
- env.exclude_hosts:排除特定的服务器
- env.user SSH:到远程服务器的用户名
- env.port:远程服务器的端口号
- env.key_filename:私钥文件的位置
- env.password SSH:到远程服务器的密码
针对不同主机不同密码的情况,可以使用如下的方式:
env.hosts = [
'root@192.168.10.201:22',
'root@192.168.10.202:22',
'root@192.168.10.203:22'
]
env.passwords = {
'root@192.168.10.201:22':'123456201',
'root@192.168.10.202:22':'123456202',
'root@192.168.10.203:22':'123456203'
fabric提供的命令
run():在远程服务器上执行Linux命令,还有一个重要的参数pty,如果我们执行命令以后需要有一个常驻的服务进程,那么就需要设置pty=False,避免因为Fabric退出导致进程的退出
run('service mysqld start',pty=False)
PS:执行完毕会返回输出的信息,我们可以定义变量接受,同时这个返回信息有一个方法return_code,当返回的是正确执行的结果时code为0,否则不为0
def hello(): with settings(hide('everything'),warn_only=True): # 关闭显示
result = run('anetstat -lntup|grep -w 25')
print(result) # 命令执行的结果
print(result.return_code) # 返回码,0表示正确执行,1表示错误
结果
[192.168.5.128] Executing task 'hello'
/bin/bash: anetstat: command not found
1
True Done.
Disconnecting from 192.168.5.128... done.
sudo():与run类似,使用管理员权限在远程服务器上执行shell命令,还有一个重要的参数pty,如果我们执行命令以后需要有一个常驻的服务进程,那么就需要设置pty=False,避免因为Fabric退出导致进程的退出。
local():用以执行本地命令,返回要执行的命令,local是对Python的Subprocess模块的封装,更负载的功能可以直接使用Subprocess模块,包含capture参数,默认为False,表示subprocess输出的信息进行显示,如果不想显示,那么指定capture=True即可
ef test():
result = local('make test',capture=True)
print(result)
print(result.failed)
print(result.succeeded) # 返回执行的命令
# 如果执行失败那么 result.failed 为True
# 如果执行成功那么 result.succeeded 为True
get():从远程服务器上获取文件,通过remote_path参数声明从何处下载,通过local_path表示下载到何处。remote_path支持通配符。
get(remote_path='/etc/passwd',local_path='/tmp/passwd')
put():将本地的文件上传到远程服务器,参数与get相似,此外,还可以通过mode参数执行远程文件的权限配置。
get(remote_path='/etc/passwd',local_path='/tmp/passwd')
reboot():重启远程服务器,可以通过wait参数设置等待几秒钟重启
reboot(wait=30)
propmt():用以在Fabric执行任务的过程中与管理员进行交互,类似于python的input
key = prompt('Please specify process nice level:',key='nice',validate=int)
# 会返回采集到的key
fabric的上下文管理器
env中存储的是全局配置,有时候我们并不希望修改全局配置参数,只希望临时修改部分配置,例如:修改当前工作目录,修改日志输出级别等。
在fabric中我们可以通过上下文管理器临时修改参数配置,而不会影响全局配置。当程序进入上下文管理器的作用域时,临时修改就会起作用;当程序离开上下文管理器时,临时修改就会消失。
cd():切换远程目录
def change(dir='/tmp'):
with cd(dir):
run('pwd') # /tmp
run('pwd') # /root
lcd():切换本地目录
path():配置远程服务器PATH环境变量,只对当前会话有效,不会影响远程服务器的其他操作,path的修改支持多种模式
- append:默认行为,将给定的路径添加到PATH后面。
- prepend:将给定的路径添加到PATH的前面。
- replace:替换当前环境的PATH变量。
def addpath():
with path('/tmp','prepend'):
run("echo $PATH")
run("echo $PATH")
prefix():前缀,它接受一个命令作为参数,表示在其内部执行的代码块,都要先执行prefix的命令参数。
def testprefix():
with cd('/tmp'):
with prefix('echo 123'):
run('echo 456')
run('echo 789') # 转换为Linux命令为:
cd /tmp && echo '123' && echo '456'
cd /tmp && echo '123' && echo '789'
shell_env():设置shell脚本的环境变量
def setenv():
with shell_env(HTTP_PROXY='1.1.1.1'):
run('echo $HTTP_PROXY')
run('echo $HTTP_PROXY') # 等同于shell中的export
export HTTP_PROXY='1.1.1.1'
settings():通用配置,用于临时覆盖env变量
def who():
with settings(user='dev'): # 临时修改用户名为dev
run('who')
run('who')
remote_tunnel():通过SSH的端口转发建立的链接
with remote_tunnel(3306):
run('mysql -uroot -p password')
hide():用于隐藏指定类型的输出信息,hide定义的可选类型有7种
- status:状态信息,如服务器断开链接,用户使用ctrl+C等,如果Fabric顺利执行,不会有状态信息
- aborts:终止信息,一般将fabric当作库使用的时候需要关闭
- warnings:警告信息,如grep的字符串不在文件中
- running:fabric运行过程中的数据
- stdout:执行shell命令的标准输出
- stderr:执行shell命令的错误输出
- user:用户输出,类似于Python中的print函数
为了方便使用,fabric对以上其中类型做了进一步的封装
- output:包含stdout,stderr
- everything:包含stdout,stderr,warnings,running,user
- commands:包含stdout,running
show():与hide相反,表示显示指定类型的输出
def hello():
with settings(show('everything'),warn_only=True): # 显示所有
result = run('netstat -lntup|grep')
print('1='+result) # 命令执行的结果
print('2='+str(result.return_code)) # 返回码,0表示正确执行,1表示错误
print('3='+str(result.failed))
结果
pyvip@Vip:~/utils$ fab -f fab_utils.py hello
[192.168.5.128] Executing task 'hello'
[192.168.5.128] run: netstat -lntup|grep
[192.168.5.128] out: 用法: grep [选项]... PATTERN [FILE]...
[192.168.5.128] out: 试用‘grep --help’来获得更多信息。
[192.168.5.128] out: Warning: run() received nonzero return code 2 while executing 'netstat -lntup|grep'! NoneType 1=用法: grep [选项]... PATTERN [FILE]...
试用‘grep --help’来获得更多信息。
2=2
3=True Done.
quiet():隐藏全部输出,仅在执行错误的时候发出告警信息,功能等同于 with settings(hide('everything'),warn_only=True) .
# 比如创建目录的时候,如果目录存在,默认情况下Fabric会报错退出,我们是允许这种错误的,所以针对这种错误,我们进行如下设置,使fabric只打出告警信息而不会中断执行。
with settings(warn_only=True)
装饰器
Fabric提供的命令一般都是执行某一个具体的操作,提供的上下文管理器一般都是用于临时修改配置参数,而fabric提供的装饰器,既不是执行具体的操作,也不是修改参数,而是控制如何执行这些操作,在那些服务器上执行这些操作,fabric的装饰器与人物执行紧密相关。下面从几个方面来进行说明
- hosts:定制执行task的服务器列表
- roles:定义执行task的role列表
- parallel:并行执行task
- serial:串行执行task
- task:定义一个task
- runs_once:该task只执行一次
fabric的task
task就是fabric需要在远程服务器上执行的函数,在fabric中有3中方法定义一个task
- 默认情况下,fabfile中每一个函数都是一个task。
- 继承自fabric的task类,这种方式比较难用,不推荐。
- 使用fabric的task装饰器,这是使用fabric最快速的方式,也是推荐的用法。
from fabric.api import * env.user='root'
env.password='mysql123' @task
def hello():
run('echo hello') def world():
run('echo world')
PS:默认情况下,fabfile中的所有函数对象都是一个task,但是如果我们使用了task装饰器,显示的定义了一个task,那么,其他没有通过task装饰器装饰的函数将不会被认为是一个task。
fabric的host
为了方便我们的使用,fabric提供了非常灵活的方式指定对哪些远程服务器执行操作,根据我们前面的知识,我们知道有两种方式:通过env.hosts来执行,或者在fab执行命令的时候使用-H参数,除此之外,还有以下需要注意的地方
- 指定host时,可以同时指定用户名和端口号: username@hostname:port
- 通过命令行指定要多哪些hosts执行人物:fab mytask:hosts="host1;host2"
- 通过hosts装饰器指定要对哪些hosts执行当前task
- 通过env.reject_unkown_hosts控制未知host的行为,默认True,类似于SSH的StrictHostKeyChecking的选项设置为no,不进行公钥确认。
from fabric.api import * env.hosts = [
'root@192.168.10.201:22',
'root@192.168.10.202:22',
'root@192.168.10.203:22'
]
env.passwords = {
'root@192.168.10.201:22':'123456201',
'root@192.168.10.202:22':'123456202',
'root@192.168.10.203:22':'123456203'
} @hosts('root@192.168.10.201:22')
@task
def hello():
run('ifconfig br0') # 命令行的方式:
fab hello:hosts="root@192.168.10.201;root@192.168.10.202"
fabric的role
role是对服务器进行分类的手段,通过role可以定义服务器的角色,以便对不同的服务器执行不同的操作,Role逻辑上将服务器进行了分类,分类以后,我们可以对某一类服务器指定一个role名即可。进行task任务时,对role进行控制。
# role在env.roledefs中进行定义
env.roledefs = {
'web':['root@192.168.10.201','192.168.10.202'] # role名称为:web
'db':['root@192.168.10.203',] # role名称为:db
}
当我们定义好role以后,我们就可以通过roles装饰器来指定在哪些role上运行task。 from fabric.api import * env.roledefs = {
'web':['root@192.168.10.201:22','root@192.168.10.202:22',],
'db':['root@192.168.10.203:22',]
}
env.passwords = {
'root@192.168.10.201:22':'123456201',
'root@192.168.10.202:22':'123456202',
'root@192.168.10.203:22':'123456203'
} @roles('db') # 只对role为db的主机进行操作
@task
def hello():
run('ifconfig br0')
注意:hosts装饰器可以和roles装饰器一起使用(全集),看起来容易造成混乱,不建议混搭。
fabric的执行模型
fabric执行任务的步骤如下:
- 创建任务列表,这些任务就是fab命令行参数指定的任务,fab会保持这些任务的顺序
- 对于每个任务,构造需要执行该任务的服务器列表,服务器列表可以通过命令行参数指定,或者env.hosts指定,或者通过hosts和roles装饰器指定
- 遍历任务列表,对于每一台服务器分别执行任务,可以将任务列表和服务器列表看作是两个for循环,任务列表是外层循环,服务器列表是内存循环,fabric默认是串行执行的可以通过装饰器或者命令行参数确定任务执行的方式
- 对于没有指定服务器的任务默认为本地任务,仅执行一次
PS:关于并行模式:
- 通过命令行参数-P(--parallel)通知Fabric并行执行task
- 通过env.parallel设置设否需要并行执行
- 通过parallel装饰器通知Fabric并行执行task,它接受一个pool_size作为参数(默认为0),表示可以有几个任务并行执行
其他装饰器
前面介绍了task,hosts,roles和parallel装饰器,此外还有两个装饰器比较常用
- runs_once:只执行一次,防止task被多次调用。例如,对目录打包进行上传,上传动作对不同的服务器可能会执行多次,但是打包的动作只需要执行一次即可。
- serial:强制当前task穿行执行。使用该参数时优先级最高,即便是制定了并发执行的参数
常用的功能函数
fabric中还有其他的一些好用的函数
封装task
fabric提供了一个execute函数,用来对task进行封装。它最大的好处就是可以将一个大的任务拆解为很多小任务,每个小任务互相独立,互不干扰
from fabric.api import * env.roledefs = {
'web':['root@192.168.10.201:22','root@192.168.10.202:22',],
'db':['root@192.168.10.203:22',]
}
env.passwords = {
'root@192.168.10.201:22':'123456201',
'root@192.168.10.202:22':'123456202',
'root@192.168.10.203:22':'123456203'
} @roles('db')
def hello():
run('echo hello') @roles('web')
def world():
run('echo world') @task
def helloworld():
execute(hello)
execute(world)
# 函数helloworld作为入口,分别调用两个task,对不同的主机进行操作
utils函数
包含一些辅助行的功能函数,这些函数位于fabric.utils下,常用的函数如下:
- abort:终止函数执行,打印错误信息到stderr,并且以退出码1退出。
- warn:输出警告信息,但是不会终止函数的执行
- puts:打印输出,类似于Python中的print函数
def helloworld():
execute(hello)
abort('----->abort') # 执行到这里时,直接退出
warn('----->warn') # 会发出提示信息,不会退出
puts('----->puts') # 会打印括号中的信息
execute(world)
带颜色的输出
fabric为了让输出日志更具有可读性,对命令行中断的颜色输出进行了封装,使用print打印带有不同颜色的文本,这些颜色包含在fabric.colors中。像warn,puts打印输出的,也可以直接渲染颜色
- blue(text,blod=False) 蓝色
- cyan(text,blod=False) 淡蓝色
- green(text,blod=False) 绿色
- magenta(text,blod=False) 紫色
- red(text,blod=False) 红色
- white(text,blod=False) 白色
- yellow(text,blod=False) 黄色
def ls(path='.'):
run('ls {0}'.format(path)) def hello(): execute(hell) # task任务hell
warn(yellow('----->warn')) # 会发出提示信息,不会退出
puts(green('----->puts')) # 会打印括号中的信息
execute(ls) # task任务ls
print(green('the text is green')) # 单纯的渲染文字: def hell(name='world'):
print('hello %s' % name)
确认信息
有时候我们在某一步执行错误,会给用户提示,是否继续执行时,confirm就非常有用了,它包含在 fabric.contrib.console中
def testconfirm(): result = confirm('Continue Anyway?')
print(result) # 会提示输入y/n
# y 时 result为True
# n 时 result为False
使用Fabric源码安装redis
下载一个redis的包和fabfile.py放在同级目录即可,不同目录需要修改包的位置,这里使用的是redis-4.0.9版本。
#!/usr/bin/env python3
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.utils import abort
from fabric.colors import * env.hosts = ['192.168.10.202',]
env.user = 'root'
env.password = '123456202' @runs_once
@task
def test():
with settings(warn_only=True):
local('tar xf redis-4.0.9.tar.gz')
with lcd('redis-4.0.9'):
result = local('make test',capture=True)
if result.failed and not confirm('Test is Faild Continue Anyway?'):
abort('Aborting at user request.') with lcd('redis-4.0.9'):
local("make clean")
local('tar zcvf redis-4.0.10.tar.gz redis-4.0.9') @task
def deploy():
put('redis-4.0.10.tar.gz','/tmp/')
with cd('/tmp'):
run('tar xf redis-4.0.10.tar.gz')
with cd('redis-4.0.9'):
sudo('make install') @task
def start_redis():
with settings(warn_only=True):
result = run('netstat -lntup | grep -w redis-server')
if result.return_code == 0:
print(green('redis is started!'))
else:
run('set -m ; /usr/local/bin/redis-server &') # 用pty=False, fabric进程退不出来,不知道为啥,所以这里用set -m
print(green('redis start Successful')) @task
def clean_local_file():
local('rm -rf redis-4.0.10.tar.gz') @task
def clean_file():
with cd('/tmp'):
sudo('rm -rf redis-4.0.9')
sudo('rm -rf redis-4.0.10.tar.gz') @task
def install():
execute(test)
execute(deploy)
execute(clean_file)
execute(clean_local_file)
execute(start_redis)
PS:关于set -m 的作用如下: "set -m" turns on job control, you can run processes in a separate process group.
理解:在一个独立的进程组里面运行我们的进程。
参考资料
http://www.cnblogs.com/dachenzi/p/8695330.html
Python模块学习 - fabric的更多相关文章
- 【目录】Python模块学习系列
目录:Python模块学习笔记 1.Python模块学习 - Paramiko - 主机管理 2.Python模块学习 - Fileinput - 读取文件 3.Python模块学习 - Confi ...
- 【转】Python模块学习 - fnmatch & glob
[转]Python模块学习 - fnmatch & glob 介绍 fnmatch 和 glob 模块都是用来做字符串匹配文件名的标准库. fnmatch模块 大部分情况下使用字符串匹配查找特 ...
- python模块之 fabric
Python模块之Fabric Fabric简介 Fabric是一个Python库,可以通过SSH在多个host上批量执行任务.你可以编写任务脚本,然后通过Fabric在本地就可以使用SSH在大量 ...
- Python模块学习filecmp文件比较
Python模块学习filecmp文件比较 filecmp模块用于比较文件及文件夹的内容,它是一个轻量级的工具,使用非常简单.python标准库还提供了difflib模块用于比较文件的内容.关于dif ...
- python模块学习第 0000 题
将你的 QQ 头像(或者微博头像)右上角加上红色的数字,类似于微信未读信息数量那种提示效果. 类似于图中效果: 好可爱>%<! 题目来源:https://github.com/Yixiao ...
- Python模块学习:logging 日志记录
原文出处: DarkBull 许多应用程序中都会有日志模块,用于记录系统在运行过程中的一些关键信息,以便于对系统的运行状况进行跟踪.在.NET平台中,有非常著名的第三方开源日志组件log4net ...
- 解惑Python模块学习,该如何着手操作...
Python模块 晚上和朋友聊天,说到公司要求精兵计划,全员都要有编程能力.然后C.Java.Python-对于零基础入门的,当然是选择Python的人较多了.可朋友说他只是看了简单的语法,可pyth ...
- Python模块学习
6. Modules If you quit from the Python interpreter and enter it again, the definitions you have made ...
- Python模块学习系列
python模块-time python模块-datetime python模块-OS模块详解
随机推荐
- IntelliJ IDEA2017 激活方法 最新的(亲测可用)
IntelliJ IDEA2017 激活方法(亲测可用): 搭建自己的授权服务器,对大佬来说也很简单,我作为菜鸟就不说了,网上有教程. 我主要说第二种,现在,直接写入注册码,是不能成功激活的(如果你成 ...
- 加入EOS主网
[加入EOS主网] 根据之前的博文,可以直接在本地测试单节点网络.这里再给出一下.详情见[参考1]. alias cleos='docker exec -it eosio /opt/eosio/bin ...
- python中的字符串
一.在python中,字符串是不可变类型 通过以下代码说明: >>> s = 'hello, world' >>> id(s) 2108634288304 > ...
- mysql 报错You can't specify target table 'wms_cabinet_form' for update in FROM clause
这个错误是说从t表select出来的无法又更新t表. 可以在select的时候先取个别名,弄个临时表即可.
- 129. Sum Root to Leaf Numbers pathsum路径求和
[抄题]: Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a ...
- 学习Hibernate的体会
这个学期老师让我们做一个系统(服务器和客户端),语言自选,我也随大家开始学习java web 和android . 下面是我自学的一些体会和遇到的问题. 关于jar包. jsds.jar javasi ...
- HDU2028
#include <bits/stdc++.h> using namespace std; ; int gcd(int a, int b) { ? b:gcd(b, a%b); } int ...
- linux学习第七天 (Linux就该这么学)
今天讲了chmod (权限 设置)和 chown(属性 设置),特殊权限:SUID u+s 数字法是4 x=s - = S,SGID g+s 数字法是2 x=s -=S,SBIT o+t x=t ...
- springmvc为什么是线程不安全的
1.因为springmvc默认是单例的,所以会有线程安全的问题,如果存在全局变量,因为全局变量是存在方法区的,而局部变量是放在栈中的,方法区是所有线程公用的,而每个线程都有属于自己的栈.所以如果使用单 ...
- 第二阶段第一次spring会议
昨天我们讨论了改进方法,打算建立数据库. 今天我对39个组发表了建议以及总结了改进意见和改进方案. 明天我将对软件添加回收站.