趣味编程网站Codecademy新增了Python编程语言的学习课程

趣味编程网站Codecademy今天增加了Python编程语言的编程学习课程。就在上个月,公司刚获得一轮1000万美元的融资,Codecademy网站也新增5个语言的版本,包括中文、俄语、日语、西班牙语和德语。 Codecademy此前就已经支持JavaScript、HTML和CSS三种编程语言的编程学习课程。公司联合创始人Zach Sim表示,支持Python编程语言只是一个开始,Codecademy在未来还将提供更多的编程语言学习课程。不过Sims并没有透露具体还将新增哪些编程语言。 去年年底,Codecademy推出了实验室Labs功能,目的是为了能让人们更方便地学以致用,免去下载安装桌面版本的编辑器或集成开发环境(IDE)的麻烦。除了编辑,Codecademy Labs还能让你运行和下载可执行文件,拿到别的地方去运行。你不仅可以在上面学习磨练你的JavaScript,要是你在别的地方也学了Python和Ruby,你同样可以在Codecademy上面磨刀霍霍地训练起来。不过当时还没有Python课程,今天Codecademy上的Python课程终于推出。 Sims还表示,从一开始,Codecademy用户就对Python编程课程有强烈的需求,其中大部分是中学或大学的老师。对于想学习编程的新手,他们不妨加入Codecademy推出的新年编程项目Code Year,他们在这里可以进行JavaScript、HTML、CSS和jQuery的混合编程练习。

阅读全文 »

谈谈Python函数的默认参数

Python中很奇葩的一个地方是它的函数的默认参数的值,仅仅在def语句执行的时候计算一次。这会导致什么问题呢? 奇葩的例子 我们来看一个例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 In [44]: def packitem(item, pkg = []): ....: pkg.append(item) ....: return pkg In [45]: l = [100,200] In [46]: packitem(300, l) Out[46]: [100, 200, 300] In [47]: packitem(1) Out[47]: [1] In [48]: packitem(2) Out[48]: [1, 2] In [49]: packitem(3) Out[49]: [1, 2, 3] 这个可以看到packitem的默认参数pkg=[]仅仅计算了一次。而之后的packitem函数调用时,pkg都指向了最初创建的那个列表。 为什么 为什么会这样呢? 我们此时需要从Python编译出来的字节码中寻求答案。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 In [65]: def main(): ....: def packitem(item, pkg = []): ....: pkg.append(item) ....: return pkg ....: print packitem(1) ....: print packitem(2) ....: print packitem(3) In [66]: main() [1] [1, 2] [1, 2, 3] In [67]: dis.dis(main) 2 0 BUILD_LIST 0 3 LOAD_CONST 1 (code object) 6 MAKE_FUNCTION 1 9 STORE_FAST 0 (packitem) 5 12 LOAD_FAST 0 (packitem) 15 LOAD_CONST 2 (1) 18 CALL_FUNCTION 1 21 PRINT_ITEM 22 PRINT_NEWLINE 6 23 LOAD_FAST 0 (packitem) 26 LOAD_CONST 3 (2) 29 CALL_FUNCTION 1 32 PRINT_ITEM 33 PRINT_NEWLINE 7 34 LOAD_FAST 0 (packitem) 37 LOAD_CONST 4 (3) 40 CALL_FUNCTION 1 43 PRINT_ITEM 44 PRINT_NEWLINE 45 LOAD_CONST 0 (None) 48 RETURN_VALUE 可以看出。packitem函数的默认参数pkg的值是在第一条字节码创建的。随后在MAKE_FUNCTION指令的时候一起和code object打包成一个函数对象,然后通过STORE_FAST 0存在了FAST表的第0位。 后续的函数调用通过LOAD_FAST 0指令将packitem的函数对象取出,然后通过CALL_FUNCTION调用(对于CALL_FUNCTION,我们会在后续的文章进行探讨)。整个函数调用的过程并没有涉及到默认参数值的初始化。 所以,可见,Python函数的默认参数的值仅在函数定义的时候计算,后续的函数调用时的默认参数都是引用最初创建的那个对象。 Hack It 既然Python没有在我们进行函数调用的时候帮我们重新创建的默认参数的值,那我们就自己动手,丰衣足食。 第一种方案是是用不可变的默认值,例如None,然后在函数内部进行判断。此法略显麻烦。 第二种方案是通过装饰器来解决这个问题。 这段脚本是Sean Ross写的,非常感谢他。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 In [74]: def freshdefaults(f): ....: fdefaults = f.func_defaults ....: def refresher(*args, **kwds): ....: f.func_defaults = copy.deepcopy(fdefaults) ....: return f(*args, **kwds) ....: return refresher In [75]: @freshdefaults ....: def packitem(item, pkg = []): ....: pkg.append(item) ....: return pkg In [76]: l = [100,200] In [77]: packitem(300, l) Out[77]: [100, 200, 300] In [78]: packitem(1) Out[78]: [1] In [79]: packitem(2) Out[79]: [2] In [80]: packitem(3) Out[80]: [3] 可以看到,packitem的输出符合我们的预期了。我们通过装饰器freshdefault,完成了对于默认参数的更新。packitem的pkg已经在每次调用的时候更新了。 装饰器等价于 1 myfunc = wrapper(myfunc) 在此例子中 ,等价于在后面加上了一句 1 packitem = freshdefault(packitem) 参考 Python Cookbook Python源码剖析 ...

阅读全文 »

在 web.py 中使用装饰器

import web
urls = (
'/', 'hello',
)
app = web.application(urls, globals())
def hold(func):
print 'run hlod'
def f(self):
print 'in hold func'
return 'hold'
return f
class hello:
@hold
def GET(self):
print 'in hello'
return 'hello'<



 

 

现在的问题是,hold会在什么时候调用?

过去我一直以为是每次调用GET函数的时候会调用一遍hold函数
但事实并不是这样的,
事实是,当定义GET函数加载的时候,就会调用一遍hold函数
而且仅仅调用一遍hold,
这时候hold返回的函数就会替代原始的GET函数定义,
所以运行这点python代码,输出结果如下

 

 

 

http://0.0.0.0:8080/
run hlod
in hold func
10.0.2.2:51602 - - [23/Sep/2011 08:04:11] "HTTP/1.1 GET /" - 200 OK
10.0.2.2:51602 - - [23/Sep/2011 08:04:11] "HTTP/1.1 GET /favicon.ico" - 404 Not Found
in hold func
10.0.2.2:51602 - - [23/Sep/2011 08:04:12] "HTTP/1.1 GET /" - 200 OK 
				
				
				

阅读全文 »

Python 的闭包和装饰器(转载)

Part I 原文地址: http://blaag.haard.se/Python-Closures-and-Decorators–Pt–1/ 回想起来,当初我做出了错误的选择,把 Python 的课程削减到了4个小时以至于把装饰器的部分搞砸了,我答应大家我稍后会对闭包和装饰器做一个更好的解说 —— 我是这么打算的。 函数也是对象。实际上,在 Python 中函数是一级对象——也就是说,他们可以像其他对象一样使用而没有什么特别的限制。这给了我们一些有趣的选择,我会由浅到深解释这个问题。 关于函数就是对象的一个最常见的例子就是 C 中的函数指针;将函数传递到其他的将要使用它的函数。为了说明这一点,我们来看看一个重复函数的实现 —— 也就是,一个函数接受另外一个函数以及一个数字当作参数,并且重复调用指定函数指定次数: #A very simple function def greeter(): … print("Hello") … #An implementation of a repeat function def repeat(fn, times): … for i in range(times): … fn() … repeat(greeter, 3) Hello Hello Hello 这种模式在很多情况下都有用 —— 比如向一个排序算法传递比较函数,向一个语法分析器传递一个装饰器函数,通常情况下这些做法可以使一个函数的行为 更专一化 ,或者向已经抽象了工作流的函数传递一个待办的特定部分(比如, sort() 知道怎么排序, compare() 知道怎么比较元素)。 函数也可以在其他函数的内部声明,这给了我们另一个很重要的工具。在一般情况下,这可以用来隐藏实用函数的实现细节: def print_integers(values): … def is_integer(value): … try: … return value == int(value) … except: … return False … for v in values: … if is_integer(v): … print(v) … print_integers([1,2,3,"4", "parrot", 3.14]) 1 2 3 这可能是有用的,但它本身并不算是个强大的工具。相比函数可以当作参数被传递而言,我们可以将它们包装(wrap)在另外的函数中,从而向已经构建好的函数增加新的行为。一个简单的例子是向一个函数增加跟踪输出: def print_call(fn): … def fn_wrap(*args, **args): #take any arguments … print ("Calling %s" % (fn.func_name)) … return fn(*args, **kwargs) #pass any arguments to fn() … return fn_wrap … greeter = print_call(greeter) #wrap greeter repeat(greeter, 3) Calling fn_wrap Hello Calling fn_wrap Hello Calling fn_wrap Hello greeter.func_name 'fn_wrap' 正如你看到的那样,我们可以使用带日志的函数来替换掉现有函数相应的部分,然后调用原来的函数。在例子的最后两行,函数的名字已经反映出了它已经被改变,这个改变可能是我们想要的,也可能不是。如果我们想包装一个函数同时保持它原来的名字,我们可以增加一行 print_call 函数,代码如下: def print_call(fn): … def fn_wrap(*args, **kwargs): #take any arguments … print("Calling %s" % (fn.func_name)) … return fn(*args, **kwargs) #pass any arguments to fn() … fn_wrap.func_name = fn.func_name #Copy the original name … return fn_wrap 因为这是一个很长的话题,我明天会来更新第二部分,我们会讲讲闭包,偏函数(partial),还有(终于到它了)装饰器。 至此,如果这些你之前全部没有接触过,可以先用 print_call 函数作为基础,来创建一个能够在正常调用函数之前先打印出这个函数名字的一个修饰器。 Part II 原文地址: http://blaag.haard.se/Python-Closures-and-Decorators–Pt–2/ 在第一部分中,我们学习了以函数作为参数调用其他的函数,还有嵌套函数,最终我们把一个函数包装在另外的函数中。我们先把第一部分的答案给出: def print_call(fn): … def fn_wrap(*args, **kwargs): … print("Calling %s with arguments: \n\targs: %s\n\tkwargs:%s" %fn.__name__, args, kwargs)) … retval = fn(*args, **kwargs) … print("%s returning '%s'" % (fn.func_name, retval)) … return retval … fn_wrap.func_name = fn.func_name … return fn_wrap … def greeter(greeting, what='world'): … return "%s %s!" % (greeting, what) … greeter = print_call(greeter) greeter("Hi") Calling greeter with arguments: args: ('Hi',) kwargs:{} greeter returning 'Hi world!' 'Hi world!' greeter("Hi", what="Python") Calling greeter with arguments: args: ('Hi',) kwargs:{'what': 'Python'} greeter returning 'Hi Python!' 'Hi Python!' 这稍微有那么点儿用了,但它可以变的更好!你可能听说过或者没有听说过*闭包*,你可能听说过成千上万种闭包定义中的某一种或者某几种 —— 我不会那么挑剔,我只是说闭包就是一个捕捉了(或者关闭)非本地变量(自由变量)的代码块(比如一个函数)。如果你不清楚我在说什么,你可能需要进修一下 CS 的相关课程,但是不要担心 —— 我会给你演示例子。闭包的概念很简单:一个可以引用在函数闭合范围内变量的函数。 比如说,看一下这个代码: a = 0 def get_a(): … return a … get_a() 0 a = 3 get_a ...

阅读全文 »

OOREDIS:一个 Pythonic 的 Redis 库

用Redis的朋友们应该会发现,Redis的很多客户端都只是Redis命令的一个简单包装。 举个例子,在Redis的Python客户端redis-py中,设置一个String键的方法如下: from redis import Redis r = Redis r.set('key_name', 'value') 而要取得一个列表的所有元素,则要使用lrange命令: r.lrange('list', 0, -1) 这种操作方式有几个问题: 1.大量的Redis命令聚在一起,妨碍了对客户端对象的使用。 2.每次操作都要将将key name和命令参数(比如lrange的0和-1)显式地传入方法当中,容易出错。 3.命令之间没有限制,可以互相覆盖而没有错误提示。 比如你可以用set命令覆盖一个Redis列表,Redis本身不会报错。 4.客户端没有利用到语言提供的方便机制。 比如r.lrange('list', 0, -1)在Python中就没有for item in list语句来得直观。 5.Redis只储存字符串值,虽然可以储存整数或浮点数,但每次取出值都要显式类型转换,很不方便。 --- 为了解决以上问题,更好地使用Redis,我用Python写了一个Redis库,基于redis-py,名叫ooredis。 ooredis有以下目标: 1.以Key对象为单位操作Redis的数据结构 在ooredis中,Redis的函数被按类型及作用归为了一个个Python类,每个ooredis类有不同的操作。 比如在ooredis中,将Redis的Hash类函数包裹成了Dict类型,它可以以类似Python内置dict类型的方式,操纵Redis数据。 又比如,Redis的List类函数,在ooredis中被包裹成了List类型,它可以以类似Python内置list类型的方式,操纵Redis数据。 如果ooredis类尝试覆盖不同类型的数据,ooredis将抛出异常。 这样就解决了包括命名空间污染、跨类型覆盖等问题。 2.提供一组Pythonic的API 刚才我们说“以类型Python内置的dict类型的方式来操纵Redis的Hash类型数据“,我们还没详细说明这是什么意思。 比如说,在ooredis中,你可以通过传给Dict类一个key name,之后就可以操纵这个Dict对象,来完成Redis中的各种命令,像这样: form ooredis import * project = Dict('ooredis-project') project['name'] = 'ooredis' project['version'] = 1.0 project['author'] = 'huangz' 以上的语句就相当于执行Redis的命令: redis HSET ooredis name ooredis redis HSET ooredis version 1.0 redis HSET ooredis author huangz 也可以用redis-py来完成上面的任务: r.hset('ooredis-project', 'name', 'ooredis') r.hset('ooredis-project', 'version', 1.0) r.hset('ooredis-project', 'autohr', 'huangz) 可以看到,使用Dict对象比单纯的Redis命令更直观。 又比如在Dict对象中,你可以用Python内置类型set的全部命令:items、keys、values、pop,等等。 project.items() [('name', u'ooredis'), ('version', 1.0), ('author', u'huangz')] 'version' in project True project.pop('name') u'ooredis' 不仅是Dict类,ooredis的所有类都大量使用了Python的魔法方法,致力于让Redis数据的操作更直观、清晰和Pythonic。 3.提供方便的类型转换机制 至于类型问题,ooredis通过使用传入TypeCase的方式,来对Redis数据进行类型转换。 比如如果你需要一个只保存整数对象(int/long)类型的列表,只需要这样做就可: numbers = List('numbers', type_case=IntTypeCase) 如果你需要一个只接受Json对象的字典对象,只需要使用以下语句: json_only_dict = Dict('json_dict', type_case=JsonTypeCase) 其中IntTypeCase和JsonTypeCase都是ooredis默认提供的TypeCase类之一,ooredis总共提供了以下常用TypeCase: GenericTypeCase,接受Python常量值,比如int,long,float,str和unicode。为了世界的和平与正义,传入的字符串值总被转换成unicode类型。 IntTypeCase,接受int和long。 FloatTypeCase,接受浮点数。 StringTypeCase,接受str和unicode类型的值,而且总被转换成unicode。 JsonTypeCase,接受所有可被转换成Json对象的值,比如Python的dict类型。 SerializeTypeCase,使用Pickle的dumps和loads,可以对Python的class进行序列化。 当然,除了以上的TypeCase之外,你也可以很方便地定义自己的TypeCase类,像如下代码: class MyTypeCase: @staticmethod def to_redis(value): pass @staticmethod def to_python(value): pass to_redis将值转换成Redis能接受的类型,to_python则将从Redis取出的数据转回原来的类型。 --- 好的,以上就是关于ooredis的基本介绍了,抱歉因为时间关系我不能写一篇更短的文章。 如果你对ooredis有兴趣,可以访问以下地址,获得更多信息: ooredis的更详细介绍,幻灯: http://bit.ly/rbgn3Z ooredis的项目主页: https://github.com/huangz1990/ooredis ...

阅读全文 »

__init__.py文件的用途

__init__.py 有两个用途 :

1、是表示目录下面的python 程序是module 的一部分

2、module 自身,module 自身以及submodule 的初始化、声明了。

例如:

--- breakfast

|

|- spam.py

|- toast.py

|- jam.py

 

包的结构:

package1/

__init__.py

subPack1/

__init__.py

module_11.py

module_12.py

module_13.py

subPack2/

__init__.py

module_21.py

module_22.py

  ……如果用户 import breakfast.spam 来引入 spam ,这样是不行的,因为在breakfast 目录下面没有 __init__.py 这个文件, 如果在breakfast 目录下面加入 __init__.py 就可以了。

阅读全文 »

python 菜谱(python cookbook) 1.4 字符串对齐

任务:实现字符串对齐:左对齐,居中对齐,或者右对齐 这就是字符串内置函数ljust,rjust,center所能实现的功能。函数类似于S.ljust(width[, fillchar]),默认的fillchar是空格,如果想指定填充字符的话,需要给出指定字符。 x=' hej ' print '|', 'hej'.ljust(20), '|', 'hej'.center(20), 'hej'.rjust(20)

阅读全文 »

PyCon 大会相关资料(视频+PPT)

会议PPT下载: http://cn.pycon.org/2011/schedule 洪强宁-豆瓣的Python应用和创新 http://www.tudou.com/programs/view/fvnGyGXTvLM/ Daniem-Scale web application stack with coro-thread http://www.tudou.com/programs/view/afNO_Yq1kLc/ 沈葳–Python通向未来之路 http://www.tudou.com/programs/view/Dx8LHWMvjps/ 潘俊勇-易度PaaS云开发平台技术内幕 http://www.tudou.com/programs/view/9BfMlTho_1A/ 土豆网黄冬-系统工程师的非专业课 计费与流量管理 http://www.tudou.com/programs/view/kGcDov8GxNM/ 陈正—Introduction_to_SAE_Python http://www.tudou.com/programs/view/iMP1dKMgJYc/ Ryan Ye-Schemaless-data-model-Pycon http://www.tudou.com/programs/view/M8Ku2upwdGg/ 首届中国Python2011大会Q A(1) http://www.tudou.com/programs/view/PXVBJY82JrM/ 李迎辉- Web框架开发思考与实践 http://www.tudou.com/programs/view/7ua4wTEQAac/ 首届中国Python2011大会Q A(2) http://www.tudou.com/programs/view/cWEM79vOYVg/ 赖勇浩-Python 之于 webgame 的应用 http://www.tudou.com/programs/view/PP4K6ZD2r-g/ 王剑锋-OpenERP二次开发 http://www.tudou.com/programs/view/f90a0p3-sQc/ 李俊东-与python一路走来 http://www.tudou.com/programs/view/DAmnmtfwHgQ/ 林君-用tornado搭建实时应用 http://www.tudou.com/programs/view/ATbooIAjpO0/ 王浩飞-openstack_pycon http://www.tudou.com/programs/view/Za52sDDCp-g/ 宋进亮-工程师职业规划探讨 http://www.tudou.com/programs/view/BomiVOnBBe4/ Steven Yang- Workend, where developer meets designer http://www.tudou.com/programs/view/0_VW4SENilQ/ 钟子飞-图形化大规模网络设备 http://www.tudou.com/programs/view/hJD2iyruUqY/ ...

阅读全文 »