小心Python的“坑”(持续更新)

本文总结了使用Python过程中遇到的一些问题,包括:1)字典添加元素的方式;2)单元素tuple的创建误区,以及由此引发的参数传递错误;3)装饰器中使用functools.wrap的重要性;4)lambda表达式中变量作用域的理解。通过这些实例,提醒开发者在编写Python代码时需要注意的细节。
Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

用了Python也有三个多月了,在为这个语言如此简单易用而赞叹的同时,也碰到了不少“坑”的地方,开个博文总结下:


1. list添加一个元素很容易,像下面这样:

l = []
l.append('hello')

dict怎么添加?没有insert,也没有append,怎么办?

>>> d = {}
>>> d['key'] = 'value'
>>> d
{'key': 'value'}
>>> d[3] = 4
>>> d
{3: 4, 'key': 'value'}

看出来了吗?直接写一个K-V组合,就自动添加进来了

别告诉我你不知道怎么删除,del


2.  先看这个

>>> t = ()
>>> type(t)
<type 'tuple'>
>>> t = (1)
>>> type(t)
<type 'int'>
>>> t = (1, 2)
>>> type(t)
<type 'tuple'>

有没有觉得哪里不对劲?为什么中间那个是int类型,不是tuple了?我承认我当时没看清楚文档,所以碰到了这个问题:

import threading

def print_arg(arg):
    print arg

str = 'test-string'
thr = threading.Thread(target=print_arg, args=(str))
thr.start()
thr.join()
print 'threading done'

例子很简单,创建一个线程,线程的任务就是打印传入的参数,由于传入的参数要求是tuple,所以我当时想当然的用括号包裹了一下,然后运行。

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 504, in run
    self.__target(*self.__args, **self.__kwargs)
TypeError: print_arg() takes exactly 1 argument (11 given)

threading done

咦?为什么我明明只传入一个参数,却提示我传入了11个?

仔细翻看原文档,才注意到,构建tuple是靠逗号,而不是圆括号,我搜索了Python为什么1个元素的tuple不也这么写,他们解释是括号是用来组合的,比如计算的时候,括号的优先级最高(源链接找不到了)。

那我怎么构建一个元素的tuple?很简单,只是不优雅

>>> t = (1,)
>>> type(t)
<type 'tuple'>
>>> t = 1,
>>> type(t)
<type 'tuple'>

tuple的关键是那个逗号,而不是括号,由于tuple的输出格式都是用圆括号括起来,所以时间久了,就自然而然认为圆括号是tuple的核心。

所以上面那个例子,只要在括号里面的str后面,加上一个逗号,就可以得到需要的结果了。

More:11个参数是怎么回事?因为在Python里面,string和tuple有个共同特性,都是iterable的,所以传入的str被拆解成11个字符的tuple,这也是为什么提示传入了11个参数


3. decorator使用注意

写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring,例如:

from functools import wraps
def my_decorator(f):
    @wraps(f)    # 最好加上这一句
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print 'Called example function'

print example.__name__, example.__doc__

程序运行之后的输出是

example Docstring
如果去掉了 @wraps(f) 这一行,得到的结果会是这样的

wrapper None


4. lambda表达式中使用注意:

>>> x = 10
>>> a = lambda y: x+y
>>> x = 20
>>> b = lambda y: x+y
>>> a(10)
30
>>> b(10)
30

在这里a(10)和b(10)输出结果相同的原因是:x 在lambda表达式中是一个自由变量,在运行时确定,而不是定义的时候(the value of x used in the lambda expression is a free variable that gets bound at runtime, not definition time),如果需要保存 x 的值,需要这么使用:

>>> x = 10
>>> a = lambda y, x=x: x+y
>>> x = 20
>>> b = lambda y, x=x: x+y
>>> a(10)
20
>>> b(10)
30

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

【为什么学爬虫?】        1、爬虫入手容易,但是深入较难,如何写出高效率的爬虫,如何写出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这门课程,你都能学到!        2、如果是作为一个其他行业的开发者,比如app开发,web开发,学习爬虫能让你加强对技术的认知,能够开发出更加安全的软件和网站 【课程设计】 一个完整的爬虫程序,无论大小,总体来说可以分成三个步骤,分别是:网络请求:模拟浏览器的行为从网上抓取数据。数据解析:将请求下来的数据进行过滤,提取我们想要的数据。数据存储:将提取到的数据存储到硬盘或者内存中。比如用mysql数据库或者redis等。那么本课程也是按照这几个步骤循序渐进的进行讲解,带领学生完整的掌握每个步骤的技术。另外,因为爬虫的多样性,在爬取的过程中可能会发生被反爬、效率低下等。因此我们又增加了两个章节用来提高爬虫程序的灵活性,分别是:爬虫进阶:包括IP代理,多线程爬虫,图形验证码识别、JS加密解密、动态网页爬虫、字体反爬识别等。Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。通过爬虫进阶的知识点我们能应付大量的反爬网站,而Scrapy框架作为一个专业的爬虫框架,使用他可以快速提高我们编写爬虫程序的效率和速度。另外如果一台机器不能满足你的需求,我们可以用分布式爬虫让多台机器帮助你快速爬取数据。 从基础爬虫到商业化应用爬虫,本套课程满足您的所有需求!【课程服务】 专属付费社群+定期答疑
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值