使用getattr访问方法

时间:2013-09-08 00:33:35

标签: python oop getattr

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

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())表明分析是其中的一部分:

['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)

2 个答案:

答案 0 :(得分: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)

上面的代码片段确实也有它的问题(例如,更好的方法是chain of responsibility pattern)但是对于小脚本来说它会更好并且更好。

答案 1 :(得分:2)

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

可能您只需要替换第90行的代码,将read_xlsx(input_file)转换为self.read_xlsx(input_file),但您可能还需要为父DataProject实例传递额外的参数。