os模块

import os

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
path = r"aa/"
path1 = r'bb/'
# 如果path路径不加'/'的话,默认是从运行路径再加aa
os.getcwd()
#'/home/python'
# 运行ipython的路径,如果是python3 /home/python/app1.6/runner.py
# 则是/home/python/app1.6
os.path.abspath(path) # path规范化的绝对路径
#'/home/python/aa'
os.path.join(os.getcwd(),path,path1)
#'/home/python/aa/bb/'
os.path.normpath(os.path.join(os.getcwd(),path,path1))
# path规范化的绝对路径
#'/home/python/aa/bb'
将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.join('/home/python','/','aa','/home/')
# '/home/'

判断

1
2
3
4
5
6
7
8
9
10
11
12
13
os.path.exists(path)# 如果path存在,返回True;如果path不存在,返回False.
os.path.isabs(os.getcwd()) # 如果只要path是绝对路径,不管是不是存在,返回True
os.path.isfile(path)
os.path.isdir(path)
'1.jpg'.endswith('.jpng') # False
# 计算此文件的大小
(os.path.getsize(abspath))/1024/1024 # byte/k/M
#改变一个文件的文件名
os.rename(os.path.join('abspath','filename'), \
os.path.join('abspath','new_name'))
# 如果没有则创建目录,有的话就没原来的,防止
os.makedirs('/home/python/1/1/1',exist_ok=True)

分割

1
2
3
4
5
6
7
8
9
10
11
12
13
os.path.splitext(r'/home/python/22.json')
#('/home/python/22', '.json')
os.path.split('/home/python/app1.6/1.txt')
# 将path分割成目录和文件名二元组返回
#('/home/python/app1.6', '1.txt')
os.path.dirname('/home/python/app1.6/1.txt')
# 相当于os.path.split(path)的第一元素
#'/home/python/app1.6'
os.path.basename('/home/python/app1.6/1.txt')
# 相当于os.path.split(path)的第二元素
#'1.txt'

from urllib.parse import urljoin

1
2
urljoin('https://femnyy.com/','VPS/xx')
# 第一个路径必须要有最后一个'/'
Share Comments

linux防火墙设置

以在Ubuntu 16.04上为Docker Swarm配置Linux防火墙为例子

介绍

DockerSwarm 是Docker的一项功能,可以很容易地大规模投放Docker窗主机和容器. Docker窗群,或码头集群,该功能是由一个或多个主机Dockerized作为经典的节点,任何数量的工作节点组成.设置这样的系统需要仔细操纵Linux防火墙.

Docker Swarm正常工作所需的网络端口有:

TCP端口2376进行安全Docker窗客户端通信.此端口是Docker Machine工作所必需的. Docker机器用于编排Docker主机.
TCP端口2377 .此端口用于Docker Swarm或群集的节点之间的通信.它只需要在管理器节点上打开.
TCP和UDP端口7946的节点之间的通信(容器网络发现).
UDP端口4789的覆盖网络通信(容器入口联网).
注意:除了这些端口,端口22 (SSH的流量),并在集群上运行需要提供特定服务的其他端口必须是开放.

预前准备

设置组成集群的主机,包括至少一个群集管理器和一个群组工作者.您可以按照教程如何提供和管理远程Docker在Ubuntu 16.04Docker主机设置这些.
注意:您会注意到命令(在这篇文章中所有的命令)不能与前缀sudo .这是因为它假设您正在使用的登录到服务器docker-machine ssh使用Docker窗机设置后命令.

在本文中,您将学习如何使用所有Linux发行版上提供的不同防火墙管理应用程序在Ubuntu 16.04上配置Linux防火墙.这些防火墙管理应用程序是FirewallD,IPTables工具和UFW,简单的防火墙. .虽然本教程包含三种方法,每种方法都提供相同的结果,因此您可以选择最熟悉的方法.

UFW

UFW是Ubuntu发行版上的默认防火墙应用程序,包括Ubuntu 16.04
如果你只是设置你的Docker主机,UFW已经安装.您只需要启用和配置它

在将用作Swarm管理器的节点上执行以下命令:

1
2
3
4
5
6
ufw allow 22/tcp
ufw allow 2376/tcp
ufw allow 2377/tcp
ufw allow 7946/tcp
ufw allow 7946/udp
ufw allow 4789/udp

之后,重新加载并启用UFW:

1
2
ufw reload
ufw enable

这可能不是必需的,但是在任何时候更改并重新启动防火墙时,都不必重新启动Docker守护程序:

1
systemctl restart docker

然后在将用作工作线程的每个节点上,执行以下命令:

1
2
3
4
5
6
7
8
ufw allow 22/tcp
ufw allow 2376/tcp
ufw allow 7946/tcp
ufw allow 7946/udp
ufw allow 4789/udp
ufw reload
ufw enable
systemctl restart docker

关闭防火墙

1
ufw disable

FirewallD

FirewallD是Fedora,CentOS和基于它们的其他Linux发行版上的默认防火墙应用程序.但FirewallD也可用于其他Linux发行版,包括Ubuntu 16.04.

如果您选择使用FirewallD而不是UFW,请首先卸载UFW:

1
2
3
4
5
6
apt-get purge ufw
# 然后安装FirewallD:
apt-get install firewalld
systemctl status firewalld
systemctl start firewalld
systemctl enable firewalld # 开机启动

当开机启动时会生成如下文件:

1
2
3
4
Created symlink from /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service
to /usr/lib/systemd/system/firewalld.service.
Created symlink from /etc/systemd/system/basic.target.wants/firewalld.service
to /usr/lib/systemd/system/firewalld.service.

在将是Swarm管理器的节点上,使用以下命令打开必要的端口:

1
2
3
4
5
6
7
firewall-cmd --add-port=22/tcp --permanent
firewall-cmd --add-port=2376/tcp --permanent
firewall-cmd --add-port=2377/tcp --permanent
firewall-cmd --add-port=7946/tcp --permanent
firewall-cmd --add-port=7946/udp --permanent
firewall-cmd --add-port=4789/udp --permanent
# firewall-cmd --permanent --add-service=https

注意 :如果你犯了一个错误,需要删除的条目,输入

1
firewall-cmd --remove-port=port-number/tcp --permanent

重新加载防火墙:

1
2
3
4
firewall-cmd --reload
# 查看防火墙
firewall-cmd --list-all
vim /etc/firewalld/zones/public.xml

然后重新启动Docker.

1
systemctl restart docker

然后在将用作Swarm工作程序的每个节点上,执行以下命令:

1
2
3
4
5
6
7
firewall-cmd --add-port=22/tcp --permanent
firewall-cmd --add-port=2376/tcp --permanent
firewall-cmd --add-port=7946/tcp --permanent
firewall-cmd --add-port=7946/udp --permanent
firewall-cmd --add-port=4789/udp --permanent
firewall-cmd --reload
systemctl restart docker

关闭防火墙

1
2
3
4
systemctl stop firewalld
systemctl disable firewalld
# 查看
firewall-cmd --zone=public --query-service=ssh

IPTables

要在任何Linux发行版上使用IPtables,您必须首先卸载任何其他防火墙实用程序.如果您从FirewallD或UFW切换,请先卸载它们.

1
2
apt-get purge ufw firewalld
apt-get install iptables-persistent

接下来,使用此命令清除所有现有规则:

1
netfilter-persistent flush

现在,您可以添加使用规则, iptables实用程序.第一组命令应该在将用作Swarm管理器的节点上执行.

1
2
3
4
5
6
7
8
9
10
11
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 2376 -j ACCEPT
iptables -A INPUT -p tcp --dport 2377 -j ACCEPT
iptables -A INPUT -p tcp --dport 7946 -j ACCEPT
iptables -A INPUT -p udp --dport 7946 -j ACCEPT
iptables -A INPUT -p udp --dport 4789 -j ACCEPT
# 输入所有命令后,将规则保存到磁盘:
netfilter-persistent save
# 然后重新启动Docker.
sudo systemctl restart docker

在将用作Swarm工作程序的节点上,执行以下命令:

1
2
3
4
5
6
7
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 2376 -j ACCEPT
iptables -A INPUT -p tcp --dport 7946 -j ACCEPT
iptables -A INPUT -p udp --dport 7946 -j ACCEPT
iptables -A INPUT -p udp --dport 4789 -j ACCEPT
netfilter-persistent save
sudo systemctl restart docker

如果您希望在使用此方法后切换到FirewallD或UFW,正确的方法是首先停止防火墙:

1
2
3
4
5
6
7
8
9
sudo netfilter-persistent stop
# 然后刷新规则:
sudo netfilter-persistent flush
# 最后,将现在的空表保存到磁盘:
sudo netfilter-persistent save
# 然后可以切换到UFW或FirewallD.
查看开启端口
1
2
3
4
5
6
# 查看本机的端口开启情况
sudo nmap -sTU localhost
# 查看局域网的端口开启情况
sudo nmap -PS 192.168.1.222
# 查看远程服务器的端口开启情况
nc -zv 45.76.0.178 22 22334
Share Comments

basic time

from datetime import date,datetime,timedelta

datetime类型

1
2
3
4
5
d = datetime.now() datetime.datetime(2017, 6, 2, 17, 22, 5, 470694)
datetime(2017,2,3) datetime.datetime(2017, 2, 3, 0, 0)
str(d)[:19]
d.year d.month (属性,都是int类型)
current_day,month_days = calendar.monthrange(2017, 2) (获取某年某月的 当前天数 和 此月共有天)

date类型

datetime.datetime 会精确到 %H%M%S 而datetime.date 不需要

1
2
3
4
5
6
7
8
9
10
date_today = date.today()
start_date = date(2017,2,6).replace(day=1)
# 对应月份第一天的日期 datetime.date(2017, 2, 1) 如果输入是一个 datetime 实例,那么你得到的就是一个 datetime 实例
end_date = start_date + timedelta(days=month_days-1)
# 第一种获得当月月底的日期 datetime.date(2017, 2, 28)date类型和datetime类型 都可以通过 timedelta 进行前/后几天的计算
# 加月份时
from dateutil.relativedelta import relativedelta
six_months = date.today() + relativedelta(months=+6) datetime.date(2017, 12, 27)
six_months = datetime.now() + relativedelta(months=+6) datetime.datetime(2017, 12, 27, 16, 2, 5, 260990)

时间戳类型 timestamp

1
time.time() 1483756148.2785556 type:float

time tuple类型

1
time.localtime() time.struct_time(tm_year=2017, tm_mon=1, tm_mday=7, tm_hour=11, tm_min=0, t_m_sec=54, tm_wday=5, tm_yday=7, tm_isdst=0)

转换关系

datetime.datetime –> str

1
2
s = d.strftime('%Y-%m-%d %H:%M:%S.%f') (2017-01-07 10:16:12.962917)
s = date_today.strftime('%Y-%m-%d') (2017-01-07)

datetime.datetime –> time tuple

1
d.timetuple()

str –> datetime.datetime

1
datetime.strptime('20170107 10:21:28','%Y%m%d %H:%M:%S')

timestamp –> datetime

1
datetime.fromtimestamp(1483755372.0)

str –> time tuple

1
tuple = time.strptime('2017-01-07 10:16:12', '%Y-%m-%d %H:%M:%S')

time tuple –>timestamp

1
time.mktime(tuple)
Share Comments

排序

items

1
2
d = {'k':1,'x':1}
u.items() # ==dict_items([('x', 1), ('k', 1)])

sorted(iterable,key,reverse)

sorted函数按key本身的值对字典排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from operator import itemgetter
d = {'a':1,'c':3,'d':444,'b':2}
# 在签名时挺有用的
for k, v in sorted(d.items(),key=lambda x:x[0]):
print(k,v)
sort_d = sorted(d.items(),key = itemgetter(0),reverse=False)
a = {'x': 1,'y': 2,'z': 3}
b = {'w': 10,'x': 11,'y': 2}
sorted(zip(a.values(),a.keys()))
# [(1, 'x'), (2, 'y'), (3, 'z')]
max(zip(a.values(),a.keys()))
# (3, 'z')
min(zip(a.keys(),a.values()))
# ('x',1)

对v值的排序

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
from operator import itemgetter
rows = [
{'address': '5412 N CLARK', 'date': '07/01/2012'},
{'address': '5412 NIKE SHIRT', 'date': '07/01/2012'},
{'address': '5148 N CLARK', 'date': '07/04/2012'},
{'address': '5800 E 58TH', 'date': '07/02/2012'},
]
rows.sort(key=itemgetter('date'))
rows = sorted(rows,key=itemgetter('date'))
rows = sorted(rows, key=lambda x: x.get('date') \
if x.get('date') else '4000', reverse=False)
# 必須提供一個在排序过程中使用的函数,为每个元素创建一个key,然后按这个key来排序
a = ['femn','femn2014','fe','femnyy']
a.sort(key=len)
from itertools import groupby
# 按相同时间的值,进行分组
for date, items in groupby(rows, key=itemgetter('date')):
print(date)
for i in items:
print(' ', i)
# 输出如下
# 07/01/2012
# {'address': '5412 N CLARK', 'date': '07/01/2012'}
# {'address': '5412 NIKE SHIRT', 'date': '07/01/2012'}
# 07/04/2012
# {'address': '5148 N CLARK', 'date': '07/04/2012'}
# 07/02/2012
# {'address': '5800 E 58TH', 'date': '07/02/2012'}

join

如果你想要合并的字符串是在一个序列或者 iterable 中,那么最快的方式就是使用 join() 方法

1
2
3
data = ['ACME', 50, 91.1]
','.join(str(d) for d in data) # 'ACME,50,91.1'
(str(d) for d in data) #是一个 generator

random

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import random,string
v = [1, 2, 3, 4, 5, 6] # 一个序列或者 iterable
# 随机选择一个,且只能是选一个
random.choice(v)
# 随机提取N个,保证不重复出现,并且N不能超过v的长度
random.sample(v,3)
# 只是想打乱序列中的顺序
random.shuffle(v) # 此时v值的顺序已经被改变
# 生成一个随机的整数
random.randint(0,10)
''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32))
''.join([random.choice(string.ascii_letters+string.digits) for _ in range(43)])
''.join(random.sample(string.ascii_letters+string.digits, 15))
Share Comments

套接字(SOCKET)

socket套接字.是一种通信机制,用于描述IP地址和端口,是一个通信链的句柄.操作socket就像操作Unix一样,一切皆是文件,.

0.0.0.0有多少个网卡,都可以连接到本机.
程序之间进行内存数据交换(通信)比较麻烦:每个程序的内存空间都是被保护的,不能被别的程序直接访问,所以要通过某种介质,管道或第三方工具,去通信.
nosql(第三方):将内存的数据缓存进来,供其它的程序调用,所有的程序都可以往里存数据,所有的程序都可以取数据.相当于实现了一个共享的内存空间.

而所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信(网络socket)

socket.AF_UNIX;只能够用于单一的Unix系统进程间通信
socket.AF_INET:服务器之间网络通信
socket.AF_INET6 IPv6

socket 处于第4层(传输层) ICMP(网络层)
socket通信的数据格式
socket.SOCK_STREAM :PCP三次握手
socket.SOCKDGRAM:UDP
socket.SOCK_RAW 原始套接字 可以处理普通套接字不能处理的ICMP,IGMP等网络报文 可以可以伪造IP

tcp_server

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
from socket import *
#IP协议(socket type) TCP协议(数据包格式)
socketobj = socket(AF_INET,SOCK_STREAM)# 生成Socket对象
socketobj.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1)
socketobj.bind(('localhost',8080)) # 绑定IP和端口
socketobj.listen(128)# 监听连接数量
# 1
#客户端实例,客户端地址
# connection,address=socketobj.accept()
# 每个客户端一连接就会返回的结果
# 但只能连接一个客户端,只有当前客户端下线,下个客户端才能连上
# A,B客户端都运行 但A先连接 B后连接 B处于阻塞状态,没有生成connection
# A断开之后,因为只有一个connection,所以执行了 socketobj.close(),
# 服务也跟着断了 B不会自动连上
while True:
# 2
connection,address=socketobj.accept()
try:
while True:
data = connection.recv(1024) #服务器只接收1024个字节
if len(data) > 0:
# 当recv接收数据时,返回值为空,即没有返回数据,那么意味着客户端
# 已经调用了close关闭了
print('server端收到client端的信息:'+ str(data,encoding = "utf-8"))
connection.sendall(bytes("hello client","utf-8"))
#服务器返回给客户的信息
else:
print('[%s]客户端已经关闭'%str(address))
break
finally:
connection.close()
socketobj.close()

accept():等待客户端连接时阻塞与非阻塞
recv():等待客户端发送信息时阻塞与非阻塞,两者才是只能服务一个客户端的关键

client

1
2
3
4
5
6
7
8
9
10
11
12
from socket import *
socketobj = socket(AF_INET,SOCK_STREAM)
# socketobj.connect(('localhost',8080)) #绑定 阻塞的
socketobj.connect(('localhost',20000)) #asy
while True:
user_input =input("msg to server:").strip()
socketobj.send(bytes(user_input,'utf-8'))
#socketobj.sendall(bytes("hello server", 'utf-8'))
data = socketobj.recv(1024)
print("client端收到server端的信息 :"+str(data,encoding = "utf-8"))
socketobj.close()
多进程与多线程的Socket

利用进程来完成多任务,其实就是启动一个子进程(线程)来完成client.start()
也就是说: 来一个客户端连接分配一个进程或线程为其服务

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
from socket import *
from multiprocessing import *
from threading import Thread
from time import sleep
# 处理客户端的请求并为其服务
def dealWithClient(newSocket,destAddr):
while True:
recvData = newSocket.recv(1024)
if len(recvData)>0:
print('recv[%s]:%s'%(str(destAddr), recvData))
else:
print('[%s]客户端已经关闭'%str(destAddr))
break
newSocket.close()
def main():
serSocket=socket(AF_INET, SOCK_STREAM)
serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1)
localAddr=('', 8080)
serSocket.bind(localAddr)
serSocket.listen(5)
try:
while True:
print('-----主进程,,等待新客户端的到来------')
newSocket,destAddr = serSocket.accept()
# 此时已经连接的客户端Socket=服务端的Socket等待新的客户端到来
print('-----主进程,,接下来创建一个新的进程(线程)负责数据处理-----')
client = Process(target=dealWithClient, args=(newSocket, destAddr))
client.start()
# 因为已经向子进程中copy了一份(引用),并且父进程中这个套接字也没有用处了
# 所以关闭
newSocket.close()
# 多线程
# client = Thread(target=dealWithClient, args=(newSocket, destAddr))
# client.start()
# # newSocket.close()
# 因为线程中共享这个套接字, 如果关闭了会导致这个套接字不可用,
# 但是此时在线程中这个套接字可能还在收数据,因此不能关闭
finally: # 当为所有的客户端服务完之后再进行关闭,表示不再接收新的客户端的链接
serSocket.close()
if __name__ == '__main__':
main()

区别在于:进程的cow(写时copy):能共用的资源尽量共用,实在不行才copy

单进程-非堵塞socket

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
# 只适合用于少数用户,没有实际的运用
from socket import *
#1.创建socket
serSocket = socket(AF_INET, SOCK_STREAM)
#2. 绑定本地ip以及port
localAddr = ('', 8080)
serSocket.bind(localAddr)
#3. 让这个socket 变为非堵塞
serSocket.setblocking(False)
#4. 将socket变为监听(被动)套接字
serSocket.listen(100)
# 用来保存所有已经连接的客户端的信息
clientAddrList = []
while True:
#等待一个新的客户端的到来(即完成3次握手的客户端)
try:
clientSocket,clientAddr = serSocket.accept()
except:
pass
else:
print("一个新的客户端到来:%s"%str(clientAddr))
clientSocket.setblocking(False) # 设置recv为非阻塞
clientAddrList.append((clientSocket,clientAddr))
for clientSocket,clientAddr in clientAddrList:
try:
recvData = clientSocket.recv(1024)
except:
pass
else:
if len(recvData)>0:
print("%s:%s"%(str(clientAddr), recvData))
else:
clientSocket.close()
clientAddrList.remove((clientSocket, clientAddr))
print("%s 已经下线"%str(clientAddr))

但如果当有一个Socket使用到耗时的代码时,其它的Socket也将被阻塞
同时使用轮询机制,所以效率不高

epoll版-TCP服务器

Linux平台下的通过epoll来高效管理socket(server_socket,client_socket)

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
import socket
import select
# 创建套接字
s = socket.socket(socket.AF_INET,socket.SOCK_ STREAM)
# 设置可以重复使用绑定的信息
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(("",8080))
s.listen(10)
# 创建一个epoll对象
epoll = select.epoll()
epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET)
# s.fileno() 得到文件描述符(套接字对应的数字编号)
# fd:sys.stdin.fileno()
connections= {}
addresses ==={}
#循环等待客户端的到来或者对方发数据
while True:
# epoll进行fd扫描的地方--未指定超时时间则为阻塞等待
epoll_list=epoll.poll() # 得到可用的socket
# (包括等待客户端连接的Socket和连接上的客户端Socket,以及服务器的Socket )
# 对事件进行判断,对上面检测出来的Socket进行收发数据的处理
forfd,events in epoll_list:
# 如果是socket创建的套接字 被激活
iffd==s.fileno():
conn,addr=s.accept()
print('有新的客户端到来%s'%str(addr))
#将conn和addr信息分别保存起来
connections[conn.fileno()] = conn
addresses[conn.fileno()] = addr
#向epoll中注册连接socket的可读事件
epoll.register(conn .fileno(),select.EPOLLIN|select.EPOLLET)
# 判断事件是否æ¯接收数据的事件(客户端端发送信息)
elif events == select.EPOLLIN:
#从激活fd上接收
recvData = connections[fd].recv(1024)
if len(recvData)>0:
print('recv:%s'%recvData)
else:
#从epoll中移除该连接fd
epoll.unregister(fd)
#server侧主动关闭该连接fd
connections[fd].close()
print("%s---offline---"%str(addresses[fd]))

epoll的优点:socket通过事件通知机制(由socket本身的状态来告诉epoll,哪个socket可用,就不需要去轮询所有的socket了,更加高效的得到可用的Socket)
不是轮询的方式,epoll它只管你”活跃”的连接,而跟连接总数无关

asy_server

参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from socketserver import BaseRequestHandler, TCPServer, ThreadingTCPServer
import os
# socketserver 可以让我们很容易的创建简单的TCP服务器,
# 巨大部分Python的高层网络模块(比如HTTP,XML-RPC等)都是建立在socketserver功能之上
class EchoHandler(BaseRequestHandler):
def handle(self):#每个连接就会 调用此方法
print('Got connection from', self.client_address)
while True:
# 循环去监听用户的连接,否则只能像单进程的阻塞一样,只能连接一个用户
msg = self.request.recv(8192)
if not msg:#如果用户退出,没有这句的话 就变成死循环
print('connection close by', self.client_address)
break
print(msg)
# self.request.send(str(msg,encoding = "utf-8"))
self.request.send(msg)
if __name__ == '__main__':
# serv = TCPServer(('', 20000), EchoHandler)#单个线程
serv = ThreadingTCPServer(('0.0.0.0', 20000), EchoHandler)
serv.serve_forever()

Share Comments

推导式(Derivation)

list derivation(列表推导式)

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
l = [x*x for x in range(5)]
# [0, 1, 4, 9, 16] 直接返回列表而不是生成器
[i+1 if i>0 else 1 for i in l]
# [1, 2, 5, 10, 17]
[i+1 if i>0 else 2 for i in l]
# [2, 2, 5, 10, 17] # 说明 如果是取else的话,就不再去做更新的操作
[i for i in l if i >4 and i <=16] # [9,16]
vec = [[1,2,3], [4,5,6], [7,8,9]]
[num for elem in vec for num in elem]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
# [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
```
改变字典的值
```python
l_d = [{'name':'femn','age':25},{'name':'femnyy','age':35}]
[i if i.get('age')> 25 else i for i in l_d]
# 虽然此时不能得到自己想要的改变 不能用i['name']='femnhh'去做改变
[i.update({'name':'femnhh'}) if i.get('age')> 25 else i for i in l_d]
# [{'age': 25, 'name': 'femn'}, None] # 相当于是匹配没有匹配成功则返回None
# 但此时l_d却已经是改变成想要的了
l_d
# [{'age': 25, 'name': 'femn'}, {'age': 35, 'name': 'femnhh'}]

generator derivation(生成器推导式)

1
2
g = (x*x for x in range(5)) # 'generator' object
next(g) #

dict derivation (字典推导式)

1
2
3
4
prices = {'ACME': 45.23,'AAPL': 612.78,'IBM': 205.55,\
'HPQ': 37.20,'FB': 10.75}
p1 = {key: value for key, value in prices.items() if value > 20}
# {'ACME': 45.23, 'IBM': 205.55, 'HPQ': 37.2, 'AAPL': 612.78}
Share Comments

python包管理工具

pip包管理工具

配置 pip conf,自动设置源

1
2
3
4
5
6
7
# mkdir ~/.pip/
# vim ~/.pip/pip.conf
[global]
index-url=https://pypi.tuna.tsinghua.edu.cn/simple
也可以每次安装的时候制定 source
# pip install –i https://pypi.tuna.tsinghua.edu.cn/simple lxml

分别使用不同python版本 进行安装应用

install pip 以及普通用户安装包的路径

1
2
3
4
sudo apt install -y python-pip
which pip
python2.7 -m pip install tornado
# ~/.local/lib/python2.7/site-packages/tornado

install pip3 以及普通用户安装包的路径

1
2
3
4
sudo apt install -y python3-pip
which pip3
python3.5 -m pip install bson
# ~/.local/lib/python3.5/site-packages/bson

root用户安装包之后的路径

1
2
sudo python3.5 -m pip install tornado
# /usr/local/lib/python3.5/dist-packages/tornado

更新pip

1
2
3
sudo python2.7 -m pip install -U pip
sudo pip3 install -U pip
# sudo pip install -U pip 更新的还是pip3

一键导出/安装所有安装包列表

1
2
sudo pip3 freeze > requirements.txt
sudo pip3 install -U -r requirements.txt

推荐使用Conda的环境管理

1
2
3
4
5
6
7
8
9
10
11
12
# 安装环境
conda create --name jnck
# 安装好后,使用activate激活某个环境
source activate jnck
# 退出环境
source deactivate jnck
# 删除环境
conda remove --name jnck --all
# 好像和下面的环境有冲突

virtualenv

1
2
3
4
5
6
7
8
9
10
pip3 install virtualenv
virtualenv --no-site-package venv
# 命令virtualenv就可以创建一个独立的Python运行环境
# --no-site-packages,这样已经安装到系统Python环境中的所有第三方包都不会复制过来
# 同时新建的Python环境被放到当前目录下的venv目录
# 有了venv这个Python环境,可以用source进入该环境
source venv/bin/activate
# 退出该环境
deactivate

virtualenvwrapper更方便管理虚拟环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 安装
pip install virtualenvwrapper
mkdir ~/.local/virtualenvs
which virtualenvwrapper.sh
# /home/femn/anaconda3/bin/virtualenvwrapper.sh
vim ~/.bashrc
export WORKON_HOME=~/.local/virtualenvs
. /home/femn/anaconda3/bin/virtualenvwrapper.sh
source ~/.bashrc
virtualenvwrapper --help
# 基本使用
创建基本环境:mkvirtualenv [环境名], 指定python版本mkvirtualenv ttenv --python=python3.5
删除环境:rmvirtualenv [环境名]
激活环境:workon [环境名]
退出环境:deactivate
列出所有环境:workon

conda管理包

安装好Anaconda之后,可以用conda install numpy来管理python包,就像pip一样 同时届有notebook: jupyter notebook –ip=127.0.0.1
https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 下载
sh xx.sh
同时也可以在pychome中也可以用jupyter notebook格式的文件了

Share Comments

字符

信息的存储单位:位(bit)–>字节(Byte=8bit,已经可以表示所有的英语符号)–>字符(char=2Byte) 1K =1024byte 1M = 1024K G T P

字节是电脑最小的处理单元 一个字节:0x01

字符:也是一个信息单位,它是各种文字和符号的总称.比如人类 各国看得懂的文字,符号,图形符号,数字.

字符编码:是指对于字符集中的字符,将其编码为特定的二进制数,以便计算机处理.

解码:将计算机处理后的二进制信息,转换成人类看得懂的字符.

字符集和字符编码往往被认为是同文义的概念.ASCII字符编码既表示了字符集也表示了的对应的字符编码.

ASCII字符集:共有128个字符(美国,本身只需要一个字节),包含显示字符(英文大小写,阿拉伯数字)和控制字符(回车,空格键)

GB2312字符集:中国标准的简体中文字符集,其中还有一个中国的GBK字符集

Unicode字符集:世界各国语言中使用到的所有字符.用了4个字节,2个字符.汉字’严’的Unicode编码是十六进制数4E25,转化成二进制有15位

UTF-8:是一种针对Unicode的可变长度字符编码,它使用一到四个字节来表示字符.ASCII字符继续用一个字节表示.中文可能用到4个字节.

先来一个关于简单的ASCII字符集,解码和编码的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
a = 12
b = oct(a)
print(b) #0o14
# 为了将整数转换为二进制,八进制或十六进制的文本串,可以分别使用bin(),oct()或hex()
# 如果你不想输出0b,0o或者0x的前缀的话
# 可以使用format()函数.比如:format(x, 'b') 'o' 'x'
# 编码 虽然没有用encode()方法
print([n for n in b'ahello'])#[97, 104, 101, 108, 108, 111]
# 索引和迭代动作返回的是字节的值而不是字节字符串
# 编码与解码
print([int(n).to_bytes(1,'big').decode('utf-8') for n in b'ahello'])
# 成功 所以说再次证明 电脑最小的操作单位是字节 ,而不是字节的值这是人看得懂的
# ['a', 'h', 'e', 'l', 'l', 'o']

中文字符集的例子

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
print(sys.getdefaultencoding())#utf-8
c ='严'.encode('utf-8')#b'\xe4\xb8\xa5'
print(b'\xe4\xb8\xa5'[0])#228
print(len(c))# 3个字节
print(c.decode())# 严
# 字节的低位高位排列方式 big从低到高 little从高到低
from idna import unicode
unicode(b'\xe4\xb8\xa5','utf-8')
# 解码
# 多个字节的解码转换出来的 数字不太理解 虽然也是十进制的
print(int().from_bytes(c, 'little')) #10860772
# 将字节byte转换为整数 并指定字节顺序
print(int().from_bytes(c, 'big')) # 14989477
print('--------------------') # 14989477
# 编码
print(int(10860772).to_bytes(3, 'little'))
# b'\xe4\xb8\xa5'
print(int(14989477).to_bytes(3, 'big').decode('utf-8'))
# b'\xe4\xb8\xa5'
# 为了将一个大整数转换为一个字节字符串,使用 int.to_bytes() 方法
# 并像下面这样指定字节数和字节顺序
print(int(14989477).to_bytes(3, 'big'))
# b'\xe4\xb8\xa5'
print(int(14989477).to_bytes(8, 'big'))
# b'\x00\x00\x00\x00\x00\xe4\xb8\xa5'

u’’ –> str

1
2
s = '\u6211'
s = s.encode('utf-8').strip().decode()
Share Comments

序列(sequence)

在Python中,最基本的数据结构就是序列(sequence).序列中的每个元素都会分配一个序号即元素的位置也称为索引.序列的第一索引是0,最后一个是-1.

序列有6种内建的序列.最常用的是元组(不可以改),列表(可以修改)和字符串,还有Unicode字符串,buffer对象,xrange对象.内建函数会返回元组,它与Python内部的动作方式有关,几乎在所有的情况下都可以用列表替代元组.例外的情况是:使用元组作为字典的键.

通用的序列操作

所有序列类型都可以进行某些特定的操作:索引(indexing),分片(slicing),加(adding两种相同的类型的序列才能进行连接操作),乘(multiplying),以及检查某个元素是否属于序列成员(成员资格) in,除此之处,Python还有计算序列长度len(),找出最大元素max()和最小元素min()的内建函数以及迭代(iterator)

l = list(‘hello’) [‘h’,’e’,’l’,’l’,’o’]list函数适用于所有类型的序列,而不仅仅是字符串.list()为内建函数.

x=[31,5,7,8]
y=sorted(x),这个函数实际上可以用于任何序列,任何可迭代对象,却总是返回一个列表. sorted(‘Python’)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 分片操作第二个索引不包含在分片内
numbers = [1,2,3,4,5,6,7,8,9,10]
number[-3: ] # 8-10
number[:3] # 1-3
number[:] # 取所有
# 步长
numbers[0:10:2]
numbers[::4] # 步长不能为 0,但是可以为负数,如
numbers[8:3:-1] # 得到[9, 8, 7, 6, 5]
numbers[10:0:-2] # 得到[10, 8, 6, 4, 2]
number[::-2] # 得到[10, 8, 6, 4, 2]
number[5::-2] # 得到[6, 4, 2]
number[:5:-2] # 得到 [10, 8]

基本的列表操作(list)

元素赋值(不能超过索引进行赋值):是替换而不是累加

1
l[4]= 1

删除元素

1
2
3
4
5
6
7
8
9
10
11
del l[4]
remove('h')
# 用于移除列表中某个值的第一个匹配元素.
pop()
# 会移除列表中的一个元素(默认是最后 一个)并返回该元素的值.
# 后进先出(LIFO)唯一个修改了列表以返回元素值的列表方法.(出栈)
l[1:5] = []
['h', 'e', 'l', 'l']

追加元素

1
2
3
4
5
6
7
8
9
10
11
12
insert(索引位置,要插入的对象) # 将对象插入到列表中,(累加)
l.insert(4,'four')
l.append(5)
# 在列表末尾追加新的对象,它不是简单的返回一个修改过的新列表,
# 而是直接修改的原来的列表.(入栈)
l.extend()
# 可用新的列表来扩展原有的列表,只是修改(扩展)了原有的列表.
# 而原始的连接操作(+),则会返回一个新的列表.
l.extend(list('o femn'))

分片赋值

1
2
l[1:1] = list('femn')
['h', 'f', 'e', 'm', 'n', 'e', 'l', 'l']

l.count(‘h’):统计某元素在列表中出现的次数.

l.index(‘h’):用于列表中找出某个元素在列表中第一个匹配的索引位置.

l.reverse():将列表元素反向存放,它返回的是一个迭代器(iterator)对象.

sort():在原位置对列表进行排序.在”原位置排序”意味着改变原来的列表,从而让其中的元素按一定的顺序排列,而不是简单地返回一个已经排序的列表副本.

1
2
y=x[:] # y=x 错误,这样会让x,y都指向同一个列表.
y.sort()

元组:不可变序列(字符串也是不能修改)

元组通过圆括号 括起来的.如果你用逗号分隔了一些值,那么你就自动创建的元组.
tuple([1,2,3]):以一个序列作为参数并把它转换为元组.tuple并不是真正的函数,而是一种类型.

字典

dict()像list,tuple,str一样,不是真正的函数,都只是类型.这些方法如果都不带参数,返回的都是对应的空字典,列表,元组,字符串.

创建字典

1
2
3
4
5
6
7
8
9
10
d = dict(host='1',name = 'femn')
d = dict([('name','femn'),('age',18)])
u = dict({'love':'sport'},**d)
for l in d.items()
# 将字典中所有项以列表的方式返回,但返回时并没有特定的次序(dict_items)
for k,v in d.items()
d.iteritmes() # 返回的是一个迭代器对象,而不是列表.
d.keys()
# 将字典中所有的K(dict_keys),以列表形式返回d.values() (dict_values)
d.iterkeys() # 返回针对键的迭代器 d.itervalues()

典的基本操作

1
len(d) # 键值对的数量

到V

1
2
d['name'] # 返回k对应的v
d.get('name','femn')

修改V

1
d['name'] = 'femnyy'

删除 K-V

1
2
3
del d['name'] # 删除K为name的那一个项
d.pop('name') # 用来取得给定K的V,并将K-V移除.
d.clear() # 清除字典中所有的项

更新

1
2
3
4
5
6
7
d[x] = y
# 若键x存在,则修改x对应的值为y,若键x不存在,则在字典d中增加键值对x:y
# 利用一个字典项更新另一个字典
d1.update(d)
# 将字典x所有键值对添加到字典d中(不重复,重复的键值对用字典x中的键值对替代字典d中)
# update可以使用与调用dict函数(或者类型构造函数)同样的方式进行调用
# 这意味着update可以和映射,拥有键值对的队列(或者其它可迭代对象)以及关键字参数一起调用.

K in d # 检查d中是否含有键为K的项. v in l:# 查找列表的值,而不索引

1
d.has_key('name') # 返回True 或 False

键视图的一个很少被了解的特性就是它们也支持集合操作,比如集合并、交、差运算

1
2
3
4
5
6
a = {'x': 1,'y': 2,'z': 3}
b = {'w': 10,'x': 11,'y': 2}
a.keys() & b.keys() # {'x', 'y'}
a.keys() - b.keys() # {'z'}
a.items() & b.items() # {('y', 2)}
{key: a[key] for key in a.keys() - ['z', 'w']} # {'y': 2, 'x': 1}

dict copy
copy 拷贝返回一个相同的字典,此处是 Java 中的浅拷贝
共用对象的引用,独立的基本类型的引用

1
2
3
4
5
6
7
x = {'username':'admin', 'machines':['foo', 'bar', 'baz']}
y = x.copy()
y['username'] = 'mlh'
y # {'machines': ['foo', 'bar', 'baz'], 'username': 'mlh'}
y['machines'].remove('bar')
y # {'machines': ['foo', 'baz'], 'username': 'mlh'}
x # {'machines': ['foo', 'baz'], 'username': 'admin'}

deepcopy 是深拷贝,有自己独立的存储空间

1
2
3
4
5
6
7
8
from copy import deepcopy
d={}
d['names'] = ['Alfred', 'Bertrand']
c = d.copy()
dc = deepcopy(d)
d['names'].append('Clive')
c # {'names': ['Alfred', 'Bertrand', 'Clive']}
dc # {'names': ['Alfred', 'Bertrand']}

迭代工具

zip():并行迭代,返回一个元组的列表,zip可以处理不等长的序列,当最短的序列用完的时候就会停止.

1
2
3
name = ['femn','femnyy','femnhh']
age = [18,25]
zip(name,age) # [('femn', 18), ('femnyy', 25)]

Share Comments

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Share Comments