Python

Python

一、项目打包

常见的打包工具有哪些 ?

  • distutils
  • setuptools

什么是setuptools?

  • setuptools是distutils的增强版,并不在标准库中,拓展了很多功能,大部分用户都会选择setuptools模块

源码包与二进制包有什么区别?

  • 源码包:

    • 安装过程:先解压,再编译,最后安装,所以跨平台,速度比较慢
  • 二进制包:

    • 省去了编译的过程,直接解压安装;但是由于不同平台编译出来的包无法通用,所以在发布时需要先编译好多个平台的包:

      常见格式:

      格式 后缀
      egg .egg
      wheel .whl
    • egg和whl有何区别?

      • Egg是setuptools在2004年引入的,Wheel则是在2012年才定义,Wheel的出现是为了替代Egg,本事是一个Zip包,现在被认为是标准的Python二进制包格式
      • wheel包可以通过pip安装,只不过需要首先安装wheel模块:pip install wheel

setup.py的编写:

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
from __future__ import print_function
from setuptools import setup, find_packages

data_files = []

setup(
name='capbac',
version='1.0',
description='Sawtooth CapBAC',
author='kappanneo',
# 项目主页
url='https://github.com/kappanneo/sawtooth-capbac',
# 指的是你要安装的包
packages=find_packages(),
# 指明当前模块现需要依赖哪些包,若环境中没有,则从pypi中下载
install_requires=[
'aiohttp',
'aiocoap'
'colorlog',
'protobuf',
'sawtooth-sdk',
'sawtooth-signing',
'PyYAML',
],
#指明目的目录和源文件路径
data_files=data_files,
# 用来支持自动生成脚本,安装后自动生成/usr/bin/capbac的可执行文件
# 该文件入口指向capbac_cli.py的main_wrapper函数
entry_points={
'console_scripts': [
'capbac = capbac_cli:main_wrapper',
]
})


使用setup.py构建包:

  • 构建源码发布包:

    • 构建

      1
      python setup.py sdist
    • 安装

      1
      eash_install xxx.tar.gz
  • 构建二进制分发包:

    • Windows上可以构建成exe这样的二进制软件包:

      1
      python setup.py bdist_wininst
    • Linux上构建rpm包:

      1
      python setup.py bdist_rpm
    • Linux上构建egg包:

      1
      python setup.py bdist_egg
    • 在多个平台构建:

      1
      python setup.py bdist

使用setup.py安装包:

1
2
python setup.py install 安装到系统全局环境
python setup.py develop 不会真正安装包,而是在环境变量中创建一个软链接,便于调试

参考资料:https://blog.csdn.net/calvinpaean/article/details/113580458

二、日期模块

time

  • 当前时间戳:

    1
    2
    3
    import time
    print(time.time())
    # 1684753413.0579932
  • 时间戳转时间:

    1
    2
    3
    4
    5
    6
    import datetime
    import time

    t1 = time.time()
    t2 = datetime.datetime.fromtimestamp(t1)
    print(t2.isoformat())
  • 输出当前时间的字符串

    1
    2
    3
    import time
    print(time.strftime("%Y-%m-%d-->%H:%M:%S"))
    # 2023-05-22-->19:06:59
  • 将字符串解析为datatime对象

    1
    2
    3
    4
    5
    6
    from datetime import datetime

    date_str = '2021-05-22'
    date_obj = datetime.strptime(date_str, '%Y-%m-%d')
    print(date_obj)
    # 2021-05-22 00:00:00

参考:https://geekpy.github.io/2018/08/12/python_time/

三、Socket编程

当客户端执行sock.close(),会向服务器发送FIN包,此时服务端的conn.recv(1024)才会返回空字符串;如果直接发送空字符串,conn.recv(1024)并不会返回空字符串,而是继续阻塞等待。

服务端同理,执行conn.close()后,客户端的sock.recv(1024)也会返回空字符串

注意:当任意一段执行close()后,另一端都要再次执行close()

socket.send()受制于MTU,不一定发送完给定的数据

socket.sendall()若发送完则返回None,失败则抛出异常

  • client.py

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

    # 创建TCP套接字对象
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # socket.AF_INET为ipv4,socket.SOCK_STREAM为TCP套接字
    # 连接服务器
    sock.connect(('192.168.126.140', 8083))

    while True:
    # 发送数据到服务器并接收响应
    sock.sendall(b'asd')
    data = sock.recv(1024)
    if not data:
    print("fuck!~")
    sock.close()
    break
    # 打印从服务器接收到的响应
    print(data.decode())

    # 关闭套接字
  • server.py

    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
    import socket

    # 创建TCP套接字对象
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定IP地址和端口号
    sock.bind(('localhost', 8080))

    # 开始监听客户端连接
    sock.listen(1)
    # 1表示最多允许排队的连接数为1个

    # 等待客户端连接
    conn, addr = sock.accept()

    # 接收来自客户端的数据并发送回去
    print(addr)
    while True:
    data = conn.recv(1024)
    if not data:
    break
    conn.sendall(data + b'fuck')

    # 关闭套接字
    conn.close()
    sock.close()

四、日志

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

if __name__ == '__main__':
format = "%(asctime)s-%(levelname)s-%(message)s" # asctime为生成时间
date_format = "%Y/%m/%d %H:%M:%S" # 日期时间
logging.basicConfig(
filename="qy.log", # 输出到文件,此时不会输出到控制台
filemode='a', # 默认为追加模式
format=format,
datefmt=date_format,
level=logging.DEBUG # 日志级别
)
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")

五、参数解析Argparser

argparse模块帮助编写命令行接口

默认值参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# coding:utf-8
import argparse

parser = argparse.ArgumentParser(description='命令行中传入一些数字') # 参数解析器
parser.add_argument('-a', type=int, nargs='+', default=123, help='加数a')
parser.add_argument('-b', type=int, nargs='+', default=456, help='加数a')

args = parser.parse_args()
print(args.a[0]+args.b[0])
print(args.a)
"""
567
[123, 222, 22]
"""

必须参数

required=True

补充说明

当-和--同时出现的时候 python默认后者为参数名

1
2
3
4
参数nargs:
nargs='*'  表示参数可设置零个或多个
nargs='+' 表示参数可设置一个或多个
nargs='?' 表示参数可设置零个或一个

参考

https://zhuanlan.zhihu.com/p/56922793

https://baijiahao.baidu.com/s?id=1718013777590980266&wfr=spider&for=pc

六、Pandas

6.1 读取数据

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
data = pd.read_csv("./factor_returns.csv")
# 可以读取csv tsv txt
print(data.head(60)) # 读取前60行数据
print(data.shape) # 行数和列数
print(data.columns) # 查看列名
print(data.index) # 查看索引列
print(data.dtypes) # 查看每列的数据类型
data2 = pd.read_csv("./datingTestSet2.txt", sep="\t", header=None, names=["列名1", "列名2", "列名3", "列名4"]) # header = None表示没有头
pd.read_excel() # 读取xls或者xlsx
pd.read_sql()

6.2 数据结构

DataFrame

二维数据,类似表格,有列名columns和行名index

从DataFrame中读取一行或者一列:Series,其余仍是DataFrame

DataFrame由多个Series组成,无论是行还是列,单独拆分出来都是一个Series

若查询一列的话:直接把DataFrame当作字典即可

若查询一行的话:需要用到loc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd

data = pd.read_csv("./datingTestSet2.txt", sep="\t")
print(data.loc[0]) 截取行
"""
milage 40920.000000
Liters 8.326976
Consumtime 0.953952
target 3.000000
Name: 0, dtype: float64
"""
print(data.loc[0:3])
"""
milage Liters Consumtime target
0 40920 8.326976 0.953952 3
1 14488 7.153469 1.673904 2
2 26052 1.441871 0.805124 1
3 75136 13.147394 0.428964 1
"""

Series

一维数据,一行或者一列

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 pandas as pd

data = pd.Series(["a", "1", "abc"], index=["i1", 'i2', '3']) # 通过列表创建Series
print(data.values) # 获取数据
"""
['a' '1' 'abc']
"""
print(data.index) # 获取索引
"""
Index(['i1', 'i2', '3'], dtype='object')
"""
data2 = pd.Series({
'i0': "y",
'i1': "q",
'i2': "z",
'i3': "x",
}) # 通过字典创建Series
print(data2[["i1", "i0"]]) # 获取值
"""
i1 q
i0 y
dtype: object
"""
print(data2.i1) # 获取值
"""
q
"""

6.3 查询数据

loc() :根据标签名进行查询

iloc() :根据索引序列查询

二者均可以用切片

其中loc可以使用条件表达式进行查询

6.4 新增数据列

  1. 直接赋值

    data[:, "new_column"] = data["col1"] + data["col2"]

  2. apply方法

    axis:0为行1为列,指定了那个axis,这个axis就要动起来

    1
    2
    3
    def get_content():
    return content
    data.loc[:, "new_column"] = data.apply(get_content, axis = 1)

  3. assign方法

    1
    2
    3
    new_data = data.assign(
    new_cloumn = lambda x: x["col1"]*33
    )
  4. 按条件选择分组分别赋值

    1
    2
    3
    data["new_clo"] = ""
    data.loc[条件1"new_col"] = value1
    data.loc[条件2"new_col"] = value2

    进度:https://www.bilibili.com/video/BV1UJ411A7Fs?p=6&vd_source=bf133d296119691c661008e881da330a&t=40.3

6.5 输出excel

1
2
data = pd.DataFrame(data=data, columns=["姓名", "学号", "加权平均分", "大类排名", "方向", "方向排名", "方向百分比"])
data.to_excel("./test.xlsx")

6.6 其他

设置不隐藏列数

1
pd.set_option('display.max_columns', None)

筛选数据

1
df1 = df[df['学生学院'] == '信息与软件工程学院(示范性软件学院)']

合并数据

1
merged_df = pd.merge(df1, df2, left_on='学号', right_on='学号', how='left')

更改列的数据类型

1
merged_df['学号'] = merged_df['学号'].astype(str)

筛选数据-以xxx开头

1
df = df[df['学号'].str.startswith('20210909')]

排序

1
df = df.sort_values(by='加权平均分', ascending=False)

除去为NaN的数据

1
self.df = self.df.dropna(subset=[destPort])

重构索引

1
2
df.reset_index(drop=True,inplace=True)
# drop删除原有索引,inplace直接替换

统计数量

1
grouped_df = df.groupby(df.columns.tolist()).size().reset_index(name='Count')

删除某一列

1
df = df.drop('Flow ID',axis=1)

筛选出目标数值在某一个列表内的数据

1
bots = grouped[grouped['Source IP'].isin(bots)]

乱序

1
df = df.sample(frac=1).reset_index(drop=True)

计算若干列的均值和方差

1
2
3
selected_columns = ['column1', 'column2']  # 替换为你实际想要的列名
mean = df[selected_columns].mean() # 平均值
variance = df[selected_columns].var() # 方差

计算若干分组的均值和方差

1
2
3
4
5
6
7
8
grouped = df_filtered.groupby(' Source IP').agg({
' Flow Duration': ['mean', 'std'],
' Packet Length Mean': ['mean', 'std']
})
若想输出到csv需要对列名进行处理
grouped.columns = ['_'.join(col).strip() for col in grouped.columns.to_flat_index()]
grouped.reset_index(inplace=True)
grouped.to_csv('数值特征.csv', index=False)

七、装饰器

闭包函数

一个函数,其参数和返回值都是函数,闭包函数的返回值是对传入函数进行增强后的结果

装饰器

本质是函数闭包,修改其他函数的功能,有助于代码更简短

注意:装饰器只在第一次调用前起作用,只增强一次

无参,无返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def a_new_decorator(fun): # 装饰器
def a_func_after_decorator():
print("hello")
fun()
print("see you")

return a_func_after_decorator


@a_new_decorator
def a_func_requiring_decoration(): # 别装饰函数
print("我是一个待装饰的函数")


a_func_requiring_decoration()
print(a_func_requiring_decoration.__name__)

# outputs:
# hello
# 我是一个待装饰的函数
# see you
# a_func_after_decorator
# 进程已结束,退出代码0

eg2:使用functools.wraps

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。--菜鸟教程

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 functools import wraps


def a_new_decorator(fun): #装饰器
@wraps(fun)
def a_func_after_decorator():
print("hello")
fun()
print("see you")

return a_func_after_decorator


@a_new_decorator
def a_func_requiring_decoration():
print("我是一个待装饰的函数")


a_func_requiring_decoration()
print(a_func_requiring_decoration.__name__)
# outputs
# hello
# 我是一个待装饰的函数
# see you
#
# 进程已结束,退出代码0

有参,有返回值

若被修饰函数有参数,则需在装饰器内定义wrapper时加入参数如"*args",wrapper内调用被修饰函数也要加入参数,另外,若被修饰函数有返回值,则在wrapper里默认是无效的,需要定义一个临时变量接受其返回值

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 time


def a_decorator(func): # 装饰器,计算函数运行时间
def wrapper(*args):
start = time.time() # 开始时间
result = func(*args)
end = time.time() # 结束时间
print("运行时间:{}".format(end-start))
return result #返回值:偶数个数

return wrapper


@a_decorator
def count_nums(maximum):# 计算从0到maxinum的偶数个数
count = 0
for i in range(0, maximum):
if i % 2 == 0:
count += 1
else:
continue
return count


print(count_nums(100000000))

# outputs:
# 运行时间:3.6575281620025635
# 50000000

八、Collections

8.1 Deque

官方文档:https://docs.python.org/zh-cn/3/library/collections.html?highlight=deque#collections.deque

说明:双向队列

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

d = deque()
d.append(1)
d.append(2)
d.append(3)
print(d)
d.appendleft(11)
d.appendleft(22)
d.appendleft(33)
print(d)
print(d.pop())
print(d.popleft())
print(d)
"""
deque([1, 2, 3])
deque([33, 22, 11, 1, 2, 3])
3
33
deque([22, 11, 1, 2])
"""

8.2 Counter

官方文档:https://docs.python.org/zh-cn/3/library/collections.html?highlight=deque#collections.Counter

说明:可以很方便的用来计数

使用样例1(计数):

1
2
3
4
5
6
7
from collections import Counter

cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
cnt[word] += 1
print(cnt)
# Counter({'blue': 3, 'red': 2, 'green': 1})

使用样例2(计数):

1
2
3
4
5
from collections import Counter

cnt = Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
print(cnt)
# Counter({'blue': 3, 'red': 2, 'green': 1})

使用样例3(筛选频率最高的前n项):

1
2
3
4
5
from collections import Counter

cnt = Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
print(cnt.most_common(2))
# [('blue', 3), ('red', 2)]

8.3 heapq

官方文档:https://docs.python.org/zh-cn/3/library/heapq.html

heapq直接存放在标准库中,不在Collections下

说明:这个模块提供了堆队列的算法,也称为优先队列算法

将列表转换为小顶堆:

1
2
3
4
5
import heapq

li = [1, 3, -1, 4, 5, 89]
heapq.heapify(li)
print(li)

插入和弹出元素:

1
2
3
4
5
6
7
import heapq

li = [1, 3, -1, 4, 5, 89]
heapq.heapify(li)
heapq.heappush(li, 33)
least_ele = heapq.heappop(li)
print(least_ele)

插入某元素后立马弹出根元素:

1
2
3
4
5
6
import heapq

li = [1, 3, -1, 4, 5, 89]
heapq.heapify(li)
ele = heapq.heappushpop(li, 33)
print(ele)

弹出根元素后插入某元素:

1
2
3
4
5
6
import heapq

li = [1, 3, -1, 4, 5, 89]
heapq.heapify(li)
ele = heapq.heapreplace(li, 33)
print(ele)

九、Pytorch

9.0 基础知识

torch.tensor与torch.Tensor有何不同?

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

# torch.tensor会自动判断类型
x = torch.tensor([1, 2])
print(torch.typename(x))
# 显式指明数据类型
y = torch.tensor([1, 2], dtype=torch.float)
print(torch.typename(y))
# torch.Tensor默认返回torch.FloatTensor类型
z = torch.Tensor([1, 2])
print(torch.typename(z))
"""
torch.LongTensor
torch.FloatTensor
torch.FloatTensor
"""

9.1 矩阵相乘

参考资料:https://www.bilibili.com/video/BV1za411S7sA?t=3.8

不考虑数学意义上的矩阵乘法:

  • torch.mul()等价于*

数学意义上的矩阵相乘:

  • torch.dot():一维
  • torch.mm():二维
  • torch.bmm():三维
  • torch.matmul(),等价于@:通用

*运算

两个矩阵按位相乘,和矩阵的乘法运算不同

1
2
3
4
5
6
7
8
import torch

x = torch.tensor([1, 2])
y = torch.tensor([2])
print(x * y) # tensor([2, 4])
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
print(x * y) # tensor([3, 8])

torch.dot()

只支持一维的矩阵相乘,注意,一维矩阵的转置实际上是没有意义的

1
2
3
4
5
6
import torch

x = torch.tensor([1, 2])
y = torch.tensor([2, 4])
print(torch.dot(x, y)) # tensor(10)
print(torch.dot(x.t(), y)) # tensor(10)

torch.mm()

只支持二维的矩阵相乘

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

x = torch.tensor([[1, 2],
[1, 2]])
y = torch.tensor([[1, 2],
[3, 4]])
print(torch.mm(x, y))
print(torch.mm(x.t(), y))
"""
tensor([[ 7, 10],
[ 7, 10]])
tensor([[ 4, 6],
[ 8, 12]])
"""

torch.bmm()

类似torch.mm(),只支持三维矩阵相乘

torch.matmul()(等价于@)

功能最强,支持广播

1
2
3
4
5
6
import torch

x = torch.tensor([[1, 2],
[1, 2]])
y = torch.tensor([1, 2])
print(x @ y) # tensor([5, 5])

十、Functools

reduce:当需要对一个可迭代对象做累积操作时使用

1
2
3
4
5
6
from functools import reduce

arr = [1, 2, 3, 4, 5]
print(reduce(lambda x, y: x * y, arr, 1))
# 接受3个参数: 函数,迭代对象,初始值
# 120

十一、包和模块

https://www.bilibili.com/video/BV194411r7a8?t=30.7

模块:为了提高代码的重用价值,将一组功能写进一个单独的.py文件中,这个.py文件就是一个模块

包:一个有层次的目录结构,定义了n个模块或子包,目录下一定有__init__.py文件

库:参照其他语言的叫法,可以是模块也可以是包

  • import与from

import的最后是一个模块,比如import A.B.C中的C。如果只使用import不使用from的话,可以使用别名简化前缀,或者增加拓展性,比如import A as p与import B as p, 可以根据需求从A和B之间选择,但是最终都是p。

如果只import包,默认不会导入包的内容。我们可以在__init__.py文件中指明默认import哪些模块(要使用绝对路径)

  • from注意事项

from A import B中A的范围一定大于B,其中B一定要达到最简化,也就是把路径尽可能放在A,其中访问取值:包>模块>模块资源

我们可以通过from 模块 import * 的方式导入模块的所有资源,但是模块中需要定义__all__=['A','B'],其中列表内是所有资源。若没有__all__,则会导入所有非下划线开头的资源

当然from 包 import * 也可以,但是需要在__init__.py中指明__all__变量,列表里面存放模块名

https://www.bilibili.com/video/BV194411r7a8?t=241.3&p=15

十二、Numpy

从正态分布中随机取值

1
2
3
4
mean = 2  # 均值
std_deviation = np.sqrt(45) # 标准差,注意方差是标准差的平方
# 生成一个随机值
random_value = np.random.normal(mean, std_deviation)

十三、其它

按照不同的概率选择元素

1
2
3
proto_choices = ['tcp', 'udp']
proto_probabilities = [0.8, 0.2]
selected_proto = random.choices(proto_choices, weights=proto_probabilities)[0]

Python
https://d4wnnn.github.io/2022/01/26/Dev/Python/
作者
D4wn
发布于
2022年1月26日
许可协议