我不知道这是否有意义,但是......
我正在尝试动态地为对象分配方法。
#translate this
object.key(value)
#into this
object.method({key:value})
在我的例子中更具体一点,我有一个对象(我没有写),我们称之为motor,它有一些通用的方法集,状态和其他一些。有些人把字典作为一个参数,有些人拿一个列表。要改变电机的速度,并查看结果,我使用:
motor.set({'move_at':10})
print motor.status('velocity')
电机对象然后将此请求格式化为JSON-RPC字符串,并将其发送到IO守护程序。 python motor对象不关心参数是什么,它只是处理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...
我做了一些搜索,这表明解决方案在于lambdas和元编程,这两个主题我无法理解。
更新:
根据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 :(得分: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
变量将绑定到name
传递给__getattr__
的参数(在本例中为"move_at"
)。然后将使用您传递的参数调用该新函数(在这种情况下为10
)。
修改强>
使用lambdas(未经测试)的更简洁版本:
def __getattr__(self, name):
return lambda value: self.set({name:value})
答案 1 :(得分: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
答案 2 :(得分: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__()
实现中添加相应的例外。
答案 3 :(得分:1)
不要使用函数调用语法进行设置,而应考虑使用赋值(使用=)。同样,只需使用属性语法来获取值,而不是函数调用语法。然后你可以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>