原因:
导致在这个问题的原因是你的模块名和你要引用的类或方法或变量的名字重了。说通俗点就是,python脚本名字(模块名)和你要引用的内容(模块内的类,变量等)的名字重复了,导致你原本“类->属性/方法”的引用意图被解析为了"模块->属性”的引用意图。当模块下面没有这个属性,就抛出了这个错误。解决办法是换不重复的命名。
事故:
市民小py最近在学scrapy。小py觉得对于有编程语言基础的人来说,不存在入不入门的问题,就是刚,坑踩多了就会了(这flag立的...)。所以尽管没学过python,小py还是直接上了, 然后就遇到了各种奇怪的问题了。下面请看本台记者带来的问题报导:
我小py在GetOnePara.py文件中定义了一个提供静态方法的类GetOnePara:
class GetOnePara(): @staticmethod def getReqUrlDic(): return xxx
然后在爬虫代码开头使用下列代码引入了该类,希望能在爬虫中调用该类的静态方法。
import GetOnePara class GetOneSp(scrapy.Spider): urlDic = GetOnePara.getReqUrlDic()
当小py运行代码引用的时候发现
urlDic = GetOnePara.getReqUrlDic()这一行报错:AttributeError: 'module' object has no attribute 'getReqUrlDic', 翻译过来是"模块"对象没有getReqUrlDic这个参数。
这里小py犯了两个错误最终导致了问题:
1.模块名和类名重复,为混淆提供了可能
2.小py没有理清import xxx和 from import xxx的区别
什么是模块?
简单地说,模块就是一个保存了Python代码的文件。模块也是Python对象,具有随机的名字属性用来绑定或引用。
(摘自:http://www.runoob.com/python/python-modules.html)。、
import yyy 和 from yyy import xxx的区别?
import yyy是引入yyy这个模块,没有指定命名空间,当你使用yyy模块下的xxx你需要指定命名空间(yyy. xxx的形式),否则无法识别
from yyy import xxx 是从yyy这个模块引入xxx这个内容,使用xxx的时候就直接写xxx就行了。(然而并不推荐这种用法)
我们在python里面import xxx,这个xxx就对应一个xxx.py文件。 因为模块也是python对象,所以
小py原本的意图是通过模块下的GetOnePara类引用其静态方法getReqUrlDic。但是
GetOnePara.getReqUrlDic()这句就被解析为在模块 GetOnePara里面找直属的getReqUrlDic属性(没有这个属性),所以报错了。
根本杜绝问题的方法是确保模块名(即文件名)不和模块内要引用的内容重复。这里把GetOnePara.py重命名为fGetOnePara.py以区分模块和模块内的类。此外还需要 修改GetOnePara的类调用代码, 为其指定命名空间(其所属的模块名),即:
import GetOnePara urlDic = GetOnePara.getReqUrlDic() #模块名和类名重合,加上未指定明明空间,导致解析的结果和实际意图不服
改为 (模块名.类名.属性名 的形式)
import fGetOnePara #修改了模块名 urlDic = fGetOnePara.GetOnePara.getReqUrl() #指定命名空间