Python __getattr__实现未定义方法

注意:该文章中的方案不是最优解决方案,只针对特殊情况.

已经好久没用Python写过正经的软件,这两天在做一个由Python实现的命令行工具,主要是模拟cd,ls之类的命令.

cd和ls作为方法被写进class Cmd类中,为了处理未定义命令,不得不去捕获AttributeError异常.

但是在我写的那个class中捕获异常看着有违和感,所以换用getattr这个魔术方法解决问题.

下面是一段简化后的代码:

class A():  
  def __init__(self):
    self.hello='Hello!'
  def sayHello(self):
    print self.hello
a=A()  
a.sayHello()  
a.sayGoodBye()#Error!  

在这段代码中,类A有个sayHello方法,在类A实例化后,可以调用sayHello方法,调用sayGoodBye方法时会出现AttributeError: A instance has no attribute ‘sayGoodBye’的异常

要在不定义sayGoodBye方法的前提下让代码正常工作,需要使用getattr.

import sys  
class A():  
  def __init__(self):
    self.hello='Hello!'
  def sayHello(self):
    print self.hello
  def __getattr__(self,name):
    return lambda:sys.stdout.write('GoodBye!\n')
a=A()  
a.sayHello()  
a.sayGoodBye()  

现在调用sayGoodBye方法就会打印GoodBye!了.

但这么做可能会影响正常的程序逻辑,所以我们还是将sayGoodBye作为一种特殊情况处理,给name加上判断.

import sys  
class A():  
  def __init__(self):
    self.hello='Hello!'
  def sayHello(self):
    print self.hello
  def __getattr__(self,name):
    if name=='sayGoodBye':
      return lambda:sys.stdout.write('GoodBye!\n')
    else:
      raise AttributeError("A instance has no attribute '%s'" % name)
a=A()  
a.sayHello()  
a.sayGoodBye()  
a.sayGoodNight()#Error!  

这样在调用sayGoodBye时会打印GoodBye!,调用sayGoodNight时由于没有这个方法而抛出AttributeError异常.

到这里,我们的目的已经完成了,但还可以用字典做进一步处理,让之后的代码更好写一些.

import sys  
class A():  
  def __init__(self):
    self.method={
    'sayGoodBye':lambda:sys.stdout.write('GoodBye!\n'),
    'sayGoodNight':lambda:sys.stdout.write('GoodNight!\n')
    }
    self.hello='Hello!'
  def sayHello(self):
    print self.hello
  def __getattr__(self,name):
    if self.method.has_key(name):
      return self.method[name]
    else:
      raise AttributeError,"A instance has no attribute '%s'" % name
a=A()  
a.sayHello()  
a.sayGoodBye()  
a.sayGoodNight()  

上面的红字已经提到这是特殊情况使用的方案,常规情况请不要使用这种写法.