什么是聚类？使用场景算法解析聚类算法一种典型的无监督学习算法，主要用于将相似的样本自动归到一个类别中。在聚类算法中根据样本之间的相似性，将样本划分到不同的类别中，对于不同的相似度计算方法，会得到不同的聚类结果，常用的相似度计算方法有欧式距离法。聚类算法与分类算法最大的区别聚类算法是无监督的学习算法，而分类算法属于监督的学习算法。无监督：无标签有监督：有标签K-MeansK-Means算法接受一个参数K，表示将数据集中的数据分成K个聚类。在同一个聚类中，数据的相似度较高；而不同聚类的数据相似度较低。K-Means算法的步骤为：步骤一：选择任意K个数据，作为各个聚类的质心，（质心也可以理解为中心的意思），执行步骤二。步骤二：对每个样本进行分类，将样本划分到最近的质心所在的类别，执行步骤三。步骤三：取各个聚类的中心点作为新的质心，执行步骤二进行迭代。迭代的结束条件当新的迭代后的聚类结果没有发生变化。当迭代次数达到预设的值。流程作为新质心，重新聚类，一次上述流程。收敛：设置指定迭代次数。当质心变化微乎其微时。由于每次都要计算所有样本与每一个质心之间的相似度，故在大规模的数据集上，K-Means算法的收敛速度比较慢。测试代码：import numpy as np import matplotlib.pyplot as plt from sklearn import metrics from sklearn.datasets import make_blobs # X为样本特征，Y为样本簇类别， 共1000个样本，每个样本4个特征，共4个簇，簇中心在[-1,-1], [0,0], [1,1], [2,2]， 簇方差分别为[0.4, 0.2, 0.2] X, Y = make_blobs(n_samples=1000, n_features=2, centers=[[-1, -1], [0, 0], [1, 1], [2, 2]], cluster_std=[0.4, 0.2, 0.2, 0.2], random_state=9) plt.scatter(X[:, 0], X[:, 1], marker='o') plt.show() from sklearn.cluster import KMeans y_pred = KMeans(n_clusters=2, random_state=9).fit_predict(X) plt.scatter(X[:, 0], X[:, 1], c=y_pred) plt.show() # 用Calinski-Harabasz Index评估的聚类分数 print(metrics.calinski_harabasz_score(X, y_pred)) from sklearn.cluster import KMeans y_pred = KMeans(n_clusters=3, random_state=9).fit_predict(X) plt.scatter(X[:, 0], X[:, 1], c=y_pred) plt.show() print(metrics.calinski_harabasz_score(X, y_pred)) from sklearn.cluster import KMeans y_pred = KMeans(n_clusters=4, random_state=9).fit_predict(X) plt.scatter(X[:, 0], X[:, 1], c=y_pred) plt.show() print(metrics.calinski_harabasz_score(X, y_pred))结果：效果衡量SSE：误差平方和SSE(左图) < SSE(右图)肘部法Elbow method就是“肘”方法：对于n个点的数据集，迭代计算k from 1 to n，每次聚类完成后计算每个点到其所属的簇中心的距离的平方和。平方和是会逐渐变小的，直到k=n时平方和为0，因为每个点都是它所在的簇中心本身。在这个平方和变化过程中，会出现一个拐点也即“肘”点，下降率突然变缓时即认为是最佳的K值。import numpy as np from sklearn.cluster import KMeans from scipy.spatial.distance import cdist import matplotlib.pyplot as plt # 生成数据 cluster1 = np.random.uniform(0.5, 1.5, (2, 10)) cluster2 = np.random.uniform(3.5, 4.5, (2, 10)) X = np.hstack((cluster1, cluster2)).T # plt.figure() # plt.axis([0, 5, 0, 5]) # plt.grid(True) # plt.plot(X[:,0],X[:,1],'k.'); K = range(1, 10) meandistortions = [] for k in K: kmeans = KMeans(n_clusters=k) kmeans.fit(X) meandistortions.append(sum(np.min(cdist(X, kmeans.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0]) plt.plot(K, meandistortions, 'bx-') plt.xlabel('k') # plt.ylabel('平均畸变程度',fontproperties=font) plt.ylabel('Ave Distor') # plt.title('用肘部法则来确定最佳的K值',fontproperties=font); plt.title('Elbow method value K'); plt.show()SC系数：轮廓系数法结合了聚类的凝聚度（Cohesion）和分离度（Separation），用于评估聚类的效果。（Silhouette Coefficient）import numpy as np import pandas as pd from sklearn.cluster import KMeans from sklearn.metrics import silhouette_samples, silhouette_score import matplotlib.pyplot as plt import matplotlib.cm as cm import seaborn as sns input_data = pd.read_csv("./mall_customers.csv") input_data.head() input_data.shape input_data.isnull().sum() # selecting features x = input_data.iloc[:,[3,4]].values # Elbow Method score = [] for cluster in range(1,11): kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10) kmeans.fit(x) score.append(kmeans.inertia_) # plotting the score plt.plot(range(1,11), score) plt.title('The Elbow Method') plt.xlabel('no of clusters') plt.ylabel('wcss') plt.show() # Silhouette score for n_clusters in range(2,11): # Create a subplot with 1 row and 2 columns fig, (ax1, ax2) = plt.subplots(1, 2) fig.set_size_inches(18, 7) # The 1st subplot is the silhouette plot # The silhouette coefficient can range from -1, 1 but in this example all # lie within [-0.1, 1] ax1.set_xlim([-0.1, 1]) # The (n_clusters+1)*10 is for inserting blank space between silhouette # plots of individual clusters, to demarcate them clearly. ax1.set_ylim([0, len(x) + (n_clusters + 1) * 10]) # Initialize the clusterer with n_clusters value and a random generator # seed of 10 for reproducibility. clusterer = KMeans(n_clusters=n_clusters, random_state=10) cluster_labels = clusterer.fit_predict(x) # The silhouette_score gives the average value for all the samples. # This gives a perspective into the density and separation of the formed # clusters silhouette_avg = silhouette_score(x, cluster_labels) print("For n_clusters =", n_clusters, "The average silhouette_score is :", silhouette_avg) # Compute the silhouette scores for each sample sample_silhouette_values = silhouette_samples(x, cluster_labels) y_lower = 10 for i in range(n_clusters): # Aggregate the silhouette scores for samples belonging to # cluster i, and sort them ith_cluster_silhouette_values = \ sample_silhouette_values[cluster_labels == i] ith_cluster_silhouette_values.sort() size_cluster_i = ith_cluster_silhouette_values.shape[0] y_upper = y_lower + size_cluster_i color = cm.nipy_spectral(float(i) / n_clusters) ax1.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7) # Label the silhouette plots with their cluster numbers at the middle ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i)) # Compute the new y_lower for next plot y_lower = y_upper + 10 # 10 for the 0 samples ax1.set_title("The silhouette plot for the various clusters.") ax1.set_xlabel("The silhouette coefficient values") ax1.set_ylabel("Cluster label") # The vertical line for average silhouette score of all the values ax1.axvline(x=silhouette_avg, color="red", linestyle="--") ax1.set_yticks([]) # Clear the yaxis labels / ticks ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1]) # 2nd Plot showing the actual clusters formed colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters) ax2.scatter(x[:, 0], x[:, 1], marker='.', s=30, lw=0, alpha=0.7, c=colors, edgecolor='k') # Labeling the clusters centers = clusterer.cluster_centers_ # Draw white circles at cluster centers ax2.scatter(centers[:, 0], centers[:, 1], marker='o', c="white", alpha=1, s=200, edgecolor='k') for i, c in enumerate(centers): ax2.scatter(c[0], c[1], marker='$%d$' % i, alpha=1, s=50, edgecolor='k') ax2.set_title("The visualization of the clustered data.") ax2.set_xlabel("Feature space for the 1st feature") ax2.set_ylabel("Feature space for the 2nd feature") plt.suptitle(("Silhouette analysis for KMeans clustering on sample data " "with n_clusters = %d" % n_clusters), fontsize=14, fontweight='bold') plt.show()CH系数算法优化原始算法优缺点优点原理简单，容易实现。聚类效果中上（依赖K的选择）。空间复杂度$O(n)$，时间复杂度$O(I*K*N)$。（N为样本点数，K为中心点个数，I为迭代次数）缺点对离群点，噪声敏感（中心点易偏移）。很难发现大小差别很大的簇及进行增量计算。结果不一定是全局最优，只能保证局部最优（与K的个数及初值选取有关）。Canopy算法配合初始聚类Canopy算法的作用在于它是通过事先粗聚类的方式，为K-means算法确定初始聚类中心个数和聚类中心点。优点：K-means对噪声抗干扰较弱，通过Canopy对比，将较小的NumPoint的Cluster直接去掉有利于抗干扰。Canopy选择出来的每个Canopy的centerPoint作为K会更精确。只是针对每个Canopy的内做K-means聚类，减少相似计算的数量。不足：算法中T1, T2的确定问题。K-means++$P=\frac{D(x)^2}{ {\textstyle \sum_{x\in X}^{}D(x)^2} }$K-Means++算法采用下列步骤给定K个初始质点：从数据集中任选一个节点作为第一个聚类中心。对数据集中的每个点x，计算x到所有已有聚类中心点的距离和D(X)，基于D(X)采用线性概率选择出下一个聚类中心点(距离较远的一个点成为新增的一个聚类中心点)。重复步骤2直到找到K个聚类中心点。缺点：由于聚类中心点选择过程中的内在有序性，在扩展方面存在着性能方面的问题(第K个聚类中心点的选择依赖前K-1个聚类中心点的值)二分K-means解决K-Means算法对初始簇心比较敏感的问题，二分K-Means算法是一种弱化初始质心的一种算法，具体思路步骤如下：1、将所有样本数据作为一个簇放到一个队列中。2、从队列中选择一个簇进行K-means算法划分，划分为两个子簇，并将子簇添加到队列中。3、循环迭代第二步操作，直到中止条件达到(聚簇数量、最小平方误差、迭代次数等)。4、队列中的簇就是最终的分类簇集合。Kernel K-meansKernel K-means，将每个样本进行一个投射到高维空间的处理，然后再将处理后的数据使用普通的k-means算法思想进行聚类。K-medoidsK-medoids和K-means是有区别的，不一样的地方在于中心点的选取：K-means中，将中心点取为当前cluster中所有数据点的平均值，对异常点很敏感。K-medoids中，将从当前cluster 中选取到其他所有（当前cluster中的）点的距离之和最小的点作为中心点。算法流程：总体n个样本点中任意选取k个点作为medoids。按照与medoids最近的原则，将剩余的n-k个点分配到当前最佳的medoids代表的类中。对于第i个类中除对应medoids点外的所有其他点，按顺序计算当其为新的medoids时，代价函数的值，遍历所有可能，选取代价函数最小时对应的点作为新的medoids。重复2-3的过程，直到所有的medoids点不再发生变化或已达到设定的最大迭代次数。产出最终确定的k个类。优缺点：K-medoids对噪声的鲁棒性好。K-medoids只能对小样本起作用，样本大速度太慢。K-medoids较K-means来说，多次运行每次结果偏差较小，而k-means对初值依赖大，导致每次运行结果相异程度大。对比：ISODATAInterative Self Organizing Data Anslysis Techniques AlgorithmK-means和K-means++的聚类中心数K是固定不变的。而ISODATA算法在运行过程中能够根据各个类别的实际情况进行两种操作来调整聚类中心数K：(1)分裂操作，对应着增加聚类中心数；(2)合并操作，对应着减少聚类中心数。该算法能够在聚类过程中根据各个类所包含样本的实际情况动态调整聚类中心的数目。如果某个类中样本分散程度较大（通过方差进行衡量）并且样本数量较大，则对其进行分裂操作；如果某两个类别靠得比较近（通过聚类中心的距离衡量），则对它们进行合并操作。Mini Batch K-Means适合大数据的聚类算法。Mini Batch KMeans使用了Mini Batch（分批处理）的方法对数据点之间的距离进行计算。Mini Batch计算过程中不必使用所有的数据样本，而是从不同类别的样本中抽取一部分样本来代表各自类型进行计算。由于计算样本量少，所以会相应的减少运行时间，但另一方面抽样也必然会带来准确度的下降。步骤：从数据集中随机抽取一些数据形成小批量，把他们分配给最近的质心。更新质心。区别：与K-means相比，数据的更新在每一个小的样本集上。对于每一个小批量，通过计算平均值得到更新质心，并把小批量里的数据分配给该质心，随着迭代次数的增加，这些质心的变化是逐渐减小的，直到质心稳定或者达到指定的迭代次数，停止计算。算法进阶DBSCAN(基于密度聚类)参数1：半径（Eps），表示以给定点P为中心的圆形邻域的范围。参数2：以点P为中心的邻域内最少点的数量（MinPts）。如果满足：以点P为中心、半径为Eps的邻域内的点的个数不少于MinPts，则称点P为核心点。步骤：将所有点标记为核心点，边界点或噪声点。删除噪声点。为距离在Eps之内的所有核心点之间赋予一条边。每组连通的核心点形成一个簇。讲每个边界点都指派到一个与之关联的核心点的簇中。优点：聚类速度快且能够有效处理噪声点和发现任意形状的空间聚类。与K-Means比较，不需要输入要划分的聚类个数。可以在需要输入过滤噪声的参数，且聚类簇形状较稳定可靠。缺点：数据量增大时，要求较大的内存支持且I/O消耗也很大。当聚类的密度不均匀、聚类间距相差很大时，聚类质量较差，此时参数MinPts和Eps选取困难。算法聚类效果依赖于距离公式选取，实际应用中常用欧氏距离，对于高维数据，存在“维数灾难”。OPTICS(Ordering points to identify the clustering structure)是一基于密度的聚类算法，OPTICS算法是DBSCAN的改进版本。层次聚类先计算样本之间的距离。每次将距离最近的点合并到同一个类。然后，再计算类与类之间的距离，将距离最近的类合并为一个大类。不停的合并，直到合成了一个类。其中类与类的距离的计算方法有：最短距离法，最长距离法，中间距离法，类平均法等。MIN度量MAX度量Group Average（平均距离度量）Distance Between Centroids（质心度量）Other methods driven by an objective function层次聚类可以分为两种主要类型：凝聚型（agglomerative）和分裂型（divisive）。凝聚聚类：它也被称为AGNES（凝聚嵌套）。 它以自下而上的方式工作。 也就是说，每个对象最初被认为是单元素簇（叶子）。 在算法的每个步骤中，将最相似的两个群集组合成新的更大的群集（节点）。 迭代此过程，直到所有点都只是一个单个大簇（root）的成员（参见下图）。 结果是一棵树，可以绘制为树状图。分裂层次聚类：它也被称为DIANA（Divise Analysis），它以自上而下的方式工作。 该算法是AGNES的逆序。 它以root开头，其中所有对象都包含在单个集群中。 在迭代的每个步骤中，最异构的集群被分成两个。 迭代该过程，直到所有对象都在它们自己的集群中（见下图）。其中，凝聚聚类擅长识别小聚类。 分裂层次聚类擅长识别大型集群。步骤：孤点：将每个对象看作一类，计算两两之间的最小距离。合并：将距离最小的两类合并成一个新类。迭代：重新计算新类与所有类之间的距离。统一：重复(2)(3)直到所有类最后合并成一类。优点：距离相似度易定义，限制少。不需要预先制定聚类数。可以发现类的层次关系。缺点：合并决策是最终的。一旦合并，不可撤销。计算复杂度较高。奇异值易产生很大影响，算法很可能聚类成链状。应用：Mean Shift聚类Mean Shift（均值漂移）是基于密度的非参数聚类算法，其算法思想是假设不同簇类的数据集符合不同的概率密度分布，找到任一样本点密度增大的最快方向（最快方向的含义就是Mean Shift），样本密度高的区域对应于该分布的最大值，这些样本点最终会在局部密度最大值收敛，且收敛到相同局部最大值的点被认为是同一簇类的成员。Affinity Propagation (AP)聚类AP(Affinity Propagation)算法,称为仿射传播聚类算法、近邻传播聚类算法、亲和传播聚类算法，是根据数据点之间的相似度来进行聚类，可以是对称的，也可以是不对称的。该算法不需要先确定聚类的数目，而是把所有的数据点都看成潜在意义上的聚类中心（exemplar）。优点：不需要制定最终聚类族的个数。已有的数据点作为最终。的聚类中心， 而不是新生成一个族中心。模型对数据的初始值不敏感。对初始相似度矩阵数据的对称性没有要求。缺点：AP算法需要事先计算每对数据对象之间的相似度， 如果数据对象太多的话， 内存放不下，若存在数据库， 频繁访问数据库也需要时间。AP算法的时间复杂度较高，一次迭代大概$O(N^3)$聚类的好坏受到参考度和阻尼系数的影响。扩展：Label Propagation 算法是一种基于标签传播的局部社区划分算法。对于网络中的每一个节点，在初始阶段，Label Propagation 算法对每个节点初始化一个唯一的标签，在每次的迭代过程中，每个节点根据与其相连的节点所属的标签改变自己的标签，更改的原则是选择与其相连的节点中所属标签最多的社区标签为自己的社区标签，这便是标签传播的含义。随着社区标签不断传播，最终，连接紧密的节点将有共同的标签。Label Propagation算法包括两大步骤：(1)构造相似矩阵；(2)标签传播。SOM聚类SOM 即自组织映射，是一种用于特征检测的无监督学习神经网络。它模拟人脑中处于不同区域的神经细胞分工不同的特点，即不同区域具有不同的响应特征，而且这一过程是自动完成的。SOM 用于生成训练样本的低维空间，可以将高维数据间复杂的非线性统计关系转化为简单的几何关系，且以低维的方式展现，因此通常在降维问题中会使用它。SOM 的训练过程：紫色区域表示训练数据的分布状况，白色网格表示从该分布中提取的当前训练数据。SOM 节点位于数据空间的任意位置，最接近训练数据的节点（黄色高亮部分）会被选中。它和网格中的邻近节点一样，朝训练数据移动。在多次迭代之后，网格倾向于近似该种数据分布（下图最右）步骤：将网格的神经元随机定位在数据空间中。选择一个数据点，按顺序随机或系统地循环遍历数据集找到最接近所选数据点的神经元。这种神经元被称为最佳匹配单元BMU。将BMU移近该数据点。 BMU移动的距离由学习速率确定，学习速率在每次迭代后减小。将BMU的邻居移动到更靠近该数据点的位置，远处的邻居移动得更少。使用BMU周围的半径来识别邻居，并且在每次迭代之后该半径的值减小。在重复步骤1到4之前，更新学习速率和BMU半径。迭代这些步骤，直到神经元的位置稳定。应用：SOM 通常用在可视化中。比如右图，世界各国贫困数据的可视化。生活质量较高的国家聚集在左上方，而贫困最严重的国家聚集在右下方。数据压缩语音识别分离音源欺诈检测谱聚类谱聚类：是一种基于图论的聚类方法，通过对样本数据的拉普拉斯矩阵的特征向量进行聚类。图（Graph）：由若干点及连接两点的线所构成的图形，通常用来描述某些事物之间的某种关系，用点代表事物，线表示对应两个事物间具有这种关系。优点：稀疏处理：谱聚类只需要数据之间的相似度矩阵，因此对于处理稀疏数据的聚类很有效。高维处理：使用了降维，因此在处理高维数据聚类时的复杂度比传统聚类算法好，在高维数据上的表现尤为明显。缺点：K值只能靠猜测。聚类效果依赖于相似矩阵，不同的相似矩阵得到的最终聚类效果可能不同。总结参考链接：https://www.kaggle.com/abhishekyadav5/kmeans-clustering-with-elbow-method-and-silhouettehttps://www.bilibili.com/video/BV1jb411p7ZFhttps://www.cnblogs.com/yixuan-xu/p/6272208.htmlhttps://www.cnblogs.com/jin-liang/p/9527522.htmlhttps://file.moluuser.com/doc/%E8%81%9A%E7%B1%BB%E4%B8%93%E9%A2%98%E2%80%94Note_20190210190259.pdf
前排感谢这个开源项目：https://github.com/Morizeyao/GPT2-Chinese记录下运行以上项目的流程。运行环境导入语料由于使用单一文本进行训练，只需要把数据集放置在./data/train.json即可。如果需要合并txt文本，使用批处理type *.txt>>all.txt即可。模型训练python train_single.py --raw文本生成python ./generate.py --length=400 --nsamples=4 --prefix=xxx --fast_pattern --save_samples --save_samples_path=/mnt/xx参数说明--length：参数为生成文本的长度。 --prefix：生成文章的开头。 --fast_pattern：如果生成的length参数比较小，速度基本无差别，默认不采用fast_pattern方式。 --save_samples：默认将输出样本直接打印到控制台，传递此参数，将保存在根目录下的samples.txt。 --save_samples_path：可自行指定保存的目录，默认可递归创建多级目录，不可以传递文件名称，文件名称默认为samples.txt。结果这里model使用的是hughqiu训练生成模型，感谢分享。Others可能需要修改的地方在train.py中： #lines = json.load(f) lines = f.readlines() #full_tokenizer.max_len = 999999其他类似开源项目https://github.com/hughqiu/GPT2-Chinesehttps://github.com/jianyq/Tong-Musichttps://github.com/GaoPeng97/transformer-xl-chinesehttps://github.com/yangjianxin1/GPT2-chitchat
BeginPython下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。项目目录结构 |--project |--__init__.py 空文件 |--settings.py 项目的配置文件 |--urls.py 路由定义 |--wsgi.py 与服务器对接 本地化settings.py内 LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' 修改为： LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' 新建静态目录网站通常需要提供类似图片，JavaScript 或 CSS 的额外文件服务。在 Django 中，我们将这些文件称为“静态文件”。Django 提供了 django.contrib.staticfiles 帮你管理它们。添加以下配置： STATIC_URL = '/static/' # 新建static文件夹 STATICFILES_DIRS = os.path.join(BASE_DIR, "static") 数据库配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydatabase', 'USER': 'mydatabaseuser', 'PASSWORD': 'mypassword', 'HOST': '127.0.0.1', 'PORT': '5432', } } 详见：https://docs.djangoproject.com/zh-hans/3.0/ref/settings/#std:setting-DATABASES服务启动python manage.py runserver 0.0.0.0:8080外部访问：ALLOWED_HOSTS = ['*']创建APPpython manage.py startapp user创建后项目目录会存在user文件夹Hello world在user/views.py内 from django.http import HttpResponse def index(request): return HttpResponse('Hello World!') 在urls.py内 from user import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index), ] 在Django2.0前用url(r'正则表达式', '视图函数')路由在 settings.py内的 ROOT_URLCONF = 'untitled1.urls'找到 urls.py路由表路由传参在views内 def show_article(requset, num, name): return HttpResponse(str(num)+name) 在urls内 path('article/<int:num><str:name>', views.show_article), [scode type="share"]函数 path() 具有四个参数，两个必须参数：route 和 view，两个可选参数：kwargs 和 name。现在，是时候来研究这些参数的含义了。path() 参数： routeroute 是一个匹配 URL 的准则（类似正则表达式）。当 Django 响应一个请求时，它会从 urlpatterns 的第一项开始，按顺序依次匹配列表中的项，直到找到匹配的项。这些准则不会匹配 GET 和 POST 参数或域名。例如，URLconf 在处理请求 https://www.example.com/myapp/ 时，它会尝试匹配 myapp/ 。处理请求 https://www.example.com/myapp/?page=3 时，也只会尝试匹配 myapp/。path() 参数： view当 Django 找到了一个匹配的准则，就会调用这个特定的视图函数，并传入一个 HttpRequest 对象作为第一个参数，被“捕获”的参数以关键字参数的形式传入。稍后，我们会给出一个例子。path() 参数： kwargs任意个关键字参数可以作为一个字典传递给目标视图函数。本教程中不会使用这一特性。path() 参数： name为你的 URL 取名能使你在 Django 的任意地方唯一地引用它，尤其是在模板中。这个有用的特性允许你只改一个文件就能全局地修改某个 URL 模式。[/scode]主子路由在APP里新建 urls.py主路由中定义 path('user/', include('user.urls'))配置APP内的路由 path('login', login)视图视图函数格式 def xxx(request): return response对象 request请求由请求行，请求头，请求体组成 def index(request): print(request.path) print(request.method) print(request.is_ajax()) print(request.scheme) print(request.GET) print(request.POST) print(request.FILES) print(request.META.get('REMOTE_ADDR')) # 运行结果 # / # GET # False # http # < QueryDict: {} > # < QueryDict: {} > # < MultiValueDict: {} > # 127.0.0.1 return HttpResponse('Hello World!') response响应由响应行，响应头，响应体组成reder函数通过模板引擎Django加载模板，将模板加载完成后转成 str类，再将 str给 HttpResponse并返回 response对象。redirect + reverse函数先reverse反转，再由redirect进行重定向在主路由上添加namespace。并在每个urls.py中添加 app_name。在子路由的urlpatterns每一个路由上定义namereverse('namespace:name')模板注释{# #}向模板传参在views.py内 def test(request): name = 'admin' day = datetime.now() return render(request, 'index.html', context={'name': name, 'day': day}) 模板内 用户：{{ name }} 当前时间：{{ day }} 支持的类型str, int, float, list(name.no), tuple, dict, set, object循环 {{ question.question_text }} {% for choice in question.choice_set.all %} {{ choice.choice_text }} {% endfor %} 过滤器loweruppertitlecapfirstlengthdefaultslive(切片)cut(删去指定字符)floatformatrandom(随机获取列表中值)join(列表中拼接并展示)date(格式化日期'Y/m/d', 'Y-m-d')time(格式化时间'H:i:s'大H表示24H制)add(整数)firstlastsafe(不对字符进行转移，比如 )... 标签不再自动转义 {% autoescape on %} {{ body }} {% endautoescape %} 循环 {% for o in some_list %} {{ forloop.revcounter0 }}{{ o }} {% empty %} 空！ {% endfor %} 双层for循环 {% forloop.parentloop.counter %} if{% if %} 标签会判断给定的变量，当变量为True时（比如存在、非空、非布尔值False），就会输出块内的内容: {% if athlete_list %} Number of athletes: {% elif athlete_in_locker_room_list %} Athletes should be out of the locker room soon! {% else %} No athletes. {% endif %} {% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if not athlete_list %} There are no athletes. {% endif %} {% if athlete_list or coach_list %} There are some athletes or some coaches. {% endif %} {% if not athlete_list or coach_list %} There are no athletes or there are some coaches. {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %} url action中： {% url 'user:login' %} {% csrf_token %} .... views.py中： def login(request): if request.method == 'POST': # TODO else: # 在模板中显示msg render(request, 'login.html', {'msg': 'error!'}) return render(request, 'login.html') CSRF（Cross-site request forgery）跨站请求伪造，是一种常见的网络攻击手段当表单数据通过POST方法，发送到后台服务器的时候，除了正常的表单数据外，还会携带一个CSRF令牌随机字符串，用于进行csrf验证。详见：https://docs.djangoproject.com/zh-hans/3.0/ref/templates/builtins/模板继承 模板页面： {% extends common.html %} {% block title %} 子页面： {% block title %} body {% endblock %} static标签static标签用于链接保存在 STATIC_ROOT中的静态文件。例如： {% load static %} 还可以使用变量： {% load static %} 还可以像下面这么使用： {% load static %} {% static "images/hi.jpg" as myphoto %} 自定义标签和过滤器详见：https://www.liujiangblog.com/course/django/150模型一个模型（model）就是一个单独的、确定的数据的信息源，包含了数据的字段和操作方法。通常，每个模型映射为一张数据库中的表。每个模型在Django中的存在形式为一个Python类每个模型都是django.db.models.Model的子类模型的每个字段（属性）代表数据表的某一列Django将自动为你生成数据库访问API from django.db import models class User(models.Model): username = models.CharField(max_length=30, unique=True, error_messages='必须唯一！') 模型的元数据Meta模型的元数据，指的是“除了字段外的所有内容”，例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的，甚至元数据本身对模型也是非必须的。步骤1 . 定义模型类比如：class User(models.Model): username = models.CharField(max_length=255, null=False) password = models.CharField(max_length=255, null=False) role = models.CharField(max_length=255, default='管理员') class Meta: db_table = 'user'2 . 在 INSTALLED_APPS添加APP比如：'dashboard.apps.DashboardConfig',迁移和同步 # 同步 python manage.py makemigrations # 在migrations文件夹产生一个文件 python manage.py migrate 执行后，数据库会自动新建表。数据库的增删改查查询指定关键字 if request.method == 'POST': keyword = request.POST.get("keyword", None) result = ZhihuQue.objects.filter(title__contains=keyword)[:2000] return render(request, 'dashboard/search.html', {'result': result, 'keyword': keyword, 'cnt': result.count()}) else: return render(request, 'dashboard/search.html') 随机查询n条记录 zhihuques = ZhihuQue.objects.order_by('?')[:100] return render(request, 'dashboard/zhihuque.html', {'zhihuques': zhihuques}) 查询所有 users = User.objects.all() return render(request, 'dashboard/users.html', {'users': users}) 用户注册 # 注册 user = User() user.username = username user.password = hashlib.sha256(password.encode('utf-8')).hexdigest() user.save() 用户登录 username = request.POST.get('username') password = request.POST.get('password') user = User.objects.filter(username=username).first() if user: if user.password == hashlib.sha256(password.encode('utf-8')).hexdigest(): # 登陆成功 request.session['username'] = user.username request.session['usersum'] = User.objects.count() return render(request, 'dashboard/dashboard.html') else: hashkey = CaptchaStore.generate_key() image_url = captcha_image_url(hashkey) captcha = {'hashkey': hashkey, 'image_url': image_url} return render(request, 'dashboard/login.html', {'msg': '用户名或密码错误！', "captcha": captcha}) else: hashkey = CaptchaStore.generate_key() image_url = captcha_image_url(hashkey) captcha = {'hashkey': hashkey, 'image_url': image_url} return render(request, 'dashboard/login.html', {'msg': '用户名或密码错误！', "captcha": captcha}) 修改 user.password = hashlib.sha256(pwd.encode('utf-8')).hexdigest() user.save() return render(request, 'dashboard/edit.html', {'msg': '修改成功！', 'user': user}) 删除 user = User.objects.get(username=username) user.delete() # return redirect(users) return render(request, 'dashboard/users.html', {'msg': '删除成功！'}) 使用Redis缓存配置在settings.py中插入： CACHES = { "default": { 'BACKEND': 'django_redis.cache.RedisCache', "LOCATION": "redis://ip:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "PASSWORD": "foobared" } } } 使用 if cache.get('zhihuusers') is None: print('from db') zhihuusers = ZhihuUser.object.all() cache.set('zhihuusers', zhihuusers) else: print('from cache') return render(request, 'zhihuuser.html', {'zhihuusers': cache.get('zhihuusers')}) 测试部署只能测试使用，生产环境部署需要NGINX和uWSGInohup python3 manage.py runserver 0:80 &记录下学习Django做的Web大致实现了用户注册登录，验证码，数据库数据的分页显示。参考链接：https://www.liujiangblog.com/course/djangohttps://www.mf8.biz/rhel8-centos8-install-mysql-8-0/https://www.myfreax.com/how-to-install-mysql-on-centos-8/https://blog.csdn.net/qq_26563299/article/details/80396310https://www.howtoforge.com/how-to-install-django-on-centos-8/
Begin想把之前的体育日记生成的Python脚本部署到线上，一开始想用Java，发现一头雾水啊，改用PHP，前端用的 bootstrap把Python脚本改为接收参数una = sys.argv[1] uno = sys.argv[2] ute = sys.argv[3] usex = sys.argv[4]PHP根据用户表单输入构造命令使用 shell_exec($cmd);来执行Python脚本用 zip命令打包// 这个函数是在网上查到的，找不到出处了 // 避免同一个学号多次使用而重复 function getRandomStr($len, $special=true){ $chars = array( "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ); if($special){ $chars = array_merge($chars, array( "!", "@", "#", "$", "?", "|", "{", "/", ":", ";", "%", "^", "&", "*", "(", ")", "-", "_", "[", "]", "}", "<", ">", "~", "+", "=", ",", "." )); } $charsLen = count($chars) - 1; shuffle($chars); //打乱数组顺序 $str = ''; for($i=0; $i<$len; $i++){ $str .= $chars[mt_rand(0, $charsLen)]; //随机取出一位 } return $str; } $ran = $uno.getRandomStr(5, false).'.zip'; $zipcmd = 'zip -q -r '.$ran.' '.$uno; shell_exec($zipcmd);使用 shell_exec注意如果 php.ini中配置了使用安全模式，则无法使用。如果 php.ini中禁用的了该函数，也无法使用效果
Begin因为疫情不开学了，在家上体育课。老师非要写几十篇体育笔记。所以有了这个程序。使用Python-Docx处理Word文件。参照狗屁不通文章生成器的套路生成锻炼的感想。其他的都是固定的写法。一开始试着用了GPT2 Chinese训练好的现成模型，结果发现输入体育相关的关键词返回的是这样的段落这是用言情小说训练出来的模型？？运行结果代码[collapse title="使用到的JSON数据文件" status="false"]{"famous":["爱迪生a，天才是百分之一的勤奋加百分之九十九的汗水。b","毛泽东a，身体是革命的本钱。b","伏尔泰a，生命在于运动。b","查尔斯·史a，一个人几乎可以在任何他怀有无限热忱的事情上成功。b","培根说过，深窥自己的心，而后发觉一切的奇迹在你自己。b","歌德曾经a，流水在碰到底处时才会释放活力。b","戴尔·卡耐基a，多数人都拥有自己不了解的能力和机会，都有可能做到未曾梦想的事情。b","白哲特a，坚强的信念能赢得强者的心，并使他们变得更坚强。b","伏尔泰a，不经巨大的困难，不会有伟大的事业。b","富勒曾经a，苦难磨炼一些人，也毁灭另一些人。b","文森特·皮尔a，改变你的想法，你就改变了自己的世界。b","拿破仑·希尔a，不要等待，时机永远不会恰到好处。b","塞涅卡a，生命如同寓言，其价值不在与长短，而在与内容。b","奥普拉·温弗瑞a，你相信什么，你就成为什么样的人。b","吕凯特a，生命不可能有两次，但许多人连一次也不善于度过。b","莎士比亚a，人的一生是短的，但如果卑劣地过这一生，就太长了。b","笛卡儿a，我的努力求学没有得到别的好处，只不过是愈来愈发觉自己的无知。b","左拉a，生活的道路一旦选定，就要勇敢地走到底，决不回头。b","米歇潘a，生命是一条艰险的峡谷，只有勇敢的人才能通过。b","吉姆·罗恩a，要么你主宰生活，要么你被生活主宰。b","日本谚语a，不幸可能成为通向幸福的桥梁。b","海贝尔a，人生就是学校。在那里，与其说好的教师是幸福，不如说好的教师是不幸。b","杰纳勒尔·乔治·S·巴顿a，接受挑战，就可以享受胜利的喜悦。b","德谟克利特a，节制使快乐增加并使享受加强。b","裴斯泰洛齐a，今天应做的事没有做，明天再早也是耽误了。b","歌德a，决定一个人的一生，以及整个命运的，只是一瞬之间。b","卡耐基a，一个不注意小事情的人，永远不会成就大事业。b","卢梭a，浪费时间是一桩大罪过。b","康德a，既然我已经踏上这条道路，那么，任何东西都不应妨碍我沿着这条路走下去。b","克劳斯·莫瑟爵士a，教育需要花费钱，而无知也是一样。b","伏尔泰a，坚持意志伟大的事业需要始终不渝的精神。b","亚伯拉罕·林肯a，你活了多少岁不算什么，重要的是你是如何度过这些岁月的。b","韩非a，内外相应，言行相称。b","富兰克林a，你热爱生命吗？那么别浪费时间，因为时间是组成生命的材料。b","马尔顿a，坚强的信心，能使平凡的人做出惊人的事业。b","笛卡儿a，读一切好书，就是和许多高尚的人谈话。b","塞涅卡a，真正的人生，只有在经过艰难卓绝的斗争之后才能实现。b","易卜生a，伟大的事业，需要决心，能力，组织和责任感。b","歌德a，没有人事先了解自己到底有多大的力量，直到他试过以后才知道。b","达尔文a，敢于浪费哪怕一个钟头时间的人，说明他还不懂得珍惜生命的全部价值。b","佚名a，感激每一个新的挑战，因为它会锻造你的意志和品格。b","奥斯特洛夫斯基a，共同的事业，共同的斗争，可以使人们产生忍受一切的力量。 b","苏轼a，古之立大事者，不惟有超世之才，亦必有坚忍不拔之志。b","王阳明a，故立志者，为学之心也；为学者，立志之事也。b","歌德a，读一本好书，就如同和一个高尚的人在交谈。b","乌申斯基a，学习是劳动，是充满思想的劳动。b","别林斯基a，好的书籍是最贵重的珍宝。b","富兰克林a，读书是易事，思索是难事，但两者缺一，便全无用处。b","鲁巴金a，读书是在别人思想的帮助下，建立起自己的思想。b","培根a，合理安排时间，就等于节约时间。b","屠格涅夫a，你想成为幸福的人吗？但愿你首先学会吃得起苦。b","莎士比亚a，抛弃时间的人，时间也抛弃他。b","叔本华a，普通人只想到如何度过时间，有才能的人设法利用时间。b","博a，一次失败，只是证明我们成功的决心还够坚强。 维b","拉罗什夫科a，取得成就时坚持不懈，要比遭到失败时顽强不屈更重要。b","莎士比亚a，人的一生是短的，但如果卑劣地过这一生，就太长了。b","俾斯麦a，失败是坚忍的最后考验。b","池田大作a，不要回避苦恼和困难，挺起身来向它挑战，进而克服它。b","莎士比亚a，那脑袋里的智慧，就像打火石里的火花一样，不去打它是不肯出来的。b","希腊a，最困难的事情就是认识自己。b","黑塞a，有勇气承担命运这才是英雄好汉。b","非洲a，最灵繁的人也看不见自己的背脊。b","培根a，阅读使人充实，会谈使人敏捷，写作使人精确。b","斯宾诺莎a，最大的骄傲于最大的自卑都表示心灵的最软弱无力。b","西班牙a，自知之明是最难得的知识。b","塞内加a，勇气通往天堂，怯懦通往地狱。b","邓拓a，越是没有本领的就越加自命不凡。b","爱尔兰a，越是无能的人，越喜欢挑剔别人的错儿。b","歌德a，意志坚强的人能把世界放在手中像泥块一样任意揉捏。b","迈克尔·F·斯特利a，最具挑战性的挑战莫过于提升自我。b","爱迪生a，失败也是我需要的，它和成功对我一样有价值。b","罗素·贝克a，一个人即使已登上顶峰，也仍要自强不息。b","马云a，最大的挑战和突破在于用人，而用人最大的突破在于信任人。b","培根a，要知道对好事的称颂过于夸大，也会招来人们的反感轻蔑和嫉妒。b","莫扎特a，谁和我一样用功，谁就会和我一样成功。b","马克思a，一切节省，归根到底都归结为时间的节省。b","莎士比亚a，意志命运往往背道而驰，决心到最后会全部推倒。b","卡莱尔a，过去一切时代的精华尽在书中。b","培根a，深窥自己的心，而后发觉一切的奇迹在你自己。b","罗曼·罗兰a，只有把抱怨环境的心情，化为上进的力量，才是成功的保证。b","孔子a，知之者不如好之者，好之者不如乐之者。b","达·芬奇a，大胆和坚定的决心能够抵得上武器的精良。b","叔本华a，意志是一个强壮的盲人，倚靠在明眼的跛子肩上。b","黑格尔a，只有永远躺在泥坑里的人，才不会再掉进坑里。b","普列姆昌德a，希望的灯一旦熄灭，生活刹那间变成了一片黑暗。b","维龙a，要成功不需要什么特别的才能，只要把你能做的小事做得好就行了。b","郭沫若a，形成天才的决定因素应该是勤奋。b","洛克a，学到很多东西的诀窍，就是一下子不要学很多。b","拉罗什福科a，我们唯一不会改正的缺点是软弱。b","亚伯拉罕·林肯a，我这个人走得很慢，但是我从不后退。b","美华纳a，勿问成功的秘诀为何，且尽全力做你应该做的事吧。b","俾斯麦a，对于不屈不挠的人来说，没有失败这回事。b","阿卜·日·法拉兹a，学问是异常珍贵的东西，从任何源泉吸收都不可耻。b","白哲特a，坚强的信念能赢得强者的心，并使他们变得更坚强。 b","查尔斯·史考伯a，一个人几乎可以在任何他怀有无限热忱的事情上成功。 b","贝多芬a，卓越的人一大优点是：在不利与艰难的遭遇里百折不饶。b","莎士比亚a，本来无望的事，大胆尝试，往往能成功。b","卡耐基a，我们若已接受最坏的，就再没有什么损失。b","德国a，只有在人群中间，才能认识自己。b","史美尔斯a，书籍把我们引入最美好的社会，使我们认识各个时代的伟大智者。b","冯学峰a，当一个人用工作去迎接光明，光明很快就会来照耀着他。b","吉格·金克拉a，如果你能做梦，你就能实现它。b"],"bosh":["对于我们来说进行x体育锻炼非常重要，","多做x有助与我们提高身体素质，","做x将帮助我们更有效率的进行学习，","做x能够有效的改变人的情绪状态，","做x，能够有效的改变人的情绪状态。","多做x能够确定好自己的自我概念，以及对自己身体的客观评价。","进行x有利于人们培养坚强的品质。","做x能够有效的消除眼部疲劳。","x可以舒展身心,有助安眠及消除读书带来的压力","x可以陶冶情操，保持健康的心态，充分发挥个体的积极性、创造性和主动性，从而提高自信心和价值观，使个性在融洽的氛围中获得健康、和谐的发展。","做完这些运动，我出了一身汗。","好累啊。","今天跟着老师发的教程做了很多组x。","跟着教程做了x。","只有积极锻炼才能保持良好状态。","昨天做了x之后，我很快就睡着了，运动果然可以改善睡眠~","x利于减肥。运动时，会燃烧热量。","我完成了今天的任务。","我今天太累了，没有进行很久的体育锻炼。","做x可以改善","今天不是很累，","没有出很多汗，","加油呀~","每天都要加油！","做x虽然很累，但是很开心~","x可以调节人体紧张情绪。","我们要克服身体的惰性，","做了几组x感觉人生升华了~哈哈。","每天都要坚持做x，","今天和同学一起交流了做x的经验。"],"after":["看了这句话，让我坚定了坚持做x的决心。","这句话让我更加重视体育锻炼，","让我有了坚持的勇气。","我也想和他们一样优秀。","这句话勉励我继续做完今天的体育锻炼。","这句话让我有了锻炼的决心。","这句话让我放下手中的手机去做x 。","我们要向他们学习。","这句话让我放下游戏去做x 。","启示我们应该科学合理积极地进行体育锻炼，塑造出一个更强壮、更健康、更美好的自己！"],"before":["曾经说过","在不经意间这样说过","说过一句著名的话","曾经提到过","说过一句富有哲理的话","经常讲","曾教育我们","经常教育年轻人"]}[/collapse]''' @Description: 生成体育日记 @Author: moluuser @Date: 2020-05-22 21:23:35 @LastEditTime: 2020-05-23 16:48:54 ''' # -*- coding: UTF-8 -*- # 感谢 https://github.com/menzi11/BullshitGenerator import re import shutil import os import random import json import datetime from docx import Document from docx.shared import Inches from docx.shared import Pt from docx.oxml.ns import qn from docx.enum.text import WD_ALIGN_PARAGRAPH # 男生任务 male_d1 = ["左右开合跳", "俯卧撑", "仰卧举腿", "深蹲"] male_d3 = ["扶墙高抬腿跑", "身体反弓前后摆腿", "平板支撑", "空中脚踏车", "原地前后动态弓步"] male_d5 = ["左右开合跳", "原地快速高抬腿跑", "底姿俯卧撑", "仰卧臀桥", "波比跳"] # 女生任务 girl_d1 = ["左右开合跳", "跪姿俯卧撑", "仰卧举腿", "深蹲"] girl_d3 = ["扶墙高抬腿跑", "身体反弓前后摆腿", "平板支撑", "空中脚踏车", "原地前后动态弓步"] girl_d5 = ["左右开合跳", "原地快速高抬腿跑", "高姿俯卧撑", "仰卧臀桥", "波比跳"] ''' @description: 初始化程序 @param {type} @return: ''' class programLoad(): def load(): beginDate = input("请输入起始日期例如2020-01-01：") endDate = input("请输入结束日期例如2020-01-01：") sex = int(input("请输入性别(男生输入1，女生输入0)：")) uname = input("输入姓名：") uno = input("输入学号：") uteacher = input("输入任课教师：") # 简单检测用户输入 # 确保end大于begin，程序不做检测 while sex not in (0, 1) or re.match("\d{4}-\d{2}-\d{2}", beginDate) == None or re.match("\d{4}-\d{2}-\d{2}", endDate) == None: print("输入信息错误，请核对！") beginDate = input("请输入起始日期例如2020-01-01: ") endDate = input("请输入结束日期例如2020-01-01: ") sex = int(input("请输入性别(男生输入1，女生输入0): ")) def readJSON(fileName=""): if fileName != '': strList = fileName.split(".") if strList[len(strList)-1].lower() == "json": with open(fileName, mode='r', encoding="utf-8") as file: return json.loads(file.read()) # 导入语料 data = programLoad.readJSON("data.json") sayings = data["famous"] beforSay = data["before"] afterSay = data['after'] bosh = data['bosh'] ''' @description: 生产doc内容 @param {type} @return: ''' class diaryFactory(): def getFinish(num): tmp = str() if num == 1: for i in male_d1: tmp += diaryFactory.buildExec(i) + " " elif num == 3: for i in male_d3: tmp += diaryFactory.buildExec(i) + " " elif num == 5: for i in male_d5: tmp += diaryFactory.buildExec(i) + " " return "我完成了："+tmp # 返回固定文章头 def buildTitle(uname, uno, uteacher, cdate): return "姓名：" + uname + " " + "学号：" + uno + "\r" + "任课教师：" + uteacher + " " + "上课时间：" + cdate # 返回练习任务 # 男1女0 # flag非0则返回feeling def buildBody(sex, week, flag=0): # 对List进行混洗 if flag == 0: if sex == 1: if week == 1: random.shuffle(male_d1) return male_d1 elif week == 3: random.shuffle(male_d3) return male_d3 elif week == 5: random.shuffle(male_d5) return male_d5 elif sex == 0: # 女生 if week == 1: random.shuffle(girl_d1) return girl_d1 elif week == 3: random.shuffle(girl_d3) return girl_d3 elif week == 5: random.shuffle(girl_d5) return girl_d5 else: print("buildBody ERROR!") return else: # 获取feeling if sex == 1: if week == 1: return feelFactory.build().replace("x", str(random.sample(male_d1, 1)), 2).replace("x", str(random.sample(male_d1, 1)), 2).replace("x", str(random.sample(male_d1, 1)), 2).replace("x", str(random.sample(male_d1, 1)), 2).replace("x", str(random.sample(male_d1, 1))).replace("['", "").replace("']", "") if week == 3: return feelFactory.build().replace("x", str(random.sample(male_d3, 1)), 2).replace("x", str(random.sample(male_d3, 1)), 2).replace("x", str(random.sample(male_d3, 1)), 2).replace("x", str(random.sample(male_d3, 1)), 2).replace("x", str(random.sample(male_d3, 1))).replace("['", "").replace("']", "") if week == 5: return feelFactory.build().replace("x", str(random.sample(male_d5, 1)), 2).replace("x", str(random.sample(male_d5, 1)), 2).replace("x", str(random.sample(male_d5, 1)), 2).replace("x", str(random.sample(male_d5, 1)), 2).replace("x", str(random.sample(male_d5, 1))).replace("['", "").replace("']", "") elif sex == 0: # 女生 if week == 1: return feelFactory.build().replace("x", str(random.sample(girl_d1, 1)), 2).replace("x", str(random.sample(girl_d1, 1)), 2).replace("x", str(random.sample(girl_d1, 1)), 2).replace("x", str(random.sample(girl_d1, 1)), 2).replace("x", str(random.sample(girl_d1, 1))).replace("['", "").replace("']", "") if week == 3: return feelFactory.build().replace("x", str(random.sample(girl_d3, 1)), 2).replace("x", str(random.sample(girl_d3, 1)), 2).replace("x", str(random.sample(girl_d3, 1)), 2).replace("x", str(random.sample(girl_d3, 1)), 2).replace("x", str(random.sample(girl_d3, 1))).replace("['", "").replace("']", "") if week == 5: return feelFactory.build().replace("x", str(random.sample(girl_d5, 1)), 2).replace("x", str(random.sample(girl_d5, 1)), 2).replace("x", str(random.sample(girl_d5, 1)), 2).replace("x", str(random.sample(girl_d5, 1)), 2).replace("x", str(random.sample(girl_d5, 1))).replace("['", "").replace("']", "") else: print("buildBody ERROR!") return # 我完成了n次 # 降低复杂度，不对运动项目进行处理 # 平板支撑单位为秒 def buildExec(obj): unit = ["个", "次"] if random.randint(1, 2) > 1: return obj + str(random.randint(25, 40)) + ("秒" if obj == "平板支撑" else (str(random.sample(unit, 1))[2:3])) else: return obj + str(random.randint(25, 30)) + ("秒" if obj == "平板支撑" else (str(random.sample(unit, 1))[2:3])) + str(random.randint(1, 3)) + "组" ''' @description: 生产feeling，使用diaryFactory调用 @param {type} @return: ''' class feelFactory(): def build(): feeling = str() while len(feeling) < 200: ra = random.randint(0, 100) if ra < 20: feeling += feelFactory.getSaying() else: feeling += next(feelFactory.shuffle(bosh)) return feeling def shuffle(lis): lisPool = list(lis) * 2 while True: random.shuffle(lisPool) for i in lisPool: yield i def getSaying(): tmp = next(feelFactory.shuffle(sayings)) tmp = tmp.replace("a", random.choice(beforSay)) tmp = tmp.replace("b", random.choice(afterSay)) return tmp ''' @description: 生产doc @param {type} @return: ''' class docFactory(): def createDoc(cdate, sex, uname, uno, uteacher): dno = datetime.datetime.strptime( cdate, "%Y-%m-%d").weekday() + 1 weekno = str() if dno == 1: weekno = "星期一" elif dno == 3: weekno = "星期三" elif dno == 5: weekno = "星期五" document = Document() document.styles['Normal'].font.name = u'微软雅黑' document.styles['Normal']._element.rPr.rFonts.set( qn('w:eastAsia'), u'微软雅黑') p = document.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER # 居中 run = p.add_run("体育练习日记") run.font.size = Pt(22) pp = document.add_paragraph() run = pp.add_run(diaryFactory.buildTitle( uname, uno, uteacher, cdate) + " " + weekno+"\r") pp.alignment = WD_ALIGN_PARAGRAPH.CENTER # 居中 ppp = document.add_paragraph() run = ppp.add_run("练习内容：" + str(diaryFactory.buildBody(sex, dno) ).replace("[", "").replace("]", "").replace("'", "")) pppp = document.add_paragraph() run = pppp.add_run(diaryFactory.getFinish(dno)) ppppp = document.add_paragraph() run = ppppp.add_run("我的感受：" + diaryFactory.buildBody(sex, dno, 1)) document.save(cdate + "练习日记.doc") shutil.move(cdate + "练习日记.doc", "./diary") def exportAll(beginDate, endDate, lis): begin = datetime.datetime.strptime(beginDate, "%Y-%m-%d") end = datetime.datetime.strptime(endDate, "%Y-%m-%d") for i in range((end - begin).days+1): day = (str(begin + datetime.timedelta(days=i)))[0:10] if (datetime.datetime.strptime(day, "%Y-%m-%d").weekday() + 1) in [1, 3, 5]: docFactory.createDoc(day, lis[0], lis[1], lis[2], lis[3]) # print(day + " " + str(datetime.datetime.strptime(day, "%Y-%m-%d").weekday() + 1)) if __name__ == "__main__": # programload.Load() folder = os.path.exists("./diary") if not folder: os.makedirs("./diary") lis = (1, "姓名", "学号", "任课老师") docFactory.exportAll("2020-03-01", "2020-06-01", lis)参考链接：https://github.com/menzi11/BullshitGeneratorhttps://python-docx.readthedocs.io/en/latest/index.html
Begin使用Python处理DNA序列，本质上就是 IO操作和 字符串处理。代码使用菜单和用户进行交互获取DNA序列在https://www.ncbi.nlm.nih.gov/可以下载处理操作生成DNA互补序列本质上是CG, AT的互换生成DNA反向序列reverse字符串即可生成DNA反向互补序列在互补的基础下reverse检测GC含量GC字符占字符串长度的比例DNA转录为RNAT换为U即可运行[collapse title="可测试使用的DNA序列" status="false"]GAGTAGTCCCTTCGCAAGCCCTCATTTCACCAGGCCCCCGGCTTGGGGCGCCTTCCTTCCCCATGGCGGG ACACCTGGCTTCGGATTTCGCCTTCTCGCCCCCTCCAGGTGGTGGAGGTGATGGGCCAGGGGGGCCGGAG CCGGGCTGGGTTGATCCTCGGACCTGGCTAAGCTTCCAAGGCCCTCCTGGAGGGCCAGGAATCGGGCCGG GGGTTGGGCCAGGCTCTGAGGTGTGGGGGATTCCCCCATGCCCCCCGCCGTATGAGTTCTGTGGGGGGAT GGCGTACTGTGGGCCCCAGGTTGGAGTGGGGCTAGTGCCCCAAGGCGGCTTGGAGACCTCTCAGCCTGAG GGCGAAGCAGGAGTCGGGGTGGAGAGCAACTCCGATGGGGCCTCCCCGGAGCCCTGCACCGTCACCCCTG GTGCCGTGAAGCTGGAGAAGGAGAAGCTGGAGCAAAACCCGGAGGAGGCAAGTGAGCTTCGACGGGGTTG GGGTGTGGGGAGGTGGTCATGACAGGGCAGCCTGATGGGGAAGTGGTCACCTGCAGCTGCCCAGACCTGG CACCCAGGAGAGGAGCAGGCAGGGTCAGCTGCCCTGGCCAGGGAGGGGTGTGTATCAACTGCTGGCAGCC CTGGCAGGCAGGGGCCAGGTGGGAAGTGGAAGCTGGATTTCGAAGAGACAACTGCCGGTGAGGGCAGAGC AGCCTGGGAGAGTCGGAAGCTGGCCCAGGCTGGCCTTTGCTCTGGCCCAGCCCTTGTCAGGGTCTCTCAC ATCTCCTAGGCCTGCCCAGGGTCTGGTCACTCATTACTGGCCCAGCACCAGACCCAGCTTGGGGTTGGTT TGAGCCCCTTTTCCCACCCTTAGTCCTGCTTGAAAATTTGACCCTTATCAGACCCAAGATTTTGGCCTTA GGGTTAAGCATAGCCTGAGGGTAAAAACAGTGCTCATTCCAGGATTATTGTTCCTGAAAGTCTAGGGTGT GACTCGTTTCTGATAGGATCTCCTGTTTGGGCTGTGTGTGTGCGCGTTGTGAGCTGGGTTTACCTCCAGT CAAGTATAGGGCTTGTCTTCCCCGGATCTCTGCCTCAGGCCAATGACTGGCCACTGTGTTAAGGTGCACA CCCTGGCACCCCTTGTAGAAAGCTGGATTTTGATTGACTTCAGCCTCAGTTCCAAAGTTGTAAACAAGAA AAATGGTGAGAGATTTCTCCAGGCCATTTGCAAATATAGAGCTGCTGCGGGATTGAAGGCATCCAGCCCT GCTGAGGACTATTAAAGATGTATCTTCCAGTCCTTCAAGGCGACAAGTGTAAGCAATTAGAGATTAAATA CTAAGCCTTGAGACCTCACAGAAAGGTGTGACTGGTTTCTGGAGTGACCGAGAAGCCCCAACCTCTTCGC AGGAGGTCACTGCTGAGCCTTGAATGATAATGGCTGGCAATTGTGGTCCACTTCCTAAGTGCCTGGCTGT GTGCTCCGTTTATACATCATTATCTCATTAACCAGCACAAAATCTCCTAGGGGGAGGTATTATTATCCTA TTTAACGGGTTTTAACTGCTAAATGATGAAGCGAGGATTTGGACCAGTGTTTATTCCAAAACCCCAAAAC AGAATTTGGAAAATCCAAGATAGCAGAGGGCATTTATCAGTTTGAGTTATTGGCTGAGCAGAAGTTGGGG ATGAAAACAGCCTATTTGAAATTGATATGATCAAGCACCATTGAAACACTTCCTTGAGGCTTCAGAACTA CAAAAAGGCCTTGTTTTTTTCTCACTAGCTGTGCACCTCTGTCTGCCGGCAGCCTCATATGGCATGCCCC AGGGCTCAGTCCTTCAACCTCTGCTCTATCTACCCTTCCTTCCTCTCACCCACCCTCAAGGCTTAAATGC CATTTAGACACCAGATGACTACCGCGTTTTCTGTCTCTTGTGATGGCTCCCTGAACTGCTCCACCCTGAT CACCCAGTTGCTCAAGGCCAAACCCAGTCATCCTCAGTTTCTTTCATGTCCTACATCCTATCCTTAAGAA ACATCCTGAATCAATCACAACCTAACCCTGGCCTCAGCCACCATCATCTCTGCTGGGATTACCGCAGTAG CTTCTCAAATTATACTGCTTCCTCCCTACTGTCTGTGGCCAACACGTCAACTAGAGTCAGTGTTTTAAAA GGTGTGGCCAGGCACTTTGGGAGGCCGAGGCAGGCGAATCACCTGAGGTCGGGAGTTCGAGTCCAGCCTG ACCAACATGGCGAAACCCCATCTCTACTAAAAATACAAAATTAGCTGGGCGTGGTGACGCATGCCTGTAA TCTCAGCTACTCAGGAAGCTGAGGCAGGAGAATCGCTTGAACCTGGGAGATGGAGGTTGCGGTGAGCCGA GATCGCGCCAGTGCACTCCAGCCTAGGCAACAAAAGCGAAACTCTCAAAAAAAAAAAAAAAAAAGGTGAG GCTAGGTGCGGTGGTTCACACCTGTAATCCCAGCACTTTGGGAGGCCAAGGTGGACAGATCACTTGAGGT CTCCTGACCAGCCTGGCCAACATGGTGAAACCCCATATCTACTAAAAATACAAAAATTAGCCGGGCATGG TGGTGGGTGCCTGTAGTCCCAGCTACTCAGGCGGCTGAGGCAGAATAGCTTGAACCCAGAAGGCGGAGAT TGCAGTGAGCCAAGATCACGCCACAGCACTCCAGCCTGGGCGATAGAACGAGATTCCGTCTTGGTGGGGA GAAAAAGGGTGAGAGATCATTTCGCTTGGACTAAAACAAAGTCACTATGTCTGCAACAGGATCTACCTAG CCACCAGACCAGCTTTGGGCTCTGGAAGGCCCACTTCAGGGCCTTGCCACATTAGACTCTTGTCCTTTGC TCAAACAATCACCTTCTCTGTCTTTAAAAGTGTCACCCTCCTCCATAATCTCCTTCCCTCCTTTACCCTA CTCCTATAGACTGCTTTATTTTTTTTTTAATTTTTGAGATGGAGTCTCACTCTGTCCCTCAGGCTGGAGT GCAGTGGTGCGATCTTGGCTCACTGCAAACTCCACCTCCTAGGTTCAAGCAATTCTCCTGCCTCAGCCTC CTGAGTAGCTGGGATTATAGGGGAGCGCCATGATGCCCAGCTAATTTTTGTATTTTTAGTAGAGACAGAG TCTCACTATGTTGACCAGGCTAGTCTTGAACTCCTGACCTCAAGTGATCTACCCACCTTGGCCTCCCAAA GTGAAGGGATTACAGGCATGACCACTGCGCCCAGACTGCTTTACTTTTTTCCATAATATATATATATATT TTAAATAGAGGCAGCAGGGGTGGGAGAAGGGGCGGCACGGGTCTCACTATGTTACCCAGGCTGCTTTCTA ACTCTTGGGCTCAAGCAGTCTGCCCACCTTGGCCTCCCAAAGTGCTAGGATTTACAGACATGAGCCACTG TGCCTGGCCATTTTTTATTTTATTTACTTTTTTATTTTTCAGAGCAGGAGTGGAAGTTTATTATTAAAAA GTTATAGGGCAGGGAAAAAAGGAAAGTGCACTTGGAAGAGATCCAAGTGGGCAACTTGAAGAACAAGTGC CAAATAGCACTTCTGTCATGCTGGATGTCAGGGCTCTTTGTCCACTTTGTATAGCCGCTGGCTTATAGAA GGTGCTCGATAAATCTCTTGAATTTAAAAATCAATTAGGATGCCTCTATAGTGAAAAAGATACAGTAAAG ATGAGGGATAATCAATTTAAAAAATGAGTAAGTACACACAAAGCACTTTATCCATTCTTATGACACCTGT TACTTTTTTGCTGTGTTTGTGTGTATGCATGCCATGTTATAGTTTGTGGGACCCTCAAAGCAAGCTGGGG AGAGTATATACTGAATTTAGCTTCTGAGACATGATGCTCTTCCTTTTTAATTAACCCAGAACTTAGCAGC TTATCTATTTCTCTAATCTCAAAACATCCTTAAACTGGGGGTGATACTTGAGTGAGAGAATTTTGCAGGT ATTAAATGAACTATCTTCTTTTTTTTTTTTCTTTGAGACAGAGTCTTGCTCTGTCACCCAGGCTGGAGTG CAGTGGCGTGATCTCAGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGTGATTCTCCTGCCTCAGCCTCC TGAGTAGCTGGGATTACAGGTGCGTGCCACCGTGCCCAGCTAATTTTTGTGTTTTTAGTAGAGACGGGGT TTCACCATGTTGGCCATGCTGGTCTTGAACTCCTGACCTCGTGATCTGCCCACCTCGGCCTCCCAAAGTG CTGGAATTATAGGCGTGAGCCACCGCGCCCAGCAAAGAACTTCTAACCTTCATAACCTGACAGGTGTTCT CGAGGCCAGGGTCTCTCTTTCTGTCCTTTCACGATGCTCTGCATCCCTTGGATGTGCCAGTTTCTGGGGG AAGAGTAGTCCTTTGTTACATGCATGAGTCAGTGAACAGGGAATGGGTGAATGACATTTGTGGGTAGGTT ATTTCTAGAAGTTAGGTGGGCAGCTTGGAAGGCAGAGGCACTTCTACAGACTATTCCTTGGGGCCACACG TAGGTTCTTGAATCCCGAATGGAAAGGGGAGATTGATAACTGGTGTGTTTATGTTCTTACAAGTCTTCTG CCTTTTAAAATCCAGTCCCAGGACATCAAAGCTCTGCAGAAAGAACTCGAGCAATTTGCCAAGCTCCTGA AGCAGAAGAGGATCACCCTGGGATATACACAGGCCGATGTGGGGCTCACCCTGGGGGTTCTATTTGGTGG GTTCCCCTCTGCAGATTCTGACCGCATCTCCCCTCTAAGGAGTATCCCTGAACCTAGTGGGGAGGGGCAG GGGCAGACTACCCTCACCCATGAAGAGGAGTAGGGAGAGGGAGAAGATGCTTTGAGCTCCCTCTGGGAAG AGGTGGTAAGCTTGGATCTCAGGGTCACAAGGGCCCTGCGTGCTCCCTCACTTTGCTTCTCTTTTGACTG GCCTCCCCCAGGGAAGGTATTCAGCCAAACGACCATCTGCCGCTTTGAGGCTCTGCAGCTTAGCTTCAAG AACATGTGTAAGCTGCGGCCCTTGCTGCAGAAGTGGGTGGAGGAAGCTGACAACAATGAAAATCTTCAGG AGGTAAGGGTGGGAGGGGGATACCCGGGGACCTTCCCTTTCTTGGCCTAATTTCCATTGCTTCCATCACT GGCTCGTAGCTCTCCGTCTTTGGTGCAGTGGTTCTCAGTGGGATGGAGTGAAATTCCTCAGTTCTGCTGG GATAAGGTCCAGAGCCAACCCTTCCAGGATCCTGCCTTTTCACACCACCACCTGGCTCTGCTGACACATC TAGTCACAGACCCCTGTGATGCTGTTACTCAGCAAGTCCAAAGCTTGCCCTTGTCACCCCCTTCCCACCT GCACAGATATGCAAAGCAGAAACCCTCGTGCAGGCCCGAAAGAGAAAGCGAACCAGTATCGAGAACCGAG TGAGAGGCAACCTGGAGAATTTGTTCCTGCAGTGCCCGAAACCCACACTGCAGCAGATCAGCCACATCGC CCAGCAGCTTGGGCTCGAGAAGGATGTGAGTGCCATGTCTCTCTGCGGGCTCCATCTCTTTCCCCTGTCA CCACCTCGCTTTCCCTAGCTCTGGCTCCTCCAACTGCTCTAGGGCTGTTGGCTTTGGACAGAATGTCCAA GCAGTCAGGCCTGTCTCAGCTCATTCTCTAATGTCCTCCTCTAACTGCTCTAGGGCTGTTGGCTTTGGAT AGAATGTCCAAGCAGAGTCAGGCCCGTCTCAGCTCATTGTCTAATGTCATTCTCCTTTCTGTCATTCACT TGCAGGTGGTCCGAGTGTGGTTCTGTAACCGGCGCCAGAAGGGCAAGCGATCAAGCAGCGACTATGCACA ACGAGAGGATTTTGAGGCTGCTGGGTCTCCTTTCTCAGGGGGACCAGTGTCCTTTCCTCTGGCCCCAGGG CCCCATTTTGGTACCCCAGGCTATGGGAGCCCTCACTTCACTGCACTGTACTCCTCGGTCCCTTTCCCTG AGGGGGAAGCCTTTCCCCCTGTCTCCGTCACCACTCTGGGCTCTCCCATGCATTCAAACTGAGGTGCCTG CCCTTCTAGGAATGGGGGACAGGGGGAGGGGAGGAGCTAGGGAAAGAAAACCTGGAGTTTGTGCCAGGGT TTTTGGGATTAAGTTCTTCATTCACTAAGGAAGGAATTGGGAACACAAAGGGTGGGGGCAGGGGAGTTTG GGGCAACTGGTTGGAGGGAAGGTGAAGTTCAATGATGCTCTTGATTTTAATCCCACATCATGTATCACTT TTTTCTTAAATAAAGAAGCCTGGGACACAGTAGATAGACACACTTA[/collapse]代码import sys import os DNA = "" class toDO(): # 判断是否导入DNA def isExistDNA(self): if DNA == "null" or DNA == "": print("========================================") print("请先导入DNA再执行操作！") print("========================================") return False else: return True # 7. 将DNA全部转为大写 def toUpper(self): global DNA if not (toDO.isExistDNA(self)): return DNA = DNA.upper() # 写入文件 exportFile = "upperDNA.txt" fp = open(exportFile, "w") fp.write(DNA) print("========================================") print("转换为大写的序列保存在" + exportFile + "请查看~") print("========================================") # 6. 清除程序产生的所有文件 def cleanFiles(self): try: if os.path.exists("compDNA.txt"): os.remove("compDNA.txt") if os.path.exists("recDNA.txt"): os.remove("recDNA.txt") if os.path.exists("rev_compDNA.txt"): os.remove("rev_compDNA.txt") if os.path.exists("toRNA.txt"): os.remove("toRNA.txt") if os.path.exists("upperDNA.txt"): os.remove("upperDNA.txt") except Exception as e: print(e) print("========================================") print("已删除程序生成的所有文件！") print("========================================") # 0. 导入需要处理的DNA序列(请先选择此选项) def selectDNA(self): global DNA DNA = "null" # fileName = "dna.txt" fileName = input("请输入要读取的文件名(确保在当前目录下)：") if os.path.exists(fileName): f = open(fileName) DNA = f.read() print("========================================") print("导入成功！请进行后续操作~") print("========================================") else: print("请输入正确的文件名！") toDO.selectDNA(self) # 1. 生成DNA互补序列 def compDNA(self): if not (toDO.isExistDNA(self)): return compDNA = "" tmpList = {'C': 'G', 'G': 'C', 'T': 'A', 'A': 'T', 'c': 'g', 'g': 'c', 't': 'a', 'a': 't'} for c in DNA: # 处理字符串中的换行符 if (c != "\n"): compDNA += tmpList[c] else: compDNA += c # 写入文件 exportFile = "compDNA.txt" fp = open(exportFile, "w") fp.write(compDNA) print("========================================") print("生成的序列已保存至" + exportFile + "请查看~") print("========================================") # 2. 生成DNA反向序列 def revDNA(self): if not (toDO.isExistDNA(self)): return tmp = list(DNA) tmp.reverse() # list转为str recDNA = "".join(tmp) # print(recDNA) # 写入文件 exportFile = "recDNA.txt" fp = open(exportFile, "w") fp.write(recDNA) print("========================================") print("生成的序列已保存至" + exportFile + "请查看~") print("========================================") # 3. 生成DNA反向互补序列 def rev_compDNA(self): if not (toDO.isExistDNA(self)): return # 处理反向 tmp = list(DNA) tmp.reverse() # list转为str recDNA = "".join(tmp) # 处理互补 rev_compDNA = "" tmpList = {'C': 'G', 'G': 'C', 'T': 'A', 'A': 'T', 'c': 'g', 'g': 'c', 't': 'a', 'a': 't'} for c in recDNA: # 处理字符串中的换行符 if (c != "\n"): rev_compDNA += tmpList[c] else: rev_compDNA += c # 写入文件 exportFile = "rev_compDNA.txt" fp = open(exportFile, "w") fp.write(rev_compDNA) print("========================================") print("生成的序列已保存至" + exportFile + "请查看~") print("========================================") # 4. 检测GC含量 def calGC(self): if not (toDO.isExistDNA(self)): return gc = DNA.count('G') + DNA.count('C') + DNA.count('g') + DNA.count('c') result = gc / len(DNA) print("========================================") print("当前DNA的GC含量为：" + str(result)) print("========================================") # 5. DNA翻译为RNA def toRNA(self): if not (toDO.isExistDNA(self)): return rna = DNA.replace("T", "U").replace("t", "u") # 写入文件 exportFile = "toRNA.txt" fp = open(exportFile, "w") fp.write(rna) print("========================================") print("生成的序列已保存至" + exportFile + "请查看~") print("========================================") # print(rna) # 6. 退出程序 def quit(self): print("\n欢迎再次使用~\n") sys.exit(0) class ProgramMenu(): # 显示菜单界面 def displayMenu(self): # 输出带颜色的文字 # 如果不兼容的话，就输出下面不带颜色的 # print(""" # \033[1;32;40m========================================\033[0m # 请选择您要进行的DNA序列处理操作: # \033[1;32;40m0. 导入需要处理的DNA序列(请先选择此选项)\033[0m # \033[1;36;40m1. 生成DNA互补序列 # 2. 生成DNA反向序列 # 3. 生成DNA反向互补序列 # 4. 检测GC含量 # 5. DNA转录为RNA\033[0m # \033[1;33;40m6. 删除程序产生的文件 # 7. 将DNA全部转为大写并保存\033[0m # \033[1;31;40m8. 退出程序\033[0m # \033[1;32;40m========================================\033[0m # """ ) print(""" ======================================== 请选择您要进行的DNA序列处理操作: 0. 导入需要处理的DNA序列(请先选择此选项) 1. 生成DNA互补序列 2. 生成DNA反向序列 3. 生成DNA反向互补序列 4. 检测GC含量 5. DNA转录为RNA 6. 删除程序产生的文件 7. 将DNA全部转为大写并保存 8. 退出程序 ======================================== """) # 程序主进程 def begin(self): while True: self.displayMenu() try: num = int(input("输入选项：")) except Exception as e: print("请输入正确的选项！") continue if num == 8: toDO.quit(self) elif num == 0: toDO.selectDNA(self) elif num == 1: toDO.compDNA(self) elif num == 2: toDO.revDNA(self) elif num == 3: toDO.rev_compDNA(self) elif num == 4: toDO.calGC(self) elif num == 5: toDO.toRNA(self) elif num == 6: toDO.cleanFiles(self) elif num == 7: toDO.toUpper(self) if __name__ == "__main__": ProgramMenu().begin()参考链接：https://blog.csdn.net/u012904337/article/details/79504319https://blog.csdn.net/u011262253/article/details/88542804
花一上午帮同学写的期末作业大概写下流程记录下BeginGUI设计使用Qt Designer完成 .ui文件生成py文件 pyuic5 -o xx.py xx.ui代码管理端from PyQt5 import QtCore, QtGui, QtSql, QtWidgets import sys import sqlite3 import os from PyQt5.QtSql import QSqlDatabase, QSqlTableModel from PyQt5.QtWidgets import QApplication, QWidget # 管理界面GUI class manageUI(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(1000, 400) Form.setFixedSize(Form.width(), Form.height()) self.tableView = QtWidgets.QTableView(Form) self.tableView.setGeometry(QtCore.QRect(10, 10, 981, 291)) self.tableView.setObjectName("tableView") self.gridLayoutWidget = QtWidgets.QWidget(Form) self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 310, 481, 80)) self.gridLayoutWidget.setObjectName("gridLayoutWidget") self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") self.pushButton = QtWidgets.QPushButton(self.gridLayoutWidget) self.pushButton.setObjectName("pushButton") self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1) self.pushButton_2 = QtWidgets.QPushButton(self.gridLayoutWidget) self.pushButton_2.setObjectName("pushButton_2") self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1) self.gridLayoutWidget_2 = QtWidgets.QWidget(Form) self.gridLayoutWidget_2.setGeometry(QtCore.QRect(510, 310, 481, 80)) self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2") self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_2) self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setObjectName("gridLayout_2") self.pushButton_3 = QtWidgets.QPushButton(self.gridLayoutWidget_2) self.pushButton_3.setObjectName("pushButton_3") self.gridLayout_2.addWidget(self.pushButton_3, 0, 0, 1, 1) self.pushButton_4 = QtWidgets.QPushButton(self.gridLayoutWidget_2) self.pushButton_4.setObjectName("pushButton_4") self.gridLayout_2.addWidget(self.pushButton_4, 1, 0, 1, 1) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "隔离人员管理")) self.pushButton.setText(_translate("Form", "刷新数据")) self.pushButton_2.setText(_translate("Form", "删除人员")) self.pushButton_3.setText(_translate("Form", "新增人员")) self.pushButton_4.setText(_translate("Form", "退出")) # 绑定按钮事件 # 查询 self.pushButton.clicked.connect(self.queryAll) # 删除 self.pushButton_2.clicked.connect(self.delRow) # 新增 self.pushButton_3.clicked.connect(self.addRow) # 退出程序 self.pushButton_4.clicked.connect( QtCore.QCoreApplication.instance().quit) # 创建数据库 def createDB(self): if os.path.exists("managePerson.db") == False: try: db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName("managePerson.db") db.open() c = QtSql.QSqlQuery() c.exec(''' CREATE TABLE managePerson( id INT PRIMARY KEY NOT NULL, name TEXT, age INT, address TEXT, begindate DATE, day INT );''') # 插入测试数据 c.exec_( "INSERT INTO managePerson VALUES (20, '张三', 18, '火星', '2020-05-08', 999);") c.exec_( "INSERT INTO managePerson VALUES (40, '李四', 19, '天王星', '2020-05-09', 10);") c.exec_( "INSERT INTO managePerson VALUES (30, '王五', 22, '海王星', '2020-02-02', 999);") db.close() print("创建数据库成功！") except Exception as e: print(e) else: print("数据库已存在！") # 查询所有人员 def queryAll(self): db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName("managePerson.db") self.model = QSqlTableModel() self.tableView.setModel(self.model) self.model.setTable("managePerson") self.model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange) self.model.select() self.model.setHeaderData(0, QtCore.Qt.Horizontal, '身份证号') self.model.setHeaderData(1, QtCore.Qt.Horizontal, '姓名') self.model.setHeaderData(2, QtCore.Qt.Horizontal, '年龄') self.model.setHeaderData(3, QtCore.Qt.Horizontal, '地址') self.model.setHeaderData(4, QtCore.Qt.Horizontal, '开始隔离时间') self.model.setHeaderData(5, QtCore.Qt.Horizontal, '需要隔离天数') # 删除用户 def delRow(self): if self.model: try: self.model.removeRow(self.tableView.currentIndex().row()) except Exception as e: print(e) else: self.createDB() # 新增用户 def addRow(self): if self.model: try: self.model.insertRows(self.model.rowCount(), 1) except Exception as e: print(e) else: self.createDB() # 程序入口 if __name__ == "__main__": app = QApplication(sys.argv) form = QWidget() ui = manageUI() ui.setupUi(form) ui.createDB() form.show() ui.queryAll() sys.exit(app.exec())查询端from PyQt5 import QtCore, QtGui, QtSql, QtWidgets import sys import datetime from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtSql import QSqlDatabase, QSqlTableModel from PyQt5.QtWidgets import QMessageBox # 查询界面GUI class queryUI(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(800, 500) Form.setFixedSize(Form.width(), Form.height()) self.textEdit = QtWidgets.QTextEdit(Form) self.textEdit.setGeometry(QtCore.QRect(10, 80, 781, 341)) self.textEdit.setObjectName("textEdit") self.label = QtWidgets.QLabel(Form) self.label.setGeometry(QtCore.QRect(10, 10, 781, 61)) font = QtGui.QFont() font.setFamily(".Heiti GB18030PUA") font.setPointSize(22) self.label.setFont(font) self.label.setObjectName("label") self.pushButton = QtWidgets.QPushButton(Form) self.pushButton.setGeometry(QtCore.QRect(10, 430, 781, 61)) self.pushButton.setObjectName("pushButton") self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "隔离剩余天数查询")) self.textEdit.setHtml(_translate("Form", " \n" " \n" " ")) self.label.setText(_translate("Form", "身份证号：")) self.pushButton.setText(_translate("Form", "查询剩余隔离天数")) self.pushButton.clicked.connect(self.queryLaveDays) # 查询剩余天数 def queryLaveDays(self): # 获取文本框值 personNo = self.textEdit.toPlainText() # 连接数据库 db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName("managePerson.db") db.open() c = QtSql.QSqlQuery() c.exec("SELECT name, begindate, day FROM managePerson WHERE id=" + personNo + ";") name = "null" while c.next(): name = c.value(0) begindate = c.value(1) day = c.value(2) print(name, begindate, day) db.close() # 当前日期 today = datetime.date.today() today = datetime.datetime.strptime(str(today), "%Y-%m-%d") try: # 隔离开始时间 begindate = datetime.datetime.strptime(begindate, "%Y-%m-%d") # 隔离结束时间 endDate = begindate + datetime.timedelta(days=day) except Exception as e: print(e) if name == "null": msg = "请正确输入身份证号！" elif endDate > today: laveDay = endDate - today msg = name + "您好，您的隔离结束时间为" + str(endDate).replace(" 00:00:00", "") + "剩余" + str( laveDay).replace(" days, 0:00:00", "") + "天，请耐心等待！" else: msg = name + "您好，您已结束隔离期！" QMessageBox().information(None, "隔离剩余天数查询", msg, QMessageBox.Yes) # 程序入口 if __name__ == "__main__": app = QApplication(sys.argv) form = QWidget() ui = queryUI() ui.setupUi(form) form.show() sys.exit(app.exec())打包为exepip install pyinstaller使用PyInstallerpyinstaller的语法：pyinstaller [options] script [script...] | specfile最简单的用法，在和myscript.py同目录下执行命令：pyinstaller mycript.py然后会看到新增加了两个目录build和dist，dist下面的文件就是可以发布的可执行文件，对于上面的命令你会发现dist目录下面有一堆文件，各种都动态库文件和myscrip可执行文件。有时这样感觉比较麻烦，需要打包dist下面的所有东西才能发布，万一丢掉一个动态库就无法运行了，好在pyInstaller支持单文件模式，只需要执行：pyinstaller -F mycript.py你会发现dist下面只有一个可执行文件，这个单文件就可以发布了，可以运行在你正在使用的操作系统类似的系统的下面。当然，pyinstaller还有各种选项，有通用选项，如-d选项用于debug。在执行pyInstaller命令的时候，会在和脚本相同目录下，生成一个.spec文件，该文件会告诉pyinstaller如何处理你的所有脚本，同时包含了命令选项。一般我们不用去理会这个文件，若需要打包数据文件，或者给打包的二进制增加一些Python的运行时选项时...一些高级打包选项时，需要手动编辑.spec文件。可以使用：pyi-makespec optionsscript [script ...]创建一个.spec文件，对于手动编辑的.spec文件，我们可以使用下面任意一条命令：pyinstaller specfilepyi-build specfilePyInstaller原理简介PyInstaller其实就是把python解析器和你自己的脚本打包成一个可执行的文件，和编译成真正的机器码完全是两回事，所以千万不要指望成打包成一个可执行文件会提高运行效率，相反可能会降低运行效率，好处就是在运行者的机器上不用安装python和你的脚本依赖的库。在Linux操作系统下，它主要用的binutil工具包里面的ldd和objdump命令。PyInstaller输入你指定的的脚本，首先分析脚本所依赖的其他脚本，然后去查找，复制，把所有相关的脚本收集起来，包括Python解析器，然后把这些文件放在一个目录下，或者打包进一个可执行文件里面。可以直接发布输出的整个文件夹里面的文件，或者生成的可执行文件。你只需要告诉用户，你的应用App是自我包含的，不需要安装其他包，或某个版本的Python，就可以直接运行了。需要注意的是，PyInstaller打包的执行文件，只能在和打包机器系统同样的环境下。也就是说，不具备可移植性，若需要在不同系统上运行，就必须针对该平台进行打包。实践问题pyinstaller打包后的exe运行怎么去掉弹出的命令行提示窗口？ 1.如果使用.spec文件的话, 在该文件中找到console=True修改为console=False 2.如果是直接指定python文件进行pyinstaller打包的话，需要添加—noconsole pyinstaller path\\mycode.py--noconsole 如果想只打包成一个exe： pyinstaller -F path\\mycode.py --noconsole 或： pyinstaller -F -wpath\\mycode.py更换最终exe生成路径 在cmd中，一开始就要 cd D:\PythonEXE\ 切换到输出文件夹，然后在用上面的代码，说明：各个参数的作用， 例子：pyinstaller -F -w -pD:\tmp\core-python\libs -i d:\tmp\main.ico main.py -F 表示生成单个可执行文件； -D –onedir 创建一个目录，包含exe文件，但会依赖很多文件（默认选项）。 -w 表示去掉控制台窗口，这在GUI界面时非常有用。不过如果是命令行程序的话那就把这个选项删除吧！； -c –console, –nowindowed 使用控制台，无界面(默认)； -p 表示你自己自定义需要加载的类路径，一般情况下用不到； -i 表示可执行文件的图标。参考链接：https://blog.csdn.net/zengxiantao1994/article/details/76578421https://www.codercto.com/a/19041.html?tdsourcetag=s_pctim_aiomsg