如何根据条件快速禁用类实例中的所有方法?我天真的解决方案是覆盖使用__getattr__但是当函数名称已经存在时不会调用它.
class my():
def method1(self):
print 'method1'
def method2(self):
print 'method2'
def __getattr__(self, name):
print 'Fetching '+str(name)
if self.isValid():
return getattr(self, name)
def isValid(self):
return False
if __name__ == '__main__':
m=my()
m.method1()
Run Code Online (Sandbox Code Playgroud)
您想要做的事情的等效实际上是覆盖__getattribute__,将为每个属性访问调用.除了它是非常缓慢的,照顾:通过定义每一个,包括例如呼叫self.isValid内__getattribute__的自己的身体,所以你必须使用一些迂回路线来访问属性(type(self).isValid(self)应该工作,例如,因为它得到来自类的属性,而不是来自实例的属性).
这指出了一个可怕的术语混淆:这不是禁用"来自类的方法",而是来自一个实例,特别是与之无关classmethods.如果你想在类的基础上以类似的方式工作,而不是基于实例,你需要在元类__getattribute__ 上创建一个自定义元类和覆盖(这是在访问类的属性时调用的元类 -正如你在标题和文字中所要求的那样 - 而不是在实例上 - 因为你实际上似乎在做,这是迄今为止更正常和通常的情况).
编辑:一种完全不同的方法可能是使用一种特殊的Pythonic路径来实现State设计模式:类切换.例如:
class _NotValid(object):
def isValid(self):
return False
def setValid(self, yesno):
if yesno:
self.__class__ = TheGoodOne
class TheGoodOne(object):
def isValid(self):
return True
def setValid(self, yesno):
if not yesno:
self.__class__ = _NotValid
# write all other methods here
Run Code Online (Sandbox Code Playgroud)
只要你能setValid恰当地调用,以便对象__class__被适当地切换,这是非常快速和简单的 - 基本上,对象__class__是找到所有对象的方法的地方,所以通过切换它你可以切换,集合,在给定时间存在于对象上的方法.但是,如果您绝对坚持必须"及时"执行有效性检查,即在查找对象方法的瞬间,这不起作用.
这个和__getattribute__一个之间的中间方法是引入一个额外的间接水平(这通常被认为是所有问题的解决方案;-),其方式如下:
class _Valid(object):
def __init__(self, actualobject):
self._actualobject = actualobject
# all actual methods go here
# keeping state in self._actualobject
class Wrapit(object):
def __init__(self):
self._themethods = _Valid(self)
def isValid(self):
# whatever logic you want
# (DON'T call other self. methods!-)
return False
def __getattr__(self, n):
if self.isValid():
return getattr(self._themethods, n)
raise AttributeError(n)
Run Code Online (Sandbox Code Playgroud)
这更加惯用,__getattribute__因为它依赖于__getattr__只调用其他方式无法找到的属性的事实- 因此对象可以在其中保存正常状态(数据)__dict__,并且可以在没有任何大开销的情况下访问它; 只有方法调用才能支付额外的间接费用.在_Valid类的实例可以保留部分或全部国家在各自的self._actualobject,如果任何一个国家都需要留在无效对象访问的(使无效状态禁用方法,但不是数据属性访问;如果这是需要它不是从您的问与答清楚,但这种方法提供了免费的额外可能性.这个习惯用法不易出错__getattribute__,因为可以在方法中更直接地访问状态(不触发有效性检查).
如上所述,该解决方案创建了一个循环引用循环,这可能会在垃圾收集方面产生一些开销.如果这在您的应用程序中存在问题,那么使用标准Python库中的weakref模块 - 当然,该模块通常是删除引用循环循环的最简单方法,如果它们出现问题.(例如,使类实例的_actualobject属性成为对该实例作为其属性的对象_Valid的弱引用_themethods).