Python之路【第二十篇】Tornado框架

Tornado

Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。

我们现在所知道的Tornado是基于Bret Taylor和其他人员为FriendFeed所开发的网络服务框架,当FriendFeed被Facebook收购后得以开源。不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。

C10K问题

基于线程的服务器,如Apache,为了传入的连接,维护了一个操作系统的线程池。Apache会为每个HTTP连接分配线程池中的一个线程,如果所有的线程都处于被占用的状态并且尚有内存可用时,则生成一个新的线程。尽管不同的操作系统会有不同的设置,大多数Linux发布版中都是默认线程堆大小为8MB。Apache的架构在大负载下变得不可预测,为每个打开的连接维护一个大的线程池等待数据极易迅速耗光服务器的内存资源。

大多数社交网络应用都会展示实时更新来提醒新消息、状态变化以及用户通知,这就要求客户端需要保持一个打开的连接来等待服务器端的任何响应。这些长连接或推送请求使得Apache的最大线程池迅速饱和。一旦线程池的资源耗尽,服务器将不能再响应新的请求。

异步服务器在这一场景中的应用相对较新,但他们正是被设计用来减轻基于线程的服务器的限制的。当负载增加时,诸如Node.js,lighttpd和Tornodo这样的服务器使用协作的多任务的方式进行优雅的扩展。也就是说,如果当前请求正在等待来自其他资源的数据(比如数据库查询或HTTP请求)时,一个异步服务器可以明确地控制以挂起请求。异步服务器用来恢复暂停的操作的一个常见模式是当合适的数据准备好时调用回调函数。

快速入手

1、安装Tornado

pip install tornado
源码安装:https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

2、第一个Tornado程序

#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = ‘luotianshuai‘

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/index", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

基本上所有的WEB框架都有以下的流程(以Tornado为例):

准备阶段

加载配置文件

加载路由映射   application = tornado.web.Application([(r"/index", MainHandler),])

创建socket   sk = socket

循环阶段

类似socket Server不断的循环监听文件句柄,当有请求过来的时候,根据用户的请求方法来来判断是什么请求,在通过反射来执行相应的函数或类

运行流程:

第一步:执行脚本,监听 8888 端口
第二步:浏览器客户端访问 /index  -->  http://127.0.0.1:8888/index
第三步:服务器接受请求,并交由对应的类处理该请求
第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法
第五步:方法返回值的字符串内容发送浏览器

 3、application

application = tornado.web.Application([
    (r"/index", MainHandler),
])

内部在执行的时候执行了两个方法__init__方法和self.add_handlers(".*$", handlers)方法{源码后期解析Tornado时补充}

这个add_handlers默认传输的".*$" 就是www,他内部生成的路由映射的时候相当于(二级域名的方式)下图:

我们可以通过application.add_handlers,添加一个“shuaige.com”,他会生成一个类似下面的对应关系

shuaige

.*

如果匹配的是shuaige他会去"shuaige"里去找对应关系,如果没有匹配默认就去.*,他这个就类似Django中的URL分类!~~

application = tornado.web.Application([
    (r"/index", MainHandler),
])

application.add_handlers("shuaige.com",([
    (r"/index", MainHandler),
])
)

路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类。

#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = ‘luotianshuai‘

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

class Shuaige(tornado.web.RedirectHandler):
    def get(self):
        self.write("This is shuaige web site,hello!")

application = tornado.web.Application([
    (r"/index", MainHandler),
])

application.add_handlers("shuaige.com",([
    (r"/index", Shuaige),
])
)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

模板

Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。

Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }}

控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhile 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。这些在 template 模块 的代码文档中有着详细的描述。

目录结构:

Tornado主文件:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render(‘index.html‘)

settings = {
    ‘template_path‘: ‘template‘,
    ‘static_path‘: ‘static‘,
    ‘static_url_prefix‘: ‘/static/‘,
}

application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

主模板html(layout.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>shuaige</title>
    {% block css%}

    {% end %}
</head>
<body>

    <div><h1>TEST</h1></div>
    {% block htmlbody %}{% end %}

    <script src="{{static_url(‘js/jquery-1.8.2.min.js‘)}}"></script>

    {% block JavaScript %}{% end %}

</body>
</html>

子版(index.html)

{% extends ‘layout.html‘ %}

{% block css %}
    <link href="{{static_url(‘css/index.css‘)}}" rel="stylesheet" />
{% end %}

{% block htmlbody %}
    <h1 id="shuaige" class="tim">没有取值,就先这样吧,循环就先不写了.</h1>
{% end %}

{% block JavaScript %}

{% end %}

for循环使用如下:

{% extends ‘layout.html‘%}
{% block CSS %}
    <link href="{{static_url("css/index.css")}}" rel="stylesheet" />
{% end %}

{% block RenderBody %}
    <h1>Index</h1>

    <ul>
    {%  for item in li %}
        <li>{{item}}</li>
    {% end %}
    </ul>

{% end %}

{% block JavaScript %}

{% end %}

在模板中默认提供了一些函数、字段、类以供模板使用:

  • escapetornado.escape.xhtml_escape 的別名
  • xhtml_escapetornado.escape.xhtml_escape 的別名
  • url_escapetornado.escape.url_escape 的別名
  • json_encodetornado.escape.json_encode 的別名
  • squeezetornado.escape.squeeze 的別名
  • linkifytornado.escape.linkify 的別名
  • datetime: Python 的 datetime 模组
  • handler: 当前的 RequestHandler 对象
  • requesthandler.request 的別名
  • current_userhandler.current_user 的別名
  • localehandler.locale 的別名
  • _handler.locale.translate 的別名
  • static_url: for handler.static_url 的別名
  • xsrf_form_htmlhandler.xsrf_form_html 的別名

2、自定义模板

Tornado默认提供的这些功能其实本质上就是 UIMethod 和 UIModule,我们也可以自定义从而实现类似于Django的simple_tag的功能:

1、定义

def tab(self):
    return ‘UIMethod‘

#文件名 uimethods.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from tornado.web import UIModule
from tornado import escape

class custom(UIModule):

    def render(self, *args, **kwargs):
        return escape.xhtml_escape(‘<h1>wupeiqi</h1>‘)
        #return escape.xhtml_escape(‘<h1>wupeiqi</h1>‘)

#文件名 uimodules.py

2、注册

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
from tornado.escape import linkify
import uimodules as md
import uimethods as mt

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render(‘index.html‘)

settings = {
    ‘template_path‘: ‘template‘,
    ‘static_path‘: ‘static‘,
    ‘static_url_prefix‘: ‘/static/‘,
    ‘ui_methods‘: mt,
    ‘ui_modules‘: md,
}

application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(8009)
    tornado.ioloop.IOLoop.instance().start()

main.py

实用功能

1、静态文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render(‘index.html‘)

settings = {
    ‘template_path‘: ‘template‘,
    ‘static_path‘: ‘static‘,
    ‘static_url_prefix‘: ‘/static/‘,
}

application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

在html中引用的时候

    <link href="{{static_url(‘css/index.css‘)}}" rel="stylesheet" />

目录结构:

静态文件缓存:

<link href="{{static_url(‘css/index.css‘)}}" rel="stylesheet" />
#这里static_url  为什么不写路径呢?
‘‘‘
在Django中,我们写成变量形式的主要是为了以后扩展方便。但是在Tornado中不仅有这个功能还有一个缓存的功能
‘‘‘

原理:

拿一个静态文件来说:/static/commons.js如果用Tornado封装后,类似于给他加了一个版本号/static/commons.js?v=sldkfjsldf123

当客户端访问过来的时候会携带这个值,如果发现没变客户端缓存的静态文件直接渲染就行了,不必再在服务器上下载一下静态文件了。

Tornado静态文件实现缓存源代码:

    def get_content_version(cls, abspath):
        """Returns a version string for the resource at the given path.

        This class method may be overridden by subclasses.  The
        default implementation is a hash of the file‘s contents.

        .. versionadded:: 3.1
        """
        data = cls.get_content(abspath)
        hasher = hashlib.md5()
        if isinstance(data, bytes):
            hasher.update(data)
        else:
            for chunk in data:
                hasher.update(chunk)
        return hasher.hexdigest()

2、CSRF

Tornado中的夸张请求伪造和Django中的相似,跨站伪造请求(Cross-site request forgery)

首先在index.py中启用

settings = {
    "xsrf_cookies": True,
}
application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/login", LoginHandler),
], **settings)

在form表单提交的时候加上

<form action="/new_message" method="post">
  {{ xsrf_form_html() }}
  <input type="text" name="message"/>
  <input type="submit" value="Post"/>
</form>

Ajax在使用的时候如下

function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
}

jQuery.postJSON = function(url, args, callback) {
    args._xsrf = getCookie("_xsrf");
    $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST",
        success: function(response) {
        callback(eval("(" + response + ")"));
    }});
};

注:Ajax使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求

自定义Session

对Session来说Tornado是没有的,Cookie和Session的关系可以参考我之前写的博客:http://www.cnblogs.com/luotianshuai/p/5278175.html

简单回顾下:

1、自动生成一段字符串

2、将字符串发送到客户端的浏览器,同时把字符串当做key放在session里。(可以理解为session就是一个字典)

3、在用户的session对应的value里设置任意值

操作session

  • 获取session:request.session[key]
  • 设置session:reqeust.session[key] = value
  • 删除session:del request[key]
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。

2、上面是Django的原理是一样的,那么我们来自己写一个Session

2.1、储备知识点

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

    def __getitem__(self, key):
        print  ‘__getitem__‘,key

    def __setitem__(self, key, value):
        print ‘__setitem__‘,key,value

    def __delitem__(self, key):
        print ‘__delitem__‘,key

2.2、代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time

session_container = {}

create_session_id = lambda: sha1(‘%s%s‘ % (os.urandom(16), time.time())).hexdigest()

class Session(object):

    session_id = "__sessionId__"

    def __init__(self, request):
        #当你请求过来的时候,我先去get_cookie看看有没有cookie!目的是看看有没有Cookie如果有的话就不生成了,没有就生成!
        session_value = request.get_cookie(Session.session_id)
        #如果没有Cookie生成Cookie[创建随机字符串]
        if not session_value:
            self._id = create_session_id()
        else:
            #如果有直接将客户端的随机字符串设置给_id这个字段,随机字符串封装到self._id里了
            self._id = session_value
        #在给它设置一下
        request.set_cookie(Session.session_id, self._id)

    def __getitem__(self, key):
        ret = None
        try:
            ret =  session_container[self._id][key]
        except Exception,e:
            pass
        return ret

    def __setitem__(self, key, value):
        #判断是否有这个随机字符串
        if session_container.has_key(self._id):
            session_container[self._id][key] = value
        else:
            #如果没有就生成一个字典
            ‘‘‘
            类似:随机字符串:{‘IS_LOGIN‘:‘True‘}
            ‘‘‘
            session_container[self._id] = {key: value}

    def __delitem__(self, key):
        del session_container[self._id][key]

class BaseHandler(tornado.web.RequestHandler):

    def initialize(self):
        ‘‘‘
        这里initialize的self是谁?
        obj = LoginHandler()
        obj.initialize() ==>这里LoginHandler这个类里没有initialize这个方法,在他父类里有
        所以initialize得self就是LoginHandler的对象
        ‘‘‘
        self.my_session = Session(self) #执行Session的构造方法并且把LoginHandler的对象传过去
        ‘‘‘
        这个self.my_session = Session()
        看这个例子:
        self.xxx = ‘123‘  在这里创建一个对象,在LoginHandler中是否可以通过self.xxx去访问123这个值?
        可以,因为self.xxx 是在get之前执行的,他们俩的对象都是LoginHandler对象
        ‘‘‘

class MainHandler(BaseHandler):

    def get(self):
        ret = self.my_session[‘is_login‘]
        if ret:
            self.write(‘index‘)
        else:
            self.redirect("/login")

class LoginHandler(BaseHandler):
    def get(self):
        ‘‘‘
        当用户访登录的时候我们就得给他写cookie了,但是这里没有写在哪里写了呢?
        在哪里呢?之前写的Handler都是继承的RequestHandler,这次继承的是BaseHandler是自己写的Handler
        继承自己的类,在类了加扩展initialize! 在这里我们可以在这里做获取用户cookie或者写cookie都可以在这里做
        ‘‘‘
        ‘‘‘
        我们知道LoginHandler对象就是self,我们可不可以self.set_cookie()可不可以self.get_cookie()
        ‘‘‘
        # self.set_cookie()
        # self.get_cookie()

        self.render(‘login.html‘, **{‘status‘: ‘‘})

    def post(self, *args, **kwargs):
        #获取用户提交的用户名和密码
        username = self.get_argument(‘username‘)
        password = self.get_argument(‘pwd‘)
        if username == ‘wupeiqi‘ and password == ‘123‘:
            #如果认证通过之后就可以访问这个self.my_session对象了!然后我就就可以吧Cookie写入到字典中了,NICE
            self.my_session[‘is_login‘] = ‘true‘

            ‘‘‘
            这里用到知识点是类里的:
            class Foo(object):
                def __getitem__(self,key):
                    print ‘__getitem__‘,key

                def __setitem__(self,key,value):
                    print ‘__setitem__‘,key,value

                def __delitem__(self,key):
                    print ‘__delitem__‘,key

            obj = Foo()
            result = obj[‘k1‘] #自动触发执行  __getitem__
            obj[‘k2‘] = ‘wupeiqi‘ #自动触发执行 __setitem__
            del obj[‘k1‘] #自动触发执行  __delitme__

            ‘‘‘

            self.redirect(‘/index‘)
        else:
            self.render(‘login.html‘, **{‘status‘: ‘用户名或密码错误‘})

settings = {
    ‘template_path‘: ‘template‘,
    ‘static_path‘: ‘static‘,
    ‘static_url_prefix‘: ‘/static/‘,
    ‘cookie_secret‘: ‘aiuasdhflashjdfoiuashdfiuh‘,
    ‘login_url‘: ‘/login‘
}

application = tornado.web.Application([
    #创建两个URL 分别对应  MainHandler  LoginHandler
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

分布式Session框架

上面通过Tornado预留扩展和Class中使用的知识实现了session框架,那么来看下如何实现分布式Session框架!

首先来看下,上面面的这个session,默认是保存在:session_container = {} 这个可不可使是Redis,memcache,mysql?如果们把session都存储到这台机器上不管以后去增加、删除、查询的时候都得去这台机器上去拿

一旦这台数据挂掉,或者数据量大的时候这是这台机器就满足不了了!

这是我们就需要考虑分布式了!比如有3台机器,然后一部分放在A机器上、一部分放在B机器上、一部分放在C机器上:如下图:

当用户访问过来的时候通过权重和hash计算把session加入到hash环中的服务上,实现分不到不同的主机上存储,当第二次user携带Cookie过来的时候通过计算找到Session所在的服务器取出并认证!

#!/usr/bin/env python
#coding:utf-8

import sys
import math
from bisect import bisect

if sys.version_info >= (2, 5):
    import hashlib
    md5_constructor = hashlib.md5
else:
    import md5
    md5_constructor = md5.new

class HashRing(object):
    """一致性哈希"""

    def __init__(self,nodes):
        ‘‘‘初始化
        nodes : 初始化的节点,其中包含节点已经节点对应的权重
                默认每一个节点有32个虚拟节点
                对于权重,通过多创建虚拟节点来实现
                如:nodes = [
                        {‘host‘:‘127.0.0.1:8000‘,‘weight‘:1},
                        {‘host‘:‘127.0.0.1:8001‘,‘weight‘:2},
                        {‘host‘:‘127.0.0.1:8002‘,‘weight‘:1},
                    ]
        ‘‘‘

        self.ring = dict()
        self._sorted_keys = []

        self.total_weight = 0

        self.__generate_circle(nodes)

    def __generate_circle(self,nodes):
        for node_info in nodes:
            self.total_weight += node_info.get(‘weight‘,1)

        for node_info in nodes:
            weight = node_info.get(‘weight‘,1)
            node = node_info.get(‘host‘,None)

            virtual_node_count = math.floor((32*len(nodes)*weight) / self.total_weight)
            for i in xrange(0,int(virtual_node_count)):
                key = self.gen_key_thirty_two( ‘%s-%s‘ % (node, i) )
                if self._sorted_keys.__contains__(key):
                    raise Exception(‘该节点已经存在.‘)
                self.ring[key] = node
                self._sorted_keys.append(key)

    def add_node(self,node):
        ‘‘‘ 新建节点
        node : 要添加的节点,格式为:{‘host‘:‘127.0.0.1:8002‘,‘weight‘:1},其中第一个元素表示节点,第二个元素表示该节点的权重。
        ‘‘‘
        node = node.get(‘host‘,None)
        if not node:
                raise Exception(‘节点的地址不能为空.‘)

        weight = node.get(‘weight‘,1)

        self.total_weight += weight
        nodes_count = len(self._sorted_keys) + 1

        virtual_node_count = math.floor((32 * nodes_count * weight) / self.total_weight)
        for i in xrange(0,int(virtual_node_count)):
            key = self.gen_key_thirty_two( ‘%s-%s‘ % (node, i) )
            if self._sorted_keys.__contains__(key):
                raise Exception(‘该节点已经存在.‘)
            self.ring[key] = node
            self._sorted_keys.append(key)

    def remove_node(self,node):
        ‘‘‘ 移除节点
        node : 要移除的节点 ‘127.0.0.1:8000‘
        ‘‘‘
        for key,value in self.ring.items():
            if value == node:
                del self.ring[key]
                self._sorted_keys.remove(key)

    def get_node(self,string_key):
        ‘‘‘获取 string_key 所在的节点‘‘‘
        pos = self.get_node_pos(string_key)
        if pos is None:
            return None
        return self.ring[ self._sorted_keys[pos]].split(‘:‘)

    def get_node_pos(self,string_key):
        ‘‘‘获取 string_key 所在的节点的索引‘‘‘
        if not self.ring:
            return None

        key = self.gen_key_thirty_two(string_key)
        nodes = self._sorted_keys
        pos = bisect(nodes, key)
        return pos

    def gen_key_thirty_two(self, key):

        m = md5_constructor()
        m.update(key)
        return long(m.hexdigest(), 16)

    def gen_key_sixteen(self,key):

        b_key = self.__hash_digest(key)
        return self.__hash_val(b_key, lambda x: x)

    def __hash_val(self, b_key, entry_fn):
        return (( b_key[entry_fn(3)] << 24)|(b_key[entry_fn(2)] << 16)|(b_key[entry_fn(1)] << 8)| b_key[entry_fn(0)] )

    def __hash_digest(self, key):
        m = md5_constructor()
        m.update(key)
        return map(ord, m.digest())

"""
nodes = [
    {‘host‘:‘127.0.0.1:8000‘,‘weight‘:1},
    {‘host‘:‘127.0.0.1:8001‘,‘weight‘:2},
    {‘host‘:‘127.0.0.1:8002‘,‘weight‘:1},
]

ring = HashRing(nodes)
result = ring.get_node(‘98708798709870987098709879087‘)
print result

"""

更多参考:http://www.cnblogs.com/wupeiqi/articles/5341480.html

时间: 2024-08-27 13:02:35

Python之路【第二十篇】Tornado框架的相关文章

Python之路(第二十篇) subprocess模块

一.subprocess模块 subprocess英文意思:子进程 那什么是进程呢? (一)关于进程的相关理论基础知识 进程是对正在运行程序的一个抽象,进程的概念起源于操作系统,是操作系统最核心的概念,操作系统的其他所有内容都是围绕进程的概念展开的. 所以想要真正了解进程,必须事先了解操作系统. 程序员无法把所有的硬件操作细节都了解到,管理这些硬件并且加以优化使用是非常繁琐的工作,这个繁琐的工作就是操作系统来干的,有了他,程序员就从这些繁琐的工作中解脱了出来,只需要考虑自己的应用软件的编写就可以

Python开发【第二十篇】:缓存

Python开发[第二十篇]:缓存redis&Memcache 点击这里 Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached基于一个存储键/值对的hashmap.其守护进程(daemon )是用C写的,但是客户端可

Python之路(第二十六篇) 面向对象进阶:内置方法

一.__getattribute__ object.__getattribute__(self, name) 无条件被调用,通过实例访问属性.如果class中定义了__getattr__(),则__getattr__()不会被调用(除非显示调用或引发AttributeError异常) class Foo: ? def __init__(self,x): self.x = x ? def __getattr__(self, item): print("执行__getattr__") ?

Python之路(第二十七篇) 面向对象进阶:内置方法、描述符

一.__call__ 对象后面加括号,触发执行类下面的__call__方法. 创建对象时,对象 = 类名() :而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()() class Foo: ? def __call__(self, *args, **kwargs): print("我执行啦") ? f = Foo() f() #对象加括号调用执行类下的__call__方法 #输出结果 我执行啦 二.__next__和__iter__实现迭代器协议 迭

Python开发【第二十二篇】:Web框架之Django【进阶】

Python开发[第二十二篇]:Web框架之Django[进阶] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 新随笔 联系 订阅 管理 随笔-124  文章-127  评论-205 Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻

Python开发【第二十一篇】:Web框架之Django【基础】

Python开发[第二十一篇]:Web框架之Django[基础] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5237704.html Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. 基本配置 一.创建django程序 终端命令:django-a

Python之路【第九篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached基于一个存储键/值对的hashmap.其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信. Memc

Python之路【第九篇】:Python基础(26)——socket server

socketserver Python之路[第九篇]:Python基础(25)socket模块是单进程的,只能接受一个客户端的连接和请求,只有当该客户端断开的之后才能再接受来自其他客户端的连接和请求.当然我 们也可以通过python的多线程等模块自己写一个可以同时接收多个客户端连接和请求的socket.但是这完全没有必要,因为python标准库已经为 我们内置了一个多线程的socket模块socketserver,我们直接调用就可以了,完全没有必要重复造轮子. 我们只需简单改造一下之前的sock

七日Python之路--第二天

由于之前使用过一段Ubuntu,所以基本命令啥的都还可以.装差利器Vim也是使用过一段时间的. Ubuntu快速打开终端Alt+Ctrl+T,这样才显得犀利一些嘛.说实话,终端编辑文件啥的,确实比Win下面爽的多,毕竟Win主打图形化的嘛.感觉废话有点多. 今天本想继续研究枯燥的官方文档,但昨夜偶然发现网易云课堂,如此犀利的资源怎能浪费. 零基础入门学习Python 讲师:小甲鱼 发布者:鱼C工作室 ,这个视频还是个人还是比较喜欢的,之前在youku上看到过几段,但是不全.http://stud

第二十篇:DDR内存读写问题

最近在实际的项目中碰到这样的问题: 嵌入式系统DDR (RBC row, bank, columne), 每块1Gbit816, 两块由片选决定读写其中的一块. Memory controller通过AXI连接在SOC中. 1. 在I-CACHE没有使能的情况下, 通过MC访问DDR有三路TRAFFIC, 分别是取指令, CPU刷/写FRAME BUFFER, DMA取/读FRAME BUFFER的数据 在低分辨率的情况下, 没有发现图像闪烁, 到了高分辨率的情况(1680*1050 60p,