2010-08-08 25 views
3

我想写出具有执行以下操作的能力的Python类:的Python:允许方法没有特别的限制被称为ALA __getattr__

c = MyClass() 
a = c.A("a name for A") # Calls internally c.create("A", "a name for A") 
b = c.B("a name for B") # Calls internally c.create("B", "a name for B") 

A和B可以是任何东西(当然,他们“再在数据库中定义的,但我不希望在我的代码明确定义它们)

它哈克解决方法是做到以下几点:

class MyClass(): 
    def __init__(self): 
     self.createItem = "" 

    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def create_wrapper(self, name): 
     self.create(self.createItem, name) 

    def __getattr__(self, attrName): 
     self.createItem = attrName 
     return self.create_wrapper 

这将工作当U SER要求是这样的:

a = c.A("nameA") 
b = c.B("nameB") 

然而,它会翻倒在情况下的函数指针存储,而不叫:

aFunc = c.A 
bFunc = c.B 
aFunc("nameA") # Is actually calling c.create("B", "nameA"), 
       # as c.B was the last __getattr__() call 
bFunc("nameB") 

的任何东西,我在这里失踪有什么建议?

感谢

编辑:我似乎已经只是想出这一个,但菲利普有一个更优雅的解决方案....

我的解决办法是:

class MyClassCreator(): 
    def __init__(self, origClass, itemType): 
     self.origClass = origClass 
     self.itemType = itemType 

    def create_wrapper(self, name): 
     return self.origClass.create(self.itemType, name) 

class MyClass(): 
    def __init__(self): 
     self.createItem = "" 

    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def __getattr__(self, attrName): 
     return MyClassCreator(self, attrName).create_wrapper 

版本我实际上最终使用(因为我需要比单个参数更复杂)是:(我不知道这是否可以使用lambda函数来完成......)

def __getattr__(self, attrName): 
    def find_entity_wrapper(*args, **kwargs): 
     return self.find_entity(attrName, *args, **kwargs) 

    return find_entity_wrapper 
+0

你想实现一个'Mock'库? – 2010-08-08 16:00:11

回答

6

有无__getattr__返回本地包装功能:

class MyClass(object): 
    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def __getattr__(self, attrName): 
     def create_wrapper(name): 
      self.create(attrName, name) 
     return create_wrapper 

还有其他的方法来创建包装函数。在这种情况下,最简单的一种是使用functools.partial

import functools 

class MyClass(object): 
    def create(self, itemType, itemName, *args, **kwargs): 
     print "Creating item %s with name %s, args %r and kwargs %r" % (itemType, itemName, args, kwargs) 

    def __getattr__(self, attrName): 
     return functools.partial(self.create, attrName) 

c = MyClass() 
bFunc = c.B 
bFunc("nameB", 1, 2, foo=3) 

这将自动传递所有剩余的参数传递给被包装的函数。

+0

我不确定你和我最喜欢哪一种解决方案,但它们都比我想出的更好(请参阅上面我的问题的编辑底部) – Hugh 2010-08-08 15:59:32

+0

他们不太相同 - 我的版本是只是lambda版本的拼写变体。兰姆达斯有时因为限制性和难于阅读而被Python所折服,但在语义上它们相当于命名函数。通常我只对不修改状态的简单表达式使用lambdas和其他类似功能的构造。 – Philipp 2010-08-08 16:30:05

+0

我已经把实际的功能放在了我的问题的底部 - 我实际上需要能够通过任何数量的参数,我不确定它们是否会使用lambda函数... – Hugh 2010-08-08 16:32:49

5

你可以得到你想要的东西通过简化:

class MyClass(): 

    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def __getattr__(self, attrName): 
     return lambda x: self.create(attrName, x) 

c = MyClass() 
a = c.A("nameA") 
b = c.B("nameB") 


af = c.A 
bf = c.B 
af("nameA") 
bf("nameB") 

打印:

Creating item A with name nameA 
Creating item B with name nameB 
Creating item A with name nameA 
Creating item B with name nameB 
+0

谢谢 - 看起来非常优雅!我从来没有把我的脑袋绕过lambda - 也许现在应该是时候这样做了......我会按照这种方式或者菲利普建议的方式......无论哪种方式适合我! 谢谢 – Hugh 2010-08-08 16:00:30

+0

其实,我的问题中的例子是一个非常简化的例子 - 我实际上需要能够通过一个变量(kwargs)数量的参数,我相信我不能用lambda来做到这一点......不确定,但很高兴看到Philipp的解决方案会高兴地支持这一点。 再次感谢。 – Hugh 2010-08-08 16:02:26

相关问题