python导入自定义模块 文件A下a模块 可以继承另一个模块b的类吗?

运算符是可以操纵操作数值的结构。如下一个表达式:10 + 20 = 30。这里,10和20称为操作数,+则被称为运算符。
运算符类型Python语言支持以下类型的运算符 -
1.算术运算符2.比较(关系)运算符3.赋值运算符4.逻辑运算符5.按位运算符6.成员运算符7.身份运算符
下面让我们依次来看看所有的运算符。
1.算术运算符假设变量a的值是10,变量b的值是21,则 -
加法运算,将运算符两边的操作数增加。
a + b = 31
减法运算,将运算符左边的操作数减去右边的操作数。
a – b = -11
乘法运算,将运算符两边的操作数相乘
a * b = 210
除法运算,用右操作数除左操作数
b / a = 2.1
模运算,用右操作数除数左操作数并返回余数
对运算符进行指数(幂)计算
a ** b,表示10的21次幂
地板除 - 操作数的除法,其结果是删除小数点后的商数。 但如果其中一个操作数为负数,则结果将被保留,即从零(向负无穷大)舍去
9//2 = 4 , 9.0//2.0 = 4.0, -11//3 = -4, -11.0//3 = -4.0
有关算术运算符的示例代码,请参考::
2.比较(关系)运算符比较(关系)运算符比较它们两边的值,并确定它们之间的关系。它们也称为关系运算符。假设变量a的值10,变量b的值是20,则 -
如果两个操作数的值相等,则条件为真。
(a == b)求值结果为 false
如果两个操作数的值不相等,则条件为真。
(a != b)求值结果为 true
如果左操作数的值大于右操作数的值,则条件成为真。
(a & b)求值结果为 false
如果左操作数的值小于右操作数的值,则条件成为真。
(a & b)求值结果为 true
如果左操作数的值大于或等于右操作数的值,则条件成为真。
(a &= b)求值结果为 false
如果左操作数的值小于或等于右操作数的值,则条件成为真。
(a &= b)求值结果为 true
有关比较(关系)运算符的示例代码,请参考:
3.赋值运算符假设变量a的值10,变量b的值是20,则 -
将右侧操作数的值分配给左侧操作数
c = a + b表示将a + b的值分配给c
将右操作数相加到左操作数,并将结果分配给左操作数
c + = a等价于c = c + a
从左操作数中减去右操作数,并将结果分配给左操作数
c -= a 等价于 c = c - a
将右操作数与左操作数相乘,并将结果分配给左操作数
c *= a 等价于 c = c * a
将左操作数除以右操作数,并将结果分配给左操作数
c /= a 等价于 c = c / a
将左操作数除以右操作数的模数,并将结果分配给左操作数
c %= a 等价于 c = c % a
执行指数(幂)计算,并将值分配给左操作数
c **= a 等价于 c = c ** a
运算符执行地板除运算,并将值分配给左操作数
c //= a 等价于 c = c // a
有关赋值运算符的示例代码,请参考:
4.逻辑运算符Python语言支持以下逻辑运算符。假设变量a的值为True,变量b的值为False,那么 -
如果两个操作数都为真,则条件成立。
(a and b)的结果为False
如果两个操作数中的任何一个非零,则条件成为真。
(a or b)的结果为True
用于反转操作数的逻辑状态。
not(a and b) 的结果为True。
有关逻辑运算符的示例代码,请参考:
5.按位运算符按位运算符执行逐位运算。 假设变量a = 60; 和变量b = 13; 现在以二进制格式,它们将如下 -
-----------------
Python的内置函数bin()可用于获取整数的二进制表示形式。
以下是Python语言支持位运算操作符 -
如果它存在于两个操作数中,则操作符复制位到结果中
(a & b) 结果表示为
如果它存在于任一操作数,则复制位。
b) = 61 结果表示为
二进制异或。如果它是一个操作数集合,但不是同时是两个操作数则将复制位。
(a ^ b) = 49 (结果表示为 )
二进制补码,它是一元的,具有“翻转”的效果。
(~a ) = -61有符号的二进制数,表示为的补码形式。
二进制左移,左操作数的值由右操作数指定的位数左移。
a && 2 = 240 (结果表示为 )
二进制右移,左操作数的值由右操作数指定的位数右移。
a && 2 = 15(结果表示为)
有关按位运算符的示例代码,请参考:
6.成员运算符Python成员运算符测试给定值是否为序列中的成员,例如字符串,列表或元组。 有两个成员运算符,如下所述 -
如果在指定的序列中找到一个变量的值,则返回true,否则返回false。
如果在指定序列中找不到变量的值,则返回true,否则返回false。
有关成员运算符的示例代码,请参考:
7.身份运算符身份运算符比较两个对象的内存位置。常用的有两个身份运算符,如下所述 -
如果运算符任一侧的变量指向相同的对象,则返回True,否则返回False。
如果运算符任一侧的变量指向相同的对象,则返回True,否则返回False。
有关身份运算符的示例代码,请参考:
8. 运算符优先级下表列出了从最高优先级到最低优先级的所有运算符,如下所示 -
指数(次幂)运算
补码,一元加减(最后两个的方法名称是+@和-@)
乘法,除法,模数和地板除
向右和向左位移
按位异或和常规的“OR”
比较运算符
等于运算符
= %= /= //= -= += *= **=
赋值运算符
身份运算符
成员运算符
not or and
逻辑运算符
有关运算符优先级的示例代码,请参考:
易百教程移动端:请扫描本页面底部(右侧)二维码并关注微信公众号,回复:"教程" 选择相关教程阅读或直接访问:http://m.yiibai.com 。
上一篇:下一篇:
加QQ群啦,易百教程官方技术学习群
注意:建议每个人选自己的技术方向加群,同一个QQ最多限加3个群。
Java技术群:
(人数:2000,等级:LV5,免费:否)
MySQL/SQL群:
(人数:2000,等级:LV5,免费:否)
大数据开发群:
(人数:2000,等级:LV5,免费:否)
Python技术群:
(人数:2000,等级:LV5,免费:否)
人工智能深度学习:
(人数:2000,等级:LV5,免费:否)
测试工程师(新群):
(人数:1000,等级:LV1,免费:是)
前端技术群(新群):
(人数:1000,等级:LV1,免费:是)
C/C++技术(新群):
(人数:1000,等级:LV1,免费:是)
Node.js技术(新群):
(人数:1000,等级:LV1,免费:是)
PostgreSQL数据库(新群):
(人数:1000,等级:LV1,免费:否)
Linux技术:
(人数:2000,等级:LV5,免费:否)
PHP开发者:
(人数:2000,等级:LV5,免费:是)
Oracle数据库:
(人数:2000,等级:LV5,免费:是)
C#/ASP.Net开发者:
(人数:2000,等级:LV5,免费:是)
数据分析师:
(人数:1000,等级:LV1,免费:是)R语言,Matlab语言等技术温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
当执行#1后,sys.modules会同时存在PA、PA.wave两个模块,此时可以调用PA.wave的任何类或函数了。但不能调用PA.PB1(2)下的任何模块。当前Local中有了PA名字。 当执行#2后,只是将PA.PB1载入内存,sys.modules中会有PA、PA.wave、PA.PB1三个模块,但是PA.PB1下的任何模块都没有自动载入内存,此时如果直接执行PA.PB1.pb1_m.getName()则会出错,因为PA.PB1中并没有pb1_m。当前Local中还是只有PA名字,并没有PA.PB1名字。 当执行#3后,会将PA.PB1下的pb1_m载入内存,sys.modules中会有PA、PA.wave、PA.PB1、PA.PB1.pb1_m四个模块,此时可以执行PA.PB1.pb1_m.getName()了。由于使用了as,当前Local中除了PA名字,另外添加了m1作为PA.PB1.pb1_m的别名。 当执行#4后,会将PA.PB2、PA.PB2.pb2_m载入内存,sys.modules中会有PA、PA.wave、PA.PB1、PA.PB1.pb1_m、PA.PB2、PA.PB2.pb2_m六个模块。当前Local中还是只有PA、m1。 下面的#5,#6,#7都是可以正确运行的。注意的是:如果PA.PB2.pb2_m想导入PA.PB1.pb1_m、PA.wave是可以直接成功的。最好是采用明确的导入路径,对于./..相对导入路径还是不推荐用。
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'python标准import',
blogAbstract:' 标准ImportPython中所有加载到内存的模块都放在sys.modules。当import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用import的模块的Local名字空间中。如果没有加载则从sys.path目录中按照模块名称查找模块文件,模块文件可以是py、pyc、pyd,找到后将模块载入内存,并加入到sys.modules中,并将名称导入到当前的Local名字空间。',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:5,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}看到一个python程序中a.py里import b.py,在b.py里import a.py_百度知道
看到一个python程序中a.py里import b.py,在b.py里import a.py
这样不会死循环import么?
我有更好的答案
python会形成一个已经import的模块的列表,每个模块只会import一次,再次import是会pass的,不会死循环。
采纳率:85%
这个和C++的头文件一样啊,想一下,A说B我朋友,A可以用B的东西,B说A是我朋友,我可以用A的东西,这样没有循环引用,只是告诉对方我们了解对方而已。。。
为您推荐:
其他类似问题
python的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。玩蛇网提供最新Python编程技术信息以及Python资源下载!
您现在的位置:
Python 集合set()添加删除、交集、并集、集合操作详解
在Python set是的一种集合类型,它有可变集合(set())和不可变集合(frozenset)两种。创建集合set、集合set添加、集合删除、交集、并集、差集的操作都是非常实用的方法。
玩蛇网python之家提示: 推荐在下编写python程序,会养成一个非常好的编码习惯。
创建集合set
python set类是在python的sets中,大家现在使用的python2.7.x中,不需要导入sets模块可以直接创建集合。
&&&set('boy')
set(['y', 'b', 'o'])
集合添加、删除
python 集合的添加有两种常用方法,分别是add和update。
集合add方法:是把要传入的元素做为一个整个添加到集合中,例如:
&&& a = set('boy')
&&& a.add('python')
set(['y', 'python', 'b', 'o'])
# 在学习python的朋友们,强烈推荐加入。
集合update方法:是把要传入的元素拆分,做为个体传入到集合中,例如:
&&& a = set('boy')
&&& a.update('python')
set(['b', 'h', 'o', 'n', 'p', 't', 'y'])
集合删除操作方法:remove
set(['y', 'python', 'b', 'o'])
&&& a.remove('python')
set(['y', 'b', 'o'])
python set() 集合操作符号、数学符号
集合的交集、合集(并集)、差集,了解python集合set与的这些非常好用的功能前,要先了解一些集合操作符号
简单的演示下差集、交集和合集的概念:
可变集合python set是www.iplaypy.com玩蛇网python学习交流平台,初期python学习中比较能接触到的。像、、这类可迭代的对像都可以做为集合的参数。set集合是无序的,不能通过索引和切片来做一些操作。
浏览这篇文章的网友,正在看:
更多推荐页面:
,,,,,,,,,,,
玩蛇网文章,转载请注明出处和文章网址:http://www.iplaypy.com/jichu/set.html
玩蛇网Python互助QQ群,欢迎加入-->:
修订日期:日 - 23时49分46秒
发布自玩蛇网
我要分享到:
PYTHON基础入门必备教程
Must Know PYTHON Tutorials
PYTHON进阶提高必备教程
Must Know PYTHON Modules
最新内容 NEWS
图文精华 RECOMMEND
热点文章 HOT
玩蛇网Python QQ群 QQ Groups
o 玩蛇网Python_01群
o 玩蛇网Python_02群
o 玩蛇网Python_03群
o 玩蛇网Python_04群
o 玩蛇网Python_05群
Navigation
玩蛇网Python之家,简称玩蛇网,是一个致力于推广python编程技术、程序源码资源的个人网站。站长 斯巴达 是一位 长期关注 软件、互联网、服务器与各种开发技术的Python爱好者,建立本站旨在与更多朋友分享派森编程的乐趣!
本站团队成员: 斯巴达
欢迎加入团队...Python程序员的10个常见错误 - 文章 - 伯乐在线
& Python程序员的10个常见错误
关于Python
是一门解释性的,面向对象的,并具有动态语义的高级编程语言。它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发()中颇为受欢迎,同时Python还能作为脚本语言或者胶水语言讲现成的组件或者服务结合起来。Python支持模块(modules)和包(packages),所以也鼓励程序的模块化以及代码重用。
Python简单、易学的语法可能会误导一些Python程序员(特别是那些刚接触这门语言的人们),可能会忽略某些细微之处和这门语言的强大之处。
考虑到这点,本文列出了“十大”甚至是高级的Python程序员都可能犯的,却又不容易发现的细微错误。(注意:本文是针对比《》稍微高级一点读者,对于更加新手一点的Python程序员,有兴趣可以读一读那篇文章)
常见错误1:在函数参数中乱用表达式作为默认值
Python允许给一个函数的某个参数设置默认值以使该参数成为一个可选参数。尽管这是这门语言很棒的一个功能,但是这当这个默认值是可变对象()时,那就有些麻烦了。例如,看下面这个Python函数定义:
&&& def foo(bar=[]):
# bar是可选参数,如果没有指明的话,默认值是[]
bar.append("baz")
# 但是这行可是有问题的,走着瞧…
return bar
&&& def foo(bar=[]):&&&&&&&&# bar是可选参数,如果没有指明的话,默认值是[]...&&&&bar.append("baz")&&&&# 但是这行可是有问题的,走着瞧…...&&&&return bar
人们常犯的一个错误是认为每次调用这个函数时不给这个可选参数赋值的话,它总是会被赋予这个默认表达式的值。例如,在上面的代码中,程序员可能会认为重复调用函数foo() (不传参数bar给这个函数),这个函数会总是返回‘baz’,因为我们假定认为每次调用foo()的时候(不传bar),参数bar会被置为[](即,一个空的列表)。
那么我们来看看这么做的时候究竟会发生什么:
["baz", "baz"]
["baz", "baz", "baz"]
&&& foo()["baz"]&&& foo()["baz", "baz"]&&& foo()["baz", "baz", "baz"]
嗯?为什么每次调用foo()的时候,这个函数总是在一个已经存在的列表后面添加我们的默认值“baz”,而不是每次都创建一个新的列表?
答案是一个函数参数的默认值,仅仅在该函数定义的时候,被赋值一次。如此,只有当函数foo()第一次被定义的时候,才讲参数bar的默认值初始化到它的默认值(即一个空的列表)。当调用foo()的时候(不给参数bar),会继续使用bar最早初始化时的那个列表。
由此,可以有如下的解决办法:
&&& def foo(bar=None):
if bar is None:
# 或者用 if not bar:
bar.append("baz")
return bar
123456789101112
&&& def foo(bar=None):...&&&&if bar is None:
# 或者用 if not bar:...&&&&&&&&bar = []...&&&&bar.append("baz")...&&&&return bar...&&& foo()["baz"]&&& foo()["baz"]&&& foo()["baz"]
常见错误2:不正确的使用类变量
看下面一个例子:
&&& class A(object):
&&& class B(A):
&&& class C(A):
&&& print A.x, B.x, C.x
1234567891011
&&& class A(object):...&&&& x = 1...&&& class B(A):...&&&& pass...&&& class C(A):...&&&& pass...&&& print A.x, B.x, C.x1 1 1
看起来没有问题。
&&& B.x = 2
&&& print A.x, B.x, C.x
&&& B.x = 2&&& print A.x, B.x, C.x1 2 1
嗯哈,还是和预想的一样。
&&& A.x = 3
&&& print A.x, B.x, C.x
&&& A.x = 3&&& print A.x, B.x, C.x3 2 3
我了个去。只是改变了A.x,为啥C.x也变了?
在Python里,类变量通常在内部被当做字典来处理并遵循通常所说的方法解析顺序()。因此在上面的代码中,因为属性x在类C中找不到,因此它会往上去它的基类中查找(在上面的例子中只有A这个类,当然Python是支持多重继承(multiple inheritance)的)。换句话说,C没有它自己独立于A的属性x。因此对C.x的引用实际上是对A.x的引用。(B.x不是对A.x的引用是因为在第二步里B.x=2将B.x引用到了2这个对象上,倘若没有如此,B.x仍然是引用到A.x上的。——译者注)
常见错误3:在异常处理时错误的使用参数
假设你有如下的代码:
l = ["a", "b"]
... except ValueError, IndexError:
# 想捕捉两个异常
Traceback (most recent call last):
File "&stdin&", line 3, in &module&
IndexError: list index out of range
&&& try:...&&&& l = ["a", "b"]...&&&& int(l[2])... except ValueError, IndexError:&&# 想捕捉两个异常...&&&& pass...Traceback (most recent call last):&&File "&stdin&", line 3, in &module&IndexError: list index out of range
这里的问题在于except语句不会像这样去接受一系列的异常。并且,在Python 2.x里面,语法except Exception, e是用来将异常和这个可选的参数绑定起来(即这里的e),以用来在后面查看的。因此,在上面的代码中,IndexError异常不会被except语句捕捉到;而最终ValueError这个异常被绑定在了一个叫做IndexError的参数上。
在except语句中捕捉多个异常的正确做法是将所有想要捕捉的异常放在一个元组()里并作为第一个参数给except语句。并且,为移植性考虑,使用as关键字,因为Python 2和Python 3都支持这样的语法,例如:
l = ["a", "b"]
... except (ValueError, IndexError) as e:
&&& try:...&&&& l = ["a", "b"]...&&&& int(l[2])... except (ValueError, IndexError) as e:&&...&&&& pass...&&&
常见错误4:误解Python作用域的规则
Python的作用域解析是基于叫做(Local(本地),Enclosing(封闭),Global(全局),Built-in(内置))的规则进行操作的。这看起来很直观,对吧?事实上,在Python中这有一些细微的地方很容易出错。看这个例子:
&&& x = 10
&&& def foo():
Traceback (most recent call last):
File "&stdin&", line 1, in &module&
File "&stdin&", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment
12345678910
&&& x = 10&&& def foo():...&&&& x += 1...&&&& print x...&&& foo()Traceback (most recent call last):&&File "&stdin&", line 1, in &module&&&File "&stdin&", line 2, in fooUnboundLocalError: local variable 'x' referenced before assignment
这是怎么回事?
这是因为,在一个作用域里面给一个变量赋值的时候,Python自动认为这个变量是这个作用域的本地变量,并屏蔽作用域外的同名的变量。
很多时候可能在一个函数里添加一个赋值的语句会让你从前本来工作的代码得到一个UnboundLocalError。(感兴趣的话可以读一读文章。)
在使用列表()的时候,这种情况尤为突出。看下面这个例子:
&&& lst = [1, 2, 3]
&&& def foo1():
lst.append(5)
# 这没有问题...
&&& foo1()
[1, 2, 3, 5]
&&& lst = [1, 2, 3]
&&& def foo2():
lst += [5]
# ... 这就有问题了!
&&& foo2()
Traceback (most recent call last):
File "&stdin&", line 1, in &module&
File "&stdin&", line 2, in foo
UnboundLocalError: local variable 'lst' referenced before assignment
1234567891011121314151617
&&& lst = [1, 2, 3]&&& def foo1():...&&&& lst.append(5)&& # 这没有问题......&&& foo1()&&& lst[1, 2, 3, 5]&&&& lst = [1, 2, 3]&&& def foo2():...&&&& lst += [5]&&&&&&# ... 这就有问题了!...&&& foo2()Traceback (most recent call last):&&File "&stdin&", line 1, in &module&&&File "&stdin&", line 2, in fooUnboundLocalError: local variable 'lst' referenced before assignment
嗯?为什么foo2有问题,而foo1没有问题?
答案和上一个例子一样,但是更加不易察觉。foo1并没有给lst赋值,但是foo2尝试给lst赋值。注意lst+=[5]只是lst=lst+[5]的简写,由此可以看到我们尝试给lst赋值(因此Python假设作用域为本地)。但是,这个要赋给lst的值是基于lst本身的(这里的作用域仍然是本地),而lst却没有被定义,这就出错了。
常见错误5:在遍历列表的同时又在修改这个列表
下面这个例子中的代码应该比较明显了:
&&& odd = lambda x : bool(x % 2)
&&& numbers = [n for n in range(10)]
&&& for i in range(len(numbers)):
if odd(numbers[i]):
del numbers[i]
# 这不对的:在遍历列表时删掉列表的元素。
Traceback (most recent call last):
File "&stdin&", line 2, in &module&
IndexError: list index out of range
&&& odd = lambda x : bool(x % 2)&&& numbers = [n for n in range(10)]&&& for i in range(len(numbers)):...&&&& if odd(numbers[i]):...&&&&&&&& del numbers[i]&&# 这不对的:在遍历列表时删掉列表的元素。...Traceback (most recent call last):&& &&File "&stdin&", line 2, in &module&IndexError: list index out of range
遍历一个列表或者数组的同时又删除里面的元素,对任何有经验的软件开发人员来说这是个很明显的错误。但是像上面的例子那样明显的错误,即使有经验的程序员也可能不经意间在更加复杂的程序中不小心犯错。
所幸,Python集成了一些优雅的编程范式,如果使用得当,可以写出相当简化和精简的代码。一个附加的好处是更简单的代码更不容易遇到这种“不小心在遍历列表时删掉列表元素”的bug。例如列表推导式()就提供了这样的范式。再者,列表推导式在避免这样的问题上特别有用,接下来这个对上面的代码的重新实现就相当完美:
&&& odd = lambda x : bool(x % 2)
&&& numbers = [n for n in range(10)]
&&& numbers[:] = [n for n in numbers if not odd(n)]
# 啊,这多优美
&&& numbers
[0, 2, 4, 6, 8]
&&& odd = lambda x : bool(x % 2)&&& numbers = [n for n in range(10)]&&& numbers[:] = [n for n in numbers if not odd(n)]&&# 啊,这多优美&&& numbers[0, 2, 4, 6, 8]
常见错误6:搞不清楚在闭包(closures)中Python是怎样绑定变量的
看这个例子:
&&& def create_multipliers():
return [lambda x : i * x for i in range(5)]
&&& for multiplier in create_multipliers():
print multiplier(2)
&&& def create_multipliers():...&&&& return [lambda x : i * x for i in range(5)]&&& for multiplier in create_multipliers():...&&&& print multiplier(2)...
期望得到下面的输出:
但是实际上得到的是:
这是由于Python的后期绑定(late binding)机制导致的,这是指在闭包中使用的变量的值,是在内层函数被调用的时候查找的。因此在上面的代码中,当任一返回函数被调用的时候,i的值是在它被调用时的周围作用域中查找(到那时,循环已经结束了,所以i已经被赋予了它最终的值4)。
解决的办法比较巧妙:
&&& def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
&&& for multiplier in create_multipliers():
print multiplier(2)
1234567891011
&&& def create_multipliers():...&&&& return [lambda x, i=i : i * x for i in range(5)]...&&& for multiplier in create_multipliers():...&&&& print multiplier(2)...02468
这下对了!这里利用了默认参数去产生匿名函数以达到期望的效果。有人会说这很优美,有人会说这很微妙,也有人会觉得反感。但是如果你是一名Python程序员,重要的是能理解任何的情况。
常见错误7:循环加载模块
假设你有两个文件,a.py和b.py,在这两个文件中互相加载对方,例如:
在a.py中:
return b.x
import bdef f():&&&&return b.xprint f()
在b.py中:
print a.f()
import ax = 1def g():&&&&print a.f()
首先,我们试着加载a.py:
&&& import a
&&& import a1
没有问题。也许让人吃惊,毕竟有个感觉应该是问题的循环加载在这儿。
事实上在Python中仅仅是表面上的出现循环加载并不是什么问题。如果一个模块以及被加载了,Python不会傻到再去重新加载一遍。但是,当每个模块都想要互相访问定义在对方里的函数或者变量时,问题就来了。
让我们再回到之前的例子,当我们加载a.py时,它再加载b.py不会有问题,因为在加载b.py时,它并不需要访问a.py的任何东西,而在b.py中唯一的引用就是调用a.f()。但是这个调用是在函数g()中完成的,并且a.py或者b.py中没有人调用g(),所以这会儿心情还是美丽的。
但是当我们试图加载b.py时(之前没有加载a.py),会发生什么呢:
&&& import b
Traceback (most recent call last):
File "&stdin&", line 1, in &module&
File "b.py", line 1, in &module&
File "a.py", line 6, in &module&
File "a.py", line 4, in f
return b.x
AttributeError: 'module' object has no attribute 'x'
12345678910
&&& import bTraceback (most recent call last):&& &&File "&stdin&", line 1, in &module&&& &&File "b.py", line 1, in &module&&&&&import a&& &&File "a.py", line 6, in &module& print f()&& &&File "a.py", line 4, in f return b.xAttributeError: 'module' object has no attribute 'x'
恭喜你,出错了。这里问题出在加载b.py的过程中,Python试图加载a.py,并且在a.py中需要调用到f(),而函数f()又要访问到b.x,但是这个时候b.x却还没有被定义。这就产生了AttributeError异常。
解决的方案可以做一点细微的改动。改一下b.py,使得它在g()里面加载a.py:
import a # 只有当g()被调用的时候才加载
print a.f()
x = 1def g():&&&&import a # 只有当g()被调用的时候才加载&&&&print a.f()
这会儿当我们加载b.py的时候,一切安好:
&&& import b
1 # 第一次输出,因为模块a在最后调用了‘print f()’
1 # 第二次输出,这是我们调用g()
&&& import b&&& b.g()1 # 第一次输出,因为模块a在最后调用了‘print f()’1 # 第二次输出,这是我们调用g()
常见错误8:与Python标准库模块命名冲突
Python的一个优秀的地方在于它提供了丰富的库模块。但是这样的结果是,如果你不下意识的避免,很容易你会遇到你自己的模块的名字与某个随Python附带的标准库的名字冲突的情况(比如,你的代码中可能有一个叫做email.py的模块,它就会与标准库中同名的模块冲突)。
这会导致一些很粗糙的问题,例如当你想加载某个库,这个库需要加载Python标准库里的某个模块,结果呢,因为你有一个与标准库里的模块同名的模块,这个包错误的将你的模块加载了进去,而不是加载Python标准库里的那个模块。这样一来就会有麻烦了。
所以在给模块起名字的时候要小心了,得避免与Python标准库中的模块重名。相比起你提交一个“”去向上要求改一个标准库里包的名字,并得到批准来说,你把自己的那个模块重新改个名字要简单得多。
常见错误9:不能区分Python 2和Python 3
看下面这个文件foo.py:
import sys
def bar(i):
if i == 1:
raise KeyError(1)
if i == 2:
raise ValueError(2)
def bad():
bar(int(sys.argv[1]))
except KeyError as e:
print('key error')
except ValueError as e:
print('value error')
12345678910111213141516171819
import sys&def bar(i):&&&&if i == 1:&&&&&&&&raise KeyError(1)&&&&if i == 2:&&&&&&&&raise ValueError(2)&def bad():&&&&e = None&&&&try:&&&&&&&&bar(int(sys.argv[1]))&&&&except KeyError as e:&&&&&&&&print('key error')&&&&except ValueError as e:&&&&&&&&print('value error')&&&&print(e)&bad()
在Python 2里,运行起来没有问题:
$ python foo.py 1
$ python foo.py 2
value error
$ python foo.py 1key error1$ python foo.py 2value error2
但是如果拿到Python 3上面玩玩:
$ python3 foo.py 1
Traceback (most recent call last):
File &foo.py&, line 19, in &module&
File &foo.py&, line 17, in bad
UnboundLocalError: local variable 'e' referenced before assignment
$ python3 foo.py 1key errorTraceback (most recent call last):&&File "foo.py", line 19, in <module>&&&&bad()&&File "foo.py", line 17, in bad&&&&print(e)UnboundLocalError: local variable 'e' referenced before assignment
这是怎么回事?“问题”在于,在Python 3里,在except块的作用域以外,异常对象(exception object)是不能被访问的。(原因在于,如果不这样的话,Python会在内存的堆栈里保持一个引用链直到Python的垃圾处理将这些引用从内存中清除掉。更多的技术细节可以参考。)
避免这样的问题可以这样做:保持在execpt块作用域以外对异常对象的引用,这样是可以访问的。下面是用这个办法对之前的例子做的改动,这样在Python 2和Python 3里面都运行都没有问题。
import sys
def bar(i):
if i == 1:
raise KeyError(1)
if i == 2:
raise ValueError(2)
def good():
exception = None
bar(int(sys.argv[1]))
except KeyError as e:
exception = e
print('key error')
except ValueError as e:
exception = e
print('value error')
print(exception)
123456789101112131415161718192021
import sys&def bar(i):&&&&if i == 1:&&&&&&&&raise KeyError(1)&&&&if i == 2:&&&&&&&&raise ValueError(2)&def good():&&&&exception = None&&&&try:&&&&&&&&bar(int(sys.argv[1]))&&&&except KeyError as e:&&&&&&&&exception = e&&&&&&&&print('key error')&&&&except ValueError as e:&&&&&&&&exception = e&&&&&&&&print('value error')&&&&print(exception)&good()
在Py3k里面运行:
$ python3 foo.py 1
$ python3 foo.py 2
value error
$ python3 foo.py 1key error1$ python3 foo.py 2value error2
(顺带提一下,我们的“”里讨论了从Python 2移植代码到Python 3时需要注意的其他重要的不同之处。)
常见错误10:错误的使用__del__方法
假设有一个文件mod.py中这样使用:
import foo
class Bar(object):
def __del__(self):
foo.cleanup(self.myhandle)
import foo&class Bar(object):&&
&&&&...&&&&def __del__(self):&&&&&&&&foo.cleanup(self.myhandle)
然后试图在another_mod.py里这样:
import mod
mybar = mod.Bar()
import modmybar = mod.Bar()
那么你会得到一个恶心的AttributeError异常。
为啥呢?这是因为(参考),当解释器关闭时,模块所有的全局变量会被置为空(None)。结果便如上例所示,当__del__被调用时,名字foo已经被置为空了。
使用atexit.register()可以解决这个问题。如此,当你的程序结束的时候(退出的时候),你的注册的处理程序会在解释器关闭之前处理。
这样理解的话,对上面的mod.py可以做如下的修改:
import foo
import atexit
def cleanup(handle):
foo.cleanup(handle)
class Bar(object):
def __init__(self):
atexit.register(cleanup, self.myhandle)
12345678910
import fooimport atexit&def cleanup(handle):&&&&foo.cleanup(handle)&class Bar(object):&&&&def __init__(self):&&&&&&&&...&&&&&&&&atexit.register(cleanup, self.myhandle)
这样的实现方式为在程序正常终止时调用清除功能提供了一种干净可靠的办法。显然,需要foo.cleanup决定怎么处理绑定在self.myhandle上的对象,但你知道怎么做的。
Python 是一门非常强大且灵活的语言,它众多的机制和范式能显著的提高生产效率。不过,和任何一款软件或者语言一样,对它的理解或认识不足的话,常常是弊大于利的,并会处于一种“一知半解”的状态。
多熟悉Python的一些关键的细微的地方,比如(但不局限于)本文中提到的这些问题,可以帮你更好的使用这门语言的同时帮你避免一些常见的陷阱。
感兴趣的话可以读一读这篇“”,了解一些能够区分Python程序员的面试题目。
希望您能在本文学到有用的地方,并欢迎您的反馈。
关于作者:}

我要回帖

更多关于 python 安装模块 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信