2011-01-27 67 views
4

我不知道这是否会是有意义的,但是......映射obj.method({参数:值})到obj.argument(值)

我试图动态分配方法的目的。

#translate this 
object.key(value) 
#into this 
object.method({key:value}) 

要在我的例子更具体的,我有一个对象(我没有写),让我们把它叫做电机,其中有一些通用的方法来设置,状态和其他几个人。有些人拿字典作为参数,有些人拿一份清单。来改变电机的速度,并观察结果,我使用:

motor.set({'move_at':10}) 
print motor.status('velocity') 

马达对象,则格式化该请求为JSON-RPC字符串,并将其发送到IO守护进程。 python马达对象不关心参数是什么,它只是处理JSON格式和套接字。字符串move_at和velocity只是数百个有效参数中的两个。

我希望做的是不要使用以下:

motor.move_at(10) 
print motor.velocity() 

我希望做一个通用的方法,因为我有这么多不同的参数,我们可以通过。我不希望做的是:

# create a new function for every possible argument 
def move_at(self,x) 
    return self.set({'move_at':x}) 
def velocity(self) 
    return self.status('velocity') 
#and a hundred more... 

我做了这个这表明解决一些搜索在于lambda表达式和元编程,两个主题我一直无法左右我的头。

UPDATE:

基于从user470379代码我想出下面...

# This is what I have now.... 
class Motor(object): 
    def set(self,a_dict): 
     print "Setting a value", a_dict 
    def status(self,a_list): 
     print "requesting the status of", a_list 
     return 10 

# Now to extend it.... 
class MyMotor(Motor): 
    def __getattr__(self,name): 
     def special_fn(*value): 
      # What we return depends on how many arguments there are. 
      if len(value) == 0: return self.status((name)) 
      if len(value) == 1: return self.set({name:value[0]}) 
     return special_fn 
    def __setattr__(self,attr,value): # This is based on some other answers 
     self.set({attr:value}) 


x = MyMotor() 
x.move_at = 20 # Uses __setattr__ 
x.move_at(10) # May remove this style from __getattr__ to simplify code. 
print x.velocity() 

输出:

Setting a value {'move_at': 20} 
Setting a value {'move_at': 10} 
10 

谢谢大家谁帮助!

+0

BTW,根据问题的描述,应该不是“#translate this”和“#into这个”顶部的描述被逆转? (将object.key(value)转换为object.method({key:value})) – user470379 2011-01-27 19:02:40

+0

@ user470379,是的,你是对的。 – RyanN 2011-01-27 20:04:52

回答

4

对于创建自己的__getattr__来说,返回一个即时创建的函数的类会如何? IIRC,还有一些棘手的情况下,要提防__getattr____getattribute__之间的我不记得了我的头顶,我敢肯定有人会发表评论提醒我:

def __getattr__(self, name): 
    def set_fn(self, value): 
     return self.set({name:value}) 
    return set_fn 

那应该发生的是调用不存在的属性(即:move_at)将调用__getattr__函数并创建一个将返回的新函数(上面的set_fn)。该函数的name变量将绑定到传递到__getattr__(在这种情况下为"move_at")的name参数。然后用你传递的参数调用这个新函数(在这种情况下为10)。

编辑

更简洁的版本使用lambda表达式(未经测试):

def __getattr__(self, name): 
    return lambda value: self.set({name:value}) 
+0

只有在通常的属性获取方法失败时才会调用__getattr__`。 `__getattribute__`覆盖了对象的所有属性获取活动。 (或者与之相关的东西) – senderle 2011-01-27 19:06:02

1

有很多不同的可能回答这个,但很多人可能会涉及继承的对象, /或者写入或覆盖__getattr__函数。

实质上,只要python无法以通常方式找到属性,就会调用__getattr__函数。

假设你可以继承你的对象,这里就是你可能做一个简单的例子(这是一个有点笨拙,但它是一个开始):

class foo(object): 
    def __init__(self): 
     print "initting " + repr(self) 
     self.a = 5 

    def meth(self): 
     print self.a 

class newfoo(foo): 
    def __init__(self): 
     super(newfoo, self).__init__() 
     def meth2():       # Or, use a lambda: ... 
      print "meth2: " + str(self.a)  # but you don't have to 
     self.methdict = { "meth2":meth2 } 

    def __getattr__(self, name): 
     return self.methdict[name] 

f = foo() 
g = newfoo() 

f.meth() 
g.meth() 
g.meth2() 

输出:

initting <__main__.foo object at 0xb7701e4c> 
initting <__main__.newfoo object at 0xb7701e8c> 
5 
5 
meth2: 5 
1

你似乎有你的对象的某些“属性”,可以通过设置

obj.set({"name": value}) 

和查询

obj.status("name") 

Python中常见的方法是将此行为映射为看起来像简单属性访问的行为。因此,我们写

obj.name = value 

设置属性,我们只需使用

obj.name 

进行查询。这可以很容易地使用__getattr__()__setattr__()特殊的方法来实现:

class MyMotor(Motor): 
    def __init__(self, *args, **kw): 
     self._init_flag = True 
     Motor.__init__(self, *args, **kw) 
     self._init_flag = False    
    def __getattr__(self, name): 
     return self.status(name) 
    def __setattr__(self, name, value): 
     if self._init_flag or hasattr(self, name): 
      return Motor.__setattr__(self, name, value) 
     return self.set({name: value}) 

注意,这个代码不支持动态创建新的“真实” Motor实例的初始化后的属性。如果需要,可以将相应的例外添加到__setattr__()实施中。

1

而不是使用函数调用语法进行设置,请考虑使用赋值(with =)。同样,只需使用属性语法来获取值,而不是函数调用语法。然后你可以use __getattr__ and __setattr__

class OtherType(object): # this is the one you didn't write 
    # dummy implementations for the example: 
    def set(self, D): 
    print "setting", D 
    def status(self, key): 
    return "<value of %s>" % key 

class Blah(object): 
    def __init__(self, parent): 
    object.__setattr__(self, "_parent", parent) 

    def __getattr__(self, attr): 
    return self._parent.status(attr) 
    def __setattr__(self, attr, value): 
    self._parent.set({attr: value}) 

obj = Blah(OtherType()) 
obj.velocity = 42 # prints setting {'velocity': 42} 
print obj.velocity # prints <value of velocity>