将 obj.method({argument:value}) 映射到 obj.argument(value)

发布于 2024-10-14 15:06:52 字数 1853 浏览 1 评论 0原文

我不知道这是否有意义,但是......

我正在尝试动态地将方法分配给对象。

#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 和元编程,这是我无法理解的两个主题。

更新:

根据 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

感谢所有提供帮助的人!

I don't know if this will make sense, but...

I'm trying to dynamically assign methods to an object.

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

To be more specific in my example, I have an object (which I didn't write), lets call it motor, which has some generic methods set, status and a few others. Some take a dictionary as an argument and some take a list. To change the motor's speed, and see the result, I use:

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

The motor object, then formats this request into a JSON-RPC string, and sends it to an IO daemon. The python motor object doesn't care what the arguments are, it just handles JSON formatting and sockets. The strings move_at and velocity are just two of what might be hundreds of valid arguments.

What I'd like to do is the following instead:

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

I'd like to do it in a generic way since I have so many different arguments I can pass. What I don't want to do is this:

# 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...

I did some searching on this which suggested the solution lies with lambdas and meta programming, two subjects I haven't been able to get my head around.

UPDATE:

Based on the code from user470379 I've come up with the following...

# 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()

output:

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

Thank you to everyone who helped!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不疑不惑不回忆 2024-10-21 15:06:52

为返回动态创建的函数的类? 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__name 参数(在此为 "move_at"案件)。然后,将使用您传递的参数(在本例中为 10)调用该新函数。

编辑

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

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

What about creating your own __getattr__ for the class that returns a function created on the fly? IIRC, there's some tricky cases to watch out for between __getattr__ and __getattribute__ that I don't recall off the top of my head, I'm sure someone will post a comment to remind me:

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

Then what should happen is that calling an attribute that doesn't exist (ie: move_at) will call the __getattr__ function and create a new function that will be returned (set_fn above). The name variable of that function will be bound to the name parameter passed into __getattr__ ("move_at" in this case). Then that new function will be called with the arguments you passed (10 in this case).

Edit

A more concise version using lambdas (untested):

def __getattr__(self, name):
    return lambda value: self.set({name:value})
诗笺 2024-10-21 15:06:52

对此有很多不同的潜在答案,但其中许多可能涉及对象的子类化和/或编写或重写 __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

There are a lot of different potential answers to this, but many of them will probably involve subclassing the object and/or writing or overriding the __getattr__ function.

Essentially, the __getattr__ function is called whenever python can't find an attribute in the usual way.

Assuming you can subclass your object, here's a simple example of what you might do (it's a bit clumsy but it's a start):

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()

Output:

initting <__main__.foo object at 0xb7701e4c>
initting <__main__.newfoo object at 0xb7701e8c>
5
5
meth2: 5
莫言歌 2024-10-21 15:06:52

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

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__() 实现中。

You seem to have certain "properties" of your object that can be set by

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

and queried by

obj.status("name")

A common way to go in Python is to map this behaviour to what looks like simple attribute access. So we write

obj.name = value

to set the property, and we simply use

obj.name

to query it. This can easily be implemented using the __getattr__() and __setattr__() special methods:

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})

Note that this code disallows the dynamic creation of new "real" attributes of Motor instances after the initialisation. If this is needed, corresponding exceptions could be added to the __setattr__() implementation.

梦行七里 2024-10-21 15:06:52

不要使用函数调用语法进行设置,而是考虑使用赋值(带有=)。同样,只需使用属性语法来获取值,而不是函数调用语法。然后你可以使用 __getattr__ 和 __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>

Instead of setting with function-call syntax, consider using assignment (with =). Similarly, just use attribute syntax to get a value, instead of function-call syntax. Then you can 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文