0

创建新类实例时,我试图调用不同类中的方法,但无法使其正常工作。这是我所拥有的:

class DataProject(object):    
    def __init__(self, name=none,input_file=None,datamode=None,comments=None,readnow=True):
        ..............
        # here's where I'm trying to call the method in the other class
        if type(input_file) == str:
            self.input_file_format = self.input_file.split(".")[-1]
            if readnow:
                getattr(Analysis(),'read_'+self.input_file_format)(self,input_file)

class Analysis(object):
    def __init__(self):
        pass # nothing happens here atm

    def read_xlsx(self,parent,input_file):
        """Method to parse xlsx files and dump them into a DataFrame"""
        xl = pd.ExcelFile(input_file)
        for s in sheet_names:
            parent.data[s]=xl.parse(s)

当我使用 afile.xlxs 作为输入运行它时,我得到了一个NameError: global name 'read_xlsx' is not defined结果,这让我觉得我刚刚在我的 Python 知识中发现了一个巨大的漏洞(不是说数量不多,但它们往往很难看到,有点像大森林...)。

我原以为这getattr(Analysis(), ... )将访问全局名称空间,在其中可以找到 Analysis 类及其方法。事实上print(globals().keys()),Analysis 是其中的一部分:

['plt', 'mlab', '__builtins__', '__file__', 'pylab', 'DataProject', 'matplotlib', '__package__', 'W32', 'Helpers', 'time', 'pd', 'pyplot', 'np', '__name__', 'dt', 'Analysis', '__doc__']

我在这里想念什么?

编辑:

完整的追溯是:

Traceback (most recent call last):
  File "C:\MPython\dataAnalysis\dataAnalysis.py", line 101, in <module>
    a=DataProject(input_file='C:\\MPython\\dataAnalysis\\EnergyAnalysis\\afile.xlxs',readnow=True)
  File "C:\MPython\dataAnalysis\dataAnalysis.py", line 73, in __init__
    getattr(Analysis(),'read_'+self.input_file_format)(self,input_file)
  File "C:\MPython\dataAnalysis\dataAnalysis.py", line 90, in read_xls
    read_xlsx(input_file)
NameError: global name 'read_xlsx' is not defined

我的主要电话是:

if __name__=="__main__":
    a=DataProject(input_file='C:\\MPython\\dataAnalysis\\EnergyAnalysis\\afile.xlx',readnow=True)
4

2 回答 2

2

从完整的回溯中,您的类似乎DataProject正在调用(成功)该Analysys.read_xls方法,而该方法又试图调用read_xlsx. 但是,它将其称为全局函数,而不是方法。

可能您只需要替换第 90 行的代码,read_xlsx(input_file)变成self.read_xlsx(input_file),尽管您可能还需要为父DataProject实例传递一个额外的参数。

于 2013-09-08T00:46:35.140 回答
2

getattr()正如您在 Python2.x 和 Python3.x 中描述的那样工作。该错误必须在其他地方。

对代码的这种修改(没有更改任何核心逻辑)可以正常工作,例如:

class DataProject(object):    
    def __init__(self, name="myname",input_file="xlsx",datamode=None,comments=None,readnow=True):
        if type(input_file) == str:
            self.input_file_format = input_file.split(".")[-1]
            if readnow:
                getattr(Analysis(),'read_'+self.input_file_format)(self,input_file)

class Analysis(object):
    def __init__(self):
        pass # nothing happens here atm

    def read_xlsx(self,parent,input_file):
        """Method to parse xlsx files and dumpt them into a DataFrame"""
        print("hello")

a=DataProject()

输出是:

$ python3 testfn.py
hello

为什么getattr()以这种方式使用通常是一个坏主意

您使用的方式getattr强制对您的方法 ( read_someformat) 进行命名约定。方法的命名不应成为程序逻辑的核心部分。- 您应该始终能够在每次调用和定义该函数时更改函数的名称,并使程序的行为保持不变。

如果文件格式需要由特定方法处理,则该逻辑应委托给对此负责的某个单元(例如函数)。这样做的一种方法(还有其他方法)是有一个函数来接受输入并决定哪个函数需要处理它:

def read_file(self,file,format):
    if format == `xls`:
        self.read_xls(file)
    if format == `csv`:
        self.read_csv(file)

上面的代码片段也有它的问题(例如,更好的方法是责任链模式),但它适用于小脚本并且更好。

于 2013-09-08T00:41:18.133 回答