注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

@fc_lamp

关注Web应用解决方案MySql/PHP/Python一盏名为"飞川"的灯~

 
 
 

日志

 
 

关于Python中的易错点  

2016-11-10 00:29:48|  分类: Web技术-Python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
源: 关于Python的一些吐槽

不符合预期的函数默认参数

Python函数默认参数中如果使用了mutable对象,那么这个参数是共享的,

def foobar(nums=[]):
  nums.append(1)
  print sum(nums)

>>> foobar()
1
>>> foobar()
2
>>> foobar()
3

这是一个容易产生bug的语言特性,曾经也踩过这个坑。StackOverflow也有关于此的讨论。不少Python Best Practice会提醒我们避开这种使用方式,但如果一开始就符合预期,应该会更好。

不符合直觉的循环中的lambda定义

同样也是一个容易产生bug的特性,

funcs = []
for x in xrange(5):
  funcs.append(lambda: x + 1)
for func in funcs: print func()

上述代码的输出全都是5,lambda中的x被绑定至了最后一次出现的值。因为这种不当使用导致的bug,估计不少人都遇到过。

记不清的de >__getattr__de>, de >__getattribute__de>

这两个函数其中一个是每次属性访问的时候都会被调用、另一个是当对象上没有该属性时被调用。功能很容易理解,但记忆上却很容易混淆,每次记清楚之后一段时间未用,就又搞不清了,只能运行遍代码试试。

原本attr就是attribute的缩写,于是记忆混淆就难免了。Python邮件组里曾经也有过关于这个的讨论。

容易被忽略的','

不止一次遇到过因为赋值语句末尾的逗号导致的类型异常,这确实是很蠢的一个错误,但偏偏不太容易注意到,

foo = 'foo',

上述语句末尾的','会导致foo变成一个tuple,而不是str。有时候真的是不小心或是无意识按到了',',然后运行时就悲剧了。另一方面Python的tuple定义也是有点小混淆的,

t = tuple()  # create tuple
t = ()       # create tuple
t = (1,)     # create tuple
t = 1,       # create tuple
t = (())     # create tuple
t = (1)      # just integer
t = (x for x in xrange(5))  # create generator

()这个操作符在不同使用方式中语义是不同的,是不是有点烦人呢?

可以动态添加属性的函数与不能动态添加属性的容器类(list, dict, set...)

在命令行下执行下列代码,

# no error
def foobar(): pass
foobar.name = 'foobar'

# exception rased, AttributeError: 'dict' object has no attribute 'name'
foobar = {}
foobar.name = 'foobar'

很奇怪为什么Python中的函数可以直接进行类似的动态设置属性操作,而常见的容器类们都不可以。函数属性这一条还是PEP232中通过的。StackOverflow也有不错的讨论。

这个特性的功能不难理解,但为啥别的一些类型不可以。只是单纯的对一致性产生了怀疑。

可以被修改的True、False

试试下面这小段代码,

True, False = False, True
if 1 > 0 is True:
  print 'correct'
else:
  print 'wrong'

这个问题在Python 3中得到了解决,True/False/None已经变成了保留字,但在2.x中还是依然如此,希望没人在正式代码中来这么一下。

不被推荐使用的for..else, while..else

为什么Python中加入了for..else、while..else,StackOverflow上这个问题有不少有价值的讨论。曾经尝试过在代码中使用,但一段时间之后自己就忘记了这个else到底是什么时候会进入触发。

这两个else所期望实现的功能是很明确的,但这个功能却用了else来进行标识,这与if..else中的else起始含义是不一样的,同样的名字不一样的含义,自然就是不好记忆的。

''、""、''''''、""""""

Python字符串定义可以使用这几种符号,

foobar = 'foobar'
foobar = "foobar"
foobar = '''foobar'''
foobar = """foobar"""
foobar = 'foo"bar'
foobar = "foo'bar"
foobar = """foo'''bar"""
foobar = '''foo"""bar'''

对单引号、双引号都支持,个人理解是为了方便。这两组对应的使用方式是等价的,但PEP257中竟然说为了保持一致docstring推荐使用"""""",这又是为什么?真有保持一致的需要,就不应该对单引号、双引号都支持。否则真是平添了StackOverflow上的这些讨论。

空格与Tab

Python的缩进像大多数语言那样支持空格与Tab,但Python与常用语言的差异也在于Python中的缩进是有意义的,不匹配的缩进会导致语法错误。在代码中混用空格、Tab是一件危险的行为。于是不同的项目可能约定不同的缩进方式,于是也有了网上很多无谓的讨论

如果Python的缩进不会导致语法错误,那么不对此进行约定是很正常的。可偏偏缩进就有可能导致错误,这种时候语言应该对此进行强制限定才是。

其它

一些众所周知的问题这里就没有必要再记录了。Python最大的问题可能还是Python2、Python3的分裂。可惜没有机会在正式项目中使用Python3,不然倒也想实际对比下两者的差异与改进。

最后还是来看下The Zen of Python,

import python
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

与其说是The Zen of Python不如说是The Zen of Programming,可惜其中一些条目是很难一如既往的保持的。

比如,

Special cases aren't special enough to break the rules.

不少语言特性的引入就是为了解决一些并不常见的情况。但解决这些问题真的有必要直接增加语言特性吗?

再比如,

In the face of ambiguity, refuse the temptation to guess.

混淆的特性、混淆的缩写命名..

再再比如,

There should be one-- and preferably only one --obvious way to do it.

这一条感觉太太难以实现了。看看网上的各种讨论就知道,这一条大部分时候也只是停留在纸面上。

总结

写了那么多,主要还是希望不论Python还是自己实现的代码尽量符合这里定义的“Zen”。一些问题估计也是历史遗留问题,为了保持兼容,不得不保持现状。

另外也可以发现即便Python有一些缺点,但它无疑是一门成功的语言,而且依然还处在发展期。这足以说明在现实中,是否能够获得的成功,不在于缺点如何,而在于优点如何。让优点足够优秀,那么就有可能从竞争中胜出。

  评论这张
 
阅读(77)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017