分类目录归档:解决方案

Kafka入门及Kafka-Python初体验

本文介绍了以下内容:

1.什么是Kafka?

2.为什么我们需要使用Kafka这样的消息系统及使用它的好处

3.如何将Kafka使用到我们的后端设计中。

译自https://timber.io/blog/hello-world-in-kafka-using-python/,有部分删改。

1.Kafka是什么、为什么我们需要它?

简而言之,Kafka是一个分布式消息系统。这是什么意思呢?

想象一下,你现在有一个简单的Web应用,其包含了网页前端客户端(Client)、服务端和数据库:

你需要记录所有发生在你的Web应用的事件,比如点击、请求、搜索等,以便后续进行计算和运营分析。

假设每个事件都由单独的APP完成,那么一个简单的解决方案就是将数据存储在数据库中,所有APP连接到数据库进行存储:

这看起来简单,但是其中还会出现许多问题:

1.点击、请求、搜索等事件会产生大量的数据到数据库中,这可能会导致插入事件存在延迟。

2.如果选择将高频数据存储在SQL或MongoDB等数据库中,很难再原有历史数据的基础上扩展数据库。

3.如果你需要用这些数据进行数据分析,你可能无法直接对数据库进行高频率的读取操作。

4.每个APP可以遵循自己的数据格式,这就意味着当你需要在不同的APP进行数据交换时,你需要进行数据格式的转换。

通过使用像Kafka这样的消息流系统,可以很好地解决这些问题,因为他们可以执行以下操作:

1.存储的大量数据可以被持久化、校验和复制,具备容错能力。

2.支持跨系统实时处理连续的数据流。

3.允许APP独立发布数据或数据流,并与使用它的APP无关。

那么它和传统数据库有何不同?

尽管Kafka可以持久化地存储数据,但它不是数据库。

Kafka不仅允许APP存储或提取连续的数据流,还支持实时处理。这与对被动数据执行CRUD操作或对传统数据库执行查询的方式不同。

听起来不错,那么Kafka是如何解决以上挑战的?

Kafka是一个分布式平台,是为规模而构建的,这意味着它可以处理高频率的读写和存储大量数据。它确保数据始终可靠。它还支持从故障中恢复的强大机制。

以下是为什么应该使用Kafka的一些关键因素:

1.1 简化后端架构

在Kafka的帮助下,我们前面的结构会变得简单一些:

1.2 通用数据管道

如上所示,Kafka充当多个APP和服务的通用数据管道,这给了我们两个好处:

1.数据是集成的,我们将来自不同系统的数据都存在一个地方,这使得Kafka成为真正的数据源。任何APP都可以将数据推送到该平台,然后由另一个APP提取数据。

2.Kafka使得应用程序之间交换数据变得容易。因为我们可以标准化数据格式,减少了数据格式的转换。

1.3 通用连接性

尽管Kafka允许你使用标准数据格式,但并不意味着你的APP就不需要数据转换了,它只是减少了我们转换数据的频率罢了。

此外,Kafka提供了一个叫 Kafka Connect 的框架允许我们维护遗留的老系统。

1.4 实时数据处理

类似于监控系统这样的实时APP,往往需要连续的数据流,这些数据需要被立即处理或尽量减少延迟处理。

Kafka的流式处理,使得处理引擎可以在很短的时间内(几毫米到几分钟)内取数、分析、以及响应。

2.Kafka入门

2.1 安装

安装Kafka是一个相当简单的过程。只需遵循以下给定步骤:

1.下载最新的1.1.0版本的Kafka

2.使用以下命令解压缩下载文件: tar -xzf kafka_2.11-1.1.0.tgz

3.cd到Kafka目录开始使用它: cd kafka_2.11-1.1.0

2.2 启动服务器

ZooKeeper是一个针对Kafka等分布式环境的集中管理工具,它为大型分布式系统提供配置服务、同步服务及命名注册表。

因此,我们需要先启动ZooKeeper服务器,然后再启动Kafka服务器。使用以下命令即可:

# Start ZooKeeper Server
bin/zookeeper-server-start.sh config/zookeeper.properties

# Start Kafka Server
bin/kafka-server-start.sh config/server.properties

2.3 Kafka 基本概念

我们快速介绍一下Kafka体系结构的核心概念:

1.Kafka在一个或多个服务器上作为集群运行。

2.Kafka将数据流存储在名为topics的类别中。每条数据均由键、值、时间戳组成。

3.Kafka使用发布-订阅模式。它允许某些APP充当producers(生产者),记录数据并将数据发布到Kafka topic中。

同样,它允许某些APP充当consumer(消费者)和订阅Kafka topic并处理由它产生的数据。

4.除了Prodcuer API 和 Consumer API,Kafka还为应用提供了一个 Streams API 作为流处理器。通过 Connector API 我们可以将Kafka连接到其他现有的应用程序和数据系统。

2.4 架构

如你所见,每个Kafka的 Topic 可以分为多个Partition(分区),可以使用broker(经纪人)在不同的计算机上复制这些 Topic,从而使消费者可以并行读取 Topic.

kafka的复制是针对分区的:

比如上图中有4个broker, 1个topic, 2个分区,复制因子是3。当producer发送一个消息的时候,它会选择一个分区,比如topic1-part1分区,将消息发送给这个分区的leader, broker2、broker3会拉取这个消息,一旦消息被拉取过来,slave会发送ack给master,这时候master才commit这个log。

因此,整个系统的容错级别极高。当系统正常运行时,对Topic的所有读取和写入都将通过leader,且leader会保证所有其他broker均被更新。

如果Broker失效了,系统会自动重新配置,此时副本也可以接管成为Leader.

2.5 创建Kafka Topic

让我们创建一个名为 sample,含有一个partition(分区)和一个replica(副本)的Kafka Topic:

bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic sample

列出所有的Kafka Topics,检查是否成功创建了sample Topic:

bin/kafka-topics.sh --list --zookeeper localhost:2181

describe topics 命令还可以获得特定Topic的详细信息:

bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic sample

2.6 创建生产者与消费者

这里是代码实战部分,利用Kafka-Python实现简单的生产者和消费者。

1.首先需要安装kafka-python:

pip install kafka-python

2.创建消费者(consumer.py)

from kafka import KafkaConsumer
consumer = KafkaConsumer('sample')
for message in consumer:
    print (message)

3.创建生产者(producer.py)

现在,有一个消费者正在订阅我们的消息流,因此我们要创建一个生产者,发布消息到Kafka:

from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('sample', b'Hello, World!')
producer.send('sample', key=b'message-two', value=b'This is Kafka-Python')

现在,你重新运行消费者(consumer.py),你就会接收到生产者发送过来的消息。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应红色字体的验证信息,进入互助群询问。


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

网络IO谁更快?Python与Go请求速度对比

上一篇关于Python和Go的文章是:

什么?Python Celery 也能调度Go worker?

文中我们讨论了Python Celery调度Go写的worker的方法。

而在 优劣互补! Python+Go结合开发的探讨

一文中,我们讨论了Go在单线程计算性能上的优势。

现在,考虑这样的一种场景:

我们需要从某些网址中同步数据并进行计算,保存到本地redis缓存中。

现在,我们可以通过编写Go Worker的方式,将计算和保存的过程保存在本地的redis缓存中,然后使用Celery来调度这些任务。

问题在于,从这些网址中获取数据的步骤,写在Go Worker里是否合适?Go进行网络请求是否比Python更稳定、速度更快?今天我们就来比较一下。

1.同步比较

首先,试试Go语言请求百度,获得这个请求和拿到回应之间的时间差:

package main

import (
    "fmt"
	"time"
	"net/http"
)

func main() {

	t1 := time.Now()
    resp, err := http.Get("https://baidu.com")
	t2 := time.Now()
	
	fmt.Println("spend time:", t2.Sub(t1))
	
    if err != nil {
		fmt.Println("请求失败")
    }

    defer resp.Body.Close()
}

结果如下:

可以看到,平均耗时在250ms左右。

然后测试Python的requests模块请求网站:

import requests
import time
t1 = time.time()*1000
requests.get("https://baidu.com")
t2 = time.time()*1000
print(t2-t1)

平均约220ms,似乎在单个请求的情况下,Python略胜一筹。

但是单个请求的比较是没有意义的,因为这个差异可以忽略不计。

重点还是在下面并发请求的比较上。

2.并发比较

现在,我们试试用Go语言并发请求10次百度:

package main

import (
    "fmt"
	"time"
	"net/http"
    "sync"
)

func test_get() {
	http.Get("https://baidu.com")
}

func main() {
	var numbers = 10
    var wg sync.WaitGroup
    wg.Add(numbers)
	t1 := time.Now()
	for i := 0; i < numbers; i++ {
		go func() {
			test_get()
			wg.Done()
		}()
	}
	wg.Wait()
	t2 := time.Now()
	
	fmt.Println("spend time:", t2.Sub(t1))
}

效果如下:

平均消耗在300ms左右,和单次请求差不多,速度还是相当快的。

接下来试试Python的并发请求,值得注意的是,这里没有用requests模板,因为requests模块是同步的,这一点一定要注意。

因此在这里需要使用aiohttp进行并发请求:

import asyncio
import time
from aiohttp import ClientSession


async def request_web():
    async with ClientSession() as session:
        async with session.get("https://baidu.com"):
            pass
 
loop = asyncio.get_event_loop()
tasks=[]
for i in range(10):
    tasks.append(request_web())

t1 = time.time()*1000
loop.run_until_complete(asyncio.wait(tasks))
t2 = time.time()*1000
print(t2 - t1)

测试结果如下:

可以看到,平均耗时在500ms左右,在并发的时候,其速度相比于Go略逊一筹。

3.总结

可以看到,Python在单个请求的时候(使用requests模块)速度比Go稍微快一丢丢,但是这样的区别几乎可以忽略不计。

在并发10次请求的情况下,Go平均耗时300ms,而Python平均耗时500ms,Go略胜一筹。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应的红字验证信息,进入互助群询问,请一定记得回复红字的问题,这样我才会拉你进群。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

Python 什么是元类(metaclasses)?

1.什么是类

在理解元类之前,我们必须先掌握Python中的类(class)。

和大多数语言一样,Python中的类知识用来描述如何“生成一个对象”:

>>> class ObjectCreator(object):
...       pass
...

>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

但是,在Python中,类不仅能用来描述如何生成一个对象,类本身也是对象

在你使用关键词 class 的时候,Python就会执行它,并创建一个对象。

>>> class ObjectCreator(object):
...       pass
...

上述指令在内存中创建了一个“ObjectiveCreator”的对象。

这个对象(类)本身具有创建对象(实例)的能力,因此它也是一个类。你可以对它做以下操作:

1.将其分配给变量
2.复制它
3.为其添加属性
4.将其作为函数参数传递

例如:

>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
...       print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>

2.动态创建类

由于类是对象,因此你可以像创建任何对象(数组、字典等)一样,随时随地创建类。

你甚至可以在函数里创建类:

>>> def choose_class(name):
...     if name == 'foo':
...         class Foo(object):
...             pass
...         return Foo # return the class, not an instance
...     else:
...         class Bar(object):
...             pass
...         return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>

但是,这样的类并不是很动态,因为你必须自己编写整个类。

使用class关键字时,Python会帮你自动创建此对象,但是,Python同样也提供了一种手动创建的方法,那就是type函数。

>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>

type函数最经典的用法是返回对象的类型。但是很少人知道,它还能接受参数并手动创建类。

type(name, bases, attrs)

其中

  • name: 类名
  • bases: 元组,父类名
  • attrs: 字典,类属性值

因此你可以这样手动创建类:

>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>

如果你想给它赋予属性,可以这样玩:

>>> class Foo(object):
...       bar = True

等同于

>>> Foo = type('Foo', (), {'bar':True})

用来继承也是可以的:

>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True

可见通过type()函数创建的类和直接写class是完全一样的。

因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

正常情况下,我们用class来定义类,但是,type()函数也允许我们动态创建类,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同。

Python是通过什么做到这一切的?那就是元类。

3.什么是元类

元类就是用于创建类的“东西”。

你定义类是为了创建对象,Python中所有的类都是对象。元类是用于创建这些对象的。可以看这个例子:

MyClass = MetaClass()
my_object = MyClass()

这有点像套娃。这段代码转化为type就是这样的:

MyClass = type('MyClass', (), {})

因此,我们可以得到一个基本事实,type 本身就是一个元类

其实,就是 type 在幕后创建了Python中所有的类。

通过检查__class__属性,你会看到Python中,一切对象都是基于 type 的:

>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>

那么,有个有趣的问题,__class__的__class__是什么呢?

>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

因此,元类只是创建类对象的东西,如果愿意,可以将其称为“类的工厂”。

type 是Python使用的内置元类。不过,你可以创建自己的元类。

3.1 __metaclass__属性

在Python 2中,可以在编写类时添加属性__metaclass__,使用某个元类来创建该类:

class Foo(object):
    __metaclass__ = something...
    [...]

不过,要小心的是,你虽然先写了 class Foo(object),但Foo这个对象尚未被创建,Python将先寻找__metaclass__类,找到后用它来创建Foo类。

如果没有这个__metaclass__类,它将使用 type 来创建类。

因此,类创建的流程是这样的:

1.创建的类中有__metaclass__元类属性吗?

2.如果有,那就用__metaclass__给该类在内存中创建一个类对象。

3.如果Python找不到__metaclass__,它将在MODULE级别查找__metaclass__属性 。

4.如果还是没有,那就使用父类的元类来创建类对象。

现在的问题就是,你可以在__metaclass__中放置些什么代码呢?

答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何继承或使用它的东西。

3.2 Python 3中的元类

设置元类的语法在Python3已改为:

class Foo(object, metaclass=something):
    ...

即不再使用__metaclass__属性,而是在基类参数列表中引入关键字参数。

不过元类的基本工作方式不变。在Python3中,你可以将属性作为关键字参数传递给元类:

class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
    ...

4.为什么需要元类

元类最主要的一个应用方向是创建API,一个最著名的应用是Django ORM,比如:

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

当你这样访问属性的时候:

person = Person(name='bob', age='35')
print(person.age)

它并不会返回models.IntegerField,而是返回了一个整形的数字。

这是因为models.Model引用了一个ModelBase类,该类随后进行了魔术般地操作,使其能够与数据库字段进行挂钩。

这就是元类的作用,Django通过它,完成了系列复杂的幕后工作,将原本非常复杂的事情变得非常简单。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

什么?Python Celery 也能调度Go worker?

我们曾经研究过如何让Python和Go互相调度,当时发现,将Go语言写的模块打包成动态链接库,就能在Python中进行调度:

优劣互补! Python+Go结合开发的探讨

Go的优势很明显,从1亿减到1,在我的设备上测试,用Go运行只需要50ms,Python可能需要接近100倍的时间。

但是,这种写法也有缺点:实在太麻烦了,大大增加了整个项目的耦合性。

那Python中有没有办法不通过打包成动态链接库的方法,用Python调度Go的任务呢?答案是Go celery.

https://github.com/gocelery/gocelery

我们可以用Go写一个计算密集型任务的Worker,然后用Python的Celery beat来调度这个Worker,下面给大家演示一下:

1.编写Go Worker

最好是将计算密集型的任务改造成Go语言版的,这样收益才能最大化。

比如这里,我使用的是上回从1亿减到1的老梗。

// 文件名: main.go
// Python实用宝典
package main

import (
	"fmt"
	"time"

	"github.com/gocelery/gocelery"
	"github.com/gomodule/redigo/redis"
)

func minus() {
    start := time.Now()
    decrement(100000000)
    fmt.Println(time.Since(start))
}

func decrement(n int) {
    for n > 0 {
        n -= 1
    }
}


func main() {

	// create redis connection pool
	redisPool := &redis.Pool{
		MaxIdle:     3,                 // maximum number of idle connections in the pool
		MaxActive:   0,                 // maximum number of connections allocated by the pool at a given time
		IdleTimeout: 240 * time.Second, // close connections after remaining idle for this duration
		Dial: func() (redis.Conn, error) {
			c, err := redis.DialURL("redis://")
			if err != nil {
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}

	// initialize celery client
	cli, _ := gocelery.NewCeleryClient(
		gocelery.NewRedisBroker(redisPool),
		&gocelery.RedisCeleryBackend{Pool: redisPool},
		5, // number of workers
	)

	// register task
	cli.Register("go_tasks.minus", minus)

	// start workers (non-blocking call)
	cli.StartWorker()

	// wait for client request
	time.Sleep(1000 * time.Second)

	// stop workers gracefully (blocking call)
	cli.StopWorker()
}

输入命令:

go run main.go

即可运行该worker

2.编写Python客户端

# 文件名: go_tasks.py
# Python实用宝典
from celery import Celery

app = Celery('go_tasks',broker='redis://127.0.0.1:6379')

app.conf.update(
    CELERY_TASK_SERIALIZER='json',
    CELERY_ACCEPT_CONTENT=['json'],  # Ignore other content
    CELERY_RESULT_SERIALIZER='json',
    CELERY_ENABLE_UTC=True,
    CELERY_TASK_PROTOCOL=1,
)


@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    # 每5秒调度一次1亿减到1,不过不跑Python worker,
    # 由于Go Worker在运行,这里的minus会被Go Worker消费。
    sender.add_periodic_task(5.0, minus.s())


@app.task
def minus():
    x = 100000000
    while x > 1:
        x = x-1

每5秒调度一次1亿减到1,不过不跑Python worker. 由于Go Worker在运行,这里的minus会被Go Worker消费。

另外请注意,这里的minus函数实际上只是为了能被识别到而编写的,其内容毫无意义,直接写个pass都没问题(因为实际上是Go Worker在消费)。

编写完后,针对go_tasks模块启动beat:

celery -A go_tasks beat

此时,调度器就会调度Go Worker执行任务:

可以看到,我们成功用Python的Celery Beat调度了Go写的Worker!可喜可贺。

接下来可以看看如果单纯用Python的Worker做这样的计算是有多耗时:

# 文件名: python_tasks
# Python实用宝典
from celery import Celery

app = Celery('python_tasks')


@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(1.0, minus.s())

@app.task
def minus():
    x = 100000000
    while x > 1:
        x = x-1

启动worker:

celery worker -A python_tasks -l info --pool=eventlet

启动beat调度器:

celery -A python_tasks beat

结果如下:

可以看到,Python从1亿减到1平均需要5.2秒左右的时间,和Go版相差了100倍左右。

如果我们将调度器的频率提高到每秒计算1次,Python版的Worker,其任务队列一定会堵塞,因为Worker消费能力不够强大。相比之下,Go版的Worker可就非常给力了。

因此,如果你的项目中有这种计算密集型的任务,可以尝试将其提取成Go版本试试,说不定有惊喜呢。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

Python 入门到进阶书籍推荐

入门

1.《像计算机科学家一样思考Python (第2版)》

简单、易懂、量少。“这是一本试图用python最小子集来揭示计算机思想的书。”,建议大家读过一遍后,再“练过”一遍。

计算机图书推荐阅读纸质版,条件不允许的话可在【Python 实用宝典】公众号后台回复 TP2 下载该书电子版。

2.《Python编程快速上手》

这是一本面向实践的书籍,讲了许多Python的实战教程(和本公众号一样),具有任务驱动性。当然,它仅仅也是初级的工具书而已。

计算机图书推荐阅读纸质版,条件不允许的话可在【Python 实用宝典】公众号后台回复 Python编程快速上手 下载该书电子版。

进阶

如果你坚持了下来,入门阶段结束后你就会想要更加深入地了解Python的美妙之处。

想要进阶,那不妨了解这几本书:

3.《流畅的Python》(必读)

“对于想要扩充知识的中级和高级Python程序员来说,这本书是充满了实用编程技巧的宝藏。” —— Daniel Greenfeld 和 Audrey Roy Greenfeld,Two Scoops of Django 作者

计算机图书推荐阅读纸质版,条件不允许的话可在【Python 实用宝典】公众号后台回复 流畅的Python 下载该书电子版。

4.《Python数据科学手册》(数据方向)

如果你学Python的目的是为了进行数据分析和数据挖掘,那么你需要这本手册,它介绍了 Numpy和Pandas的大部分功能的示例。

所谓手册,就是你要实现什么功能的时候翻书就能查到,我想这本手册是做到了。

本书英文电子版:
https://jakevdp.github.io/PythonDataScienceHandbook/

5.《Python Cookbook(第3版)》(高级)

这本书大部分内容集中于在标准库,框架和应用程序中广泛使用的高级技术。

这本书内有些更加高级的秘籍,如果耐心阅读,将有助于理解 Python 底层的工作原理。 从中你将学到一些新的技巧和技术,并应用到你自己的代码中去。

中文电子版:
https://python3-cookbook.readthedocs.io/zh_CN/latest/preface.html#id5

基本到这里就可以了,其实语言方面的书不用推荐很多。学完这5本,基本上不需要看别的Python相关的书了。

往后最重要的是工作实践获取经验,搜索引擎在手,随时可以再学习和补充。


我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

Python实用宝典7月精选实战教程

点击标题或者图片,均可直达文章。

1.Brython!极具意义的Python前端开发工具

没错,Python也能用来开发前端了,真的是无所不能。

使用Brython,你甚至不需要下载Python就能用Python写前端,非常方便。

2.国外牛人整理的Matplotlib超强使用指南与笔记

使用Matplotlib,没有搜索引擎就走不动路。

主要是因为Matplotlib的内容实在是太多了,只有经验丰富的人才能熟练掌握它。

国外有位开发者针对这种情况,写了五章使用指南,供君参考~

3.用Python实战制作一张极具意义的人生进度图

我觉得人生进度图还是很有必要绘制的。

你能根据人生进度图,从大局上规划未来和思考过去。

某些让你现在觉得很难过的经历,放到整个人生进度中,也不过影响你一两个小格子而已。

所以,通过人生进度图回顾过去,能让你更好地迈向未来。

4.Python 获取股票数据并存入MongoDB实战教程

我个人其实非常喜欢MongoDB,尤其是那些不需要事务和关系型的应用场景,MongoDB用起来会比MySQL舒服。

总的来说,MongoDB是一个绝对值得你学习的非关系型数据库。

5.Python 一个漂亮的音乐节奏可视化方案

通过可视化音乐节奏来学习音频处理的各种技巧。

6.Python celery异步快速下载股票数据

Python Celery 是一个非常重要的分布式异步任务队列,可以说是Python后台开发必不可少的组件。

如果你想用Python开发更高效的功能和模块,请学习Celery.

7.Python 三行代码检测爬虫

如果你有自己的网站,这篇文章是值得参考的,因为它提供了一个反爬虫的思路。

如果你没有自己的网站,这篇文章也是值得阅读的,因为它提供了一个反反爬虫的思路。

拒绝套娃。

8.编程利器!有道词典命令行快速翻译

每次编程遇到不会翻译的变量时,打开有道词典—等待响应—输入相关词汇,这一套流程起码得消耗30秒。

现在有了这个工具,你只需要在命令行输入一行命令,就能得到有道翻译的结果,效率极高,推荐使用!


7月份的这8篇原创文章大家觉得如何呢?欢迎在下方留言建议。​

如果你觉得有收获的话,点个赞、点个在看对于我而言都是一种莫大的支持,谢谢!

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。


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

Pycharm+Django 安装及配置指南

虽然平时我极力推荐使用简单、轻便、灵活的VSCode编辑器进行开发。

但是对于大型Web项目(Django、Tornado等框架)开发,我还是推荐大家使用Pycharm.

Pycharm拥有强大的配置工具、Git版本管理工具、代码补全工具、Debug工具等等,这些都是进行大型项目开发的利器。

尤其是今天的主角Django,由于太过于重要了,Pycharm甚至专门给其提供了配置模板:

能直接在新建项目的时候选择Django并新建一个独立的虚拟环境:

从新建到编码测试,一套流程用起来都极其方便。

1.下载Pycharm

在jetbrains官网选择相应的系统下载Pycharm:
https://www.jetbrains.com/pycharm/download/

这里强烈推荐下载Professional版(专业版),激活方法可以自行在网上查询,推荐知了哥的文章(zhile.io)。

安装完成后,根据你是否需要新建Django项目分为两种配置方式。

1.1 新建Django项目

File-New Project 新建一个Django项目:

强烈推荐新建一个环境,默认新建环境的工具是Virtualenv, 我这里用的是conda,效果其实都差不多。区别在于,conda可以选择Python版本

输入好location(安装位置)后点击create,即可生成Django项目。

1.2 配置已开发的Django项目

Pycharm中适配已开发的Django项目也非常容易,因为它为这种情况专门提供了配置模板:

点击右上角的配置框选择 Edit Configurations

进来后先输入Name 项目名称,然后在Python Interpreter选择你的代码所属环境的编译器,最后选择Fix,弹出Django配置页。

在点击Fix后出现的配置页中,输入这三项:

第一个是项目根目录,第二个是settings.py文件的位置,第三个是manage.py的位置。三者缺一不可。搞定后点击OK,配置完成。

2.运行项目

Pycharm运行Django项目只需要点击右上角这两者之一即可:

第一个是普通的启动方式,第二个是Debug启动方式,推荐第二个,因为开发的时候如果需要跟踪代码流程,Debug模式非常方便。

点击后会自动生成启动Django的命令,你可以在console里查看该语句,出现以下的输出即启动完成:

访问http://127.0.0.1:8000/就是网站的首页了。

这里默认使用的端口号是8000,你可以在配置页修改默认的域名和端口,只不过其他域名你需要在hosts中将其定向到127.0.0.1, 比如:

修改hosts文件,增加:dev.goldenstone.com 127.0.0.1

保存后修改右上角的configurations配置:

在settings.py中,将dev.goldenstone.com这个域名加入到 ALLOWED_HOSTS 中:

这样就可以通过 http://dev.goldenstone.com:5555/ 访问你的开发环境了:

3.工具

下面介绍一些Pycharm中独有的、特别的工具:

3.1 查看文件历史修改及提交记录非常方便:

点击每一个提交,都能看到每次提交的内容。

3.2 选择指定的commit行

VCS-Commit,它可以自由选择你需要提交的代码块:

3.3 自动格式化代码

3.4 全局搜索

尽管VSCode也有全局搜索,但相信我,他们两个不是一个概念:

windows下选择 Ctrl+shift+F 即可在Pycharm中全局搜索,或者在Edit-Find-Find in Path 找到该功能:

界面如下,它不仅仅是全局搜索,还能指定模块、目录进行搜索。

指定文件名搜索,高级过滤器中还能搜索指定除注释以外的符合关键词的句子等等,是一个非常强大的搜索工具。

这个搜索工具对于我而言,使用频率仅次于Debug工具。


Pycharm中非常有用的生产工具还有很多,简直是用都用不完,下次再给大家详细介绍一番!

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

Python 三行代码检测爬虫

是否担心别人将你的博客文章全部爬下来?

是否担心高频率爬虫导致网站瘫痪?

别担心,现在有一个Python写的神器——crawlerdetect,帮助你检测爬虫,保障网站的正常运转。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上噢,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),准备开始输入命令安装依赖。

当然,我更推荐大家用VSCode编辑器,把本文代码Copy下来,在编辑器下方的终端运行命令安装依赖模块,多舒服的一件事啊:Python 编程的最好搭档—VSCode 详细指南。

在终端输入以下命令安装我们所需要的依赖模块:

pip install crawlerdetect

看到 Successfully installed xxx 则说明安装成功。

2.使用方法

它可以通过user-agent、headers等请求头识别爬虫或机器人。

因此,你可以传递两种参数。第一种,使用user-agent检测机器人:

from crawlerdetect import CrawlerDetect
crawler_detect = CrawlerDetect(user_agent='Mozilla/5.0 (iPhone; CPU iPhone OS 7_1 like Mac OS X) AppleWebKit (KHTML, like Gecko) Mobile (compatible; Yahoo Ad monitoring; https://help.yahoo.com/kb/yahoo-ad-monitoring-SLN24857.html)')
crawler_detect.isCrawler()
# 如果是机器人,这条语句返回True

第二种识别方式会用上全部headers参数,这种方式比单纯用user-agent精准,因为它判断的依据更加全面。

from crawlerdetect import CrawlerDetect
crawler_detect = CrawlerDetect(headers={'DOCUMENT_ROOT': '/home/test/public_html', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HTTP_ACCEPT': '*/*', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_CACHE_CONTROL': 'no-cache', 'HTTP_CONNECTION': 'Keep-Alive', 'HTTP_FROM': 'googlebot(at)googlebot.com', 'HTTP_HOST': 'www.test.com', 'HTTP_PRAGMA': 'no-cache', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36', 'PATH': '/bin:/usr/bin', 'QUERY_STRING': 'order=closingDate', 'REDIRECT_STATUS': '200', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '3360', 'REQUEST_METHOD': 'GET', 'REQUEST_URI': '/?test=testing', 'SCRIPT_FILENAME': '/home/test/public_html/index.php', 'SCRIPT_NAME': '/index.php', 'SERVER_ADDR': '127.0.0.1', 'SERVER_ADMIN': 'webmaster@test.com', 'SERVER_NAME': 'www.test.com', 'SERVER_PORT': '80', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SIGNATURE': '', 'SERVER_SOFTWARE': 'Apache', 'UNIQUE_ID': 'Vx6MENRxerBUSDEQgFLAAAAAS', 'PHP_SELF': '/index.php', 'REQUEST_TIME_FLOAT': 1461619728.0705, 'REQUEST_TIME': 1461619728})
crawler_detect.isCrawler()
# 如果是机器人,这条语句返回True

你还可以识别相应爬虫的名字(如果有的话),通过这种方式,你能给一些著名的爬虫(如baiduspider、googlebot)添加白名单,不进行拦截。

from crawlerdetect import CrawlerDetect
crawler_detect = CrawlerDetect()
crawler_detect.isCrawler('Mozilla/5.0 (compatible; Sosospider/2.0; +http://help.soso.com/webspider.htm)')
# 如果是机器人,这条语句返回True
crawler_detect.getMatches()
# Sosospider

有了这个工具,我们就可以实现实时的爬虫封禁:

首先,你要实时监控网站上的http请求,检测其对应的headers.

其次,如果识别到该请求是机器人(爬虫)发出的,就可将其IP记录下来。

最后,将IP加入到Nginx或Apache的动态黑名单中,实现实时的爬虫封禁。

这一套流程我还没有试验过,大家有兴趣可以试试,理论上可行。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

Python 一个漂亮的音乐节奏可视化方案

相信很多人都有这样的疑问:如何用Python音乐的节奏可视化出来?我曾有过一篇文章:Python 提取音乐频谱并可视化,也不过是浅尝辄止,没有完成精美的可视化,只是将频谱用折线图进行了可视化

国外有个网友(u/avirzayev)分享了他的可视化方案。上方的视频就是用他的方案可视化Tattoo.mp3得到的结果,大家可以欣赏一下。

这份代码确实有效地跟上了音乐的节奏,如果能加强可视化效果,丰富颜色,是一份非常好的可视化代码。

下面给大家介绍一下怎么使用这份代码:

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上噢,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),准备开始输入命令安装依赖。

当然,我更推荐大家用vscode编辑器,把本文代码Copy下来,在编辑器下方的终端运行命令安装依赖模块,多舒服的一件事啊:Python 编程的最好搭档—VSCode 详细指南。

在终端输入以下命令安装我们所需要的依赖模块:

pip install matplotlib
pip install librosa
pip install numpy
pip install pygame

看到 Successfully installed xxx 则说明安装成功。

当然,还有作者的源代码,请在 Python实用宝典 公众号后台回复:【音乐可视化】获取

2.代码调整

代码架构分为两个部分,一个是用于计算频谱的 AudioAnalyzer.py,一个用于渲染生成动态视频的 mAIn.py.

这个“动态视频”是基于pygame实现的,部分代码如下:

作者的代码风格随意,不过仔细阅读还是能读懂大概的。

首先,通过pygame加载(load)音乐文件并播放(play).

然后,通过while循环和ticks对画面中的图像进行实时渲染。

渲染的代码比较长,就是一些计算柱体长度的过程,这里就不赘述了,有兴趣的同学可以开源代码。

如果你想要将你的音乐用这份代码进行可视化,仅需要修改mAIn.py的第5行代码:

这个filename可以是当前运行Python的路径下的音乐文件名称,也可以是音乐文件的绝对路径。

如果你想优化生成的动态图像的颜色,可以修改rnd_color函数,该函数控制图形颜色的变化:

如果你想修改生成的动态图像的形状,比如说去掉中间那个圆,仅需要这么改:

pygame.draw.circle(screen, circle_color, (circleX, circleY), int(radius))

将radius直接设为0,或者直接将这行代码注释掉即可:

pygame.draw.circle(screen, circle_color, (circleX, circleY), 0)

效果:

如果你熟悉pygame的相关函数,可以对这份可视化的代码做更多的DIY,比如说将其展平到平面上,用一条条柱体来展示,像网易云音乐一样:

尽管不可能做得像真正的产品那样好看,不过大家可以先试试,这份代码我就留着下次再展示吧。

如果有遇到不懂的,请在公众号后台回复:加群,加入互助群。记得备注相应的验证信息我才会通过哦。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


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

优劣互补! Python+Go结合开发的探讨

1.都说Go语言性能非常强大,那么到底比Python强多少?

为了比较Go语言和Python语言在单线程性能上的差距,我们可以做一个简单实验,从1亿减到1:

Python代码:

import time
def decrement(n):
    while n > 0:
         n -= 1

start = time.time()
decrement(100000000)
end = time.time()
print(f"{end - start}s.")

结果如下:

大约需要4秒-5秒才能完成这项工作,那么Go语言呢?

package main

import "fmt"
import "time"

var c chan int

func decrement(n int) {
    for n > 0 {
        n -= 1
    }
}

func main() {
    start := time.Now()
    decrement(100000000)
    fmt.Println(time.Since(start))
}

结果如下:

确实,两者差了不止100倍,看得出来Go是一个比较有前途的语言,具有强大的性能(除此之外,它还有简单易学、能轻松实现高并发的特点)。

不过,它的社区建设和Python相比还是有很大的差距,许多第三方库依然还没有支持Go语言。因此,它想要替代Python还有非常长的路要走。

2.Go性能强大、Python社区强大,两者能否结合起来?

我们试试看能否在Python中调用Go的方法,在Go中从1亿减到1。

首先,将刚刚go语言版的1亿减到1改为在一个函数中进行,并返回结果:

package main

import (
    "C"
    "time"
)

var c chan int

func decrement(n int) {
    for n > 0 {
        n -= 1
    }
}

//export count_time
func count_time() *C.char {
    start := time.Now()
    decrement(100000000)
    total_time := time.Since(start).String()
    return C.CString(total_time)
}

func main() {}

然后生成动态链接库以便Python调用Go里写的函数:

go build -buildmode=c-shared -o main.so count.go

这样会在当前文件夹中生成 main.so 和 main.h.

在Python中我们需要加载该生成的main.so动态链接库,并配置好输出变量的类型,最后调用方法得到结果:

import time
from ctypes import cdll, c_char_p

start = time.time()

# 加载动态链接库
lib = cdll.LoadLibrary('./main.so')

# 配置输出参数变量类型
lib.count_time.restype = c_char_p

# 调用方法
rest = lib.count_time()

end = time.time()

print(f"Go 内部执行时间:{rest}")
print(f"Python 整体执行时间: {end - start}s")

结果如下:

可以看到,使用这个方案将Python和Go两者结合起来的性能依然非常高,但就是多了一个生成和调用动态链接库的过程,增加了代码的耦合性。

其实,这也是C+Python的开发方式,只不过我们将C换成了Go,因为Go开发起来实在是舒服多了。

如果以后你的Python代码中有某个部分计算特别复杂,你可以尝试将其改写成go,通过动态链接库的方式调用go写的代码,将能大大提高性能。

这样,既能安心享受Python带来的丰富社区资源,又能享受Go语言的性能优势,真的美滋滋。

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


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