0

我有一个类 ( node),我想根据类 ( ) 的参数为其分配一组特定的函数(在本例a1中为a2b1、 和)。b2operatingMode

情况是我的电机有许多不同的操作模式。每种操作模式都允许执行某些功能,但不允许执行其他功能。将功能分配给各种模式的方式并不适合为每种操作模式创建类。

下面是我的解决方案,但它不起作用。

有什么想法吗?

def a1(self):
    return 'a1'

def a2(self):
    return 'a2'

def b1(self):
    return 'b1'

def b2(self):
    return b2




class node(object):
    def __init__(self,operatingMode):
    self.operatingMode=operatingMode

    if self.operatingMode=='A':
        self.a1function=a1
        self.a2function=a2
        print 'Operating Mode \'A\' functions loaded'

    if self.operatingMode=='B':
        self.b1function=b1
        self.b2function=b2
        print 'Operating Mode \'B\' functions loaded'

    def setOperatingMode(self,operatingMode):
        self.operatingMode=operatingMode
        self.__init__(self,operatingMode)

在我的终端中运行它可以让我调用它,但我必须两次声明肘部:

In [65]: elbow=node('A')
Operating Mode 'A' functions loaded

In [66]: elbow.a1function(elbow)
Out[66]: 'a1'

尝试运行会elbow.setOperatingMode('B')产生错误。

4

4 回答 4

2

使用types.MethodType__getattr__

import types

def a1(self):
    return 'a1'

def a2(self):
    return 'a2'

def b1(self):
    return 'b1'

def b2(self):
    return 'b2'

class Node(object):
    def __init__(self, operatingMode):
        self.operatingMode = operatingMode
    def __getattr__(self, attr):
        if self.operatingMode=='A':
            if attr == 'a1function':
                return types.MethodType(a1, self)
            if attr == 'a2function':
                return types.MethodType(a2, self)

        elif self.operatingMode=='B':
            if attr == 'b1function':
                return types.MethodType(b1, self)
            if attr == 'b2function':
                return types.MethodType(b2, self)
        else:
            raise AttributeError()

然后

elbow = Node('A')
print(elbow.a1function())
elbow.operatingMode = 'B'
print(elbow.b2function())

产量

a1
b2
于 2013-04-03T21:31:10.383 回答
1

也许使用checkMode装饰器会是一种更清洁的方式——这可以避免__getattr__type.MethodType神奇:

def checkMode(mode):
    def deco(func):
        def wrapper(self):
            if self.operatingMode == mode:
                return func(self)
            else:
                raise TypeError('Wrong operating Mode')
        return wrapper
    return deco

class Node(object):
    def __init__(self, operatingMode):
        self.operatingMode = operatingMode

    @checkMode('A')
    def a1(self):
        return 'a1'

    @checkMode('A')
    def a2(self):
        return 'a2'

    @checkMode('B')
    def b1(self):
        return 'b1'

    @checkMode('B')
    def b2(self):
        return 'b2'

使用上面的代码,我们可以这样做:

elbow = Node('A')
print(elbow.a1())
# a1

knee = Node('A')
print(knee.a1())
# a1

elbow.operatingMode = 'B'
print(knee.a1())  # knee is still in operatingMode A
# a1

print(elbow.b2())
# b2

elbow.a1()
# TypeError: Wrong operating Mode

解释:

装饰器语法的工作原理如下:

@deco
def func(): ...

相当于

def func(): ...
func = deco(func)

上面,checkMode是一个返回装饰器的函数,deco. deco然后装饰方法a1,a2等,这样

a1 = deco(a1)

因此,a1函数是否传递给deco. deco(a1)反过来,返回一个新方法,通常称为wrapper。这个新方法a1由语句分配a1 = deco(a1)。现在a1的方法也是如此wrapper。因此,当您调用 时elbow.a1(),将执行中的代码wrapper

于 2013-04-03T21:50:35.707 回答
1

针对此评论:

这是用于电机控制的,所以我试图限制开销......操作模式的更改频率将比调用单个命令的频率低得多。

Python 实例可以更改它们的类。您可以使用它来更改操作模式,而无需使用 -if子句来检查模式:

class Base(object):
    # Put any methods shared by ANode and BNode here.
    pass

class ANode(Base):
    def a1(self):
        return 'a1'

    def a2(self):
        return 'a2'

class BNode(Base):
    def b1(self):
        return 'b1'

    def b2(self):
        return 'b2'


elbow = ANode()
print(elbow.a1())
# a1

knee = ANode()
print(knee.a1())
# a1

elbow.__class__ = BNode
print(knee.a1())
# a1
print(elbow.b2())
# b2

elbow.a1()
# AttributeError: 'BNode' object has no attribute 'a1'

从积极的方面来说,这是我发布的最快的建议。if请注意,上面的代码中没有- 语句。一旦类发生变化,所有可用的方法都会“立即”发生变化,这完全是由于正常的 Python 方法调用语义。

如果Node在装饰器解决方案中定义,

In [33]: elbow = Node('A')

In [34]: %timeit elbow.a1()
1000000 loops, best of 3: 288 ns per loop

虽然,如果knee使用 定义ANode

In [36]: knee = ANode()

In [37]: %timeit knee.a1()
10000000 loops, best of 3: 126 ns per loop

所以这个解决方案调用方法的速度是装饰器解决方案的 2 倍以上。

切换速度相当:

In [38]: %timeit elbow.operatingMode = 'B'
10000000 loops, best of 3: 71.7 ns per loop

In [39]: %timeit knee.__class__ = BNode
10000000 loops, best of 3: 78.7 ns per loop

警告:困扰我发布的所有解决方案的一件事是,在切换名称后,可用方法会发生变化。这意味着当您使用这些类进行编程时,您必须先跟踪实例的状态,然后才能知道哪些方法可用。这很尴尬。

ANode如果并且BNode具有完全相同的接口——所有相同的属性和方法名称——只需更改这些方法的定义(当模式或类更改时),你的程序就会简单得多。


关于这条评论:

我有大约一百种功能和 7 种操作模式。在这些功能中,大约 10 个在所有操作模式之间共享,75 个由多个模式共享,15 个是特定模式独有的。问题是 75 没有很好地分配给模式:一些可能在模式 1,4 和 7 中,其他在 2,4,5 和 7 中,其他在 1 和 5 中。

您可以在类之外定义方法,然后将它们“连接”到基于模式的类,如下所示:

def a1(self):
    return 'a1'

def a2(self):
    return 'a2'

def b1(self):
    return 'b1'

def b2(self):
    return 'b2'

class Base(object):
    # Put the 10 methods share by all modes here
    def common1(self): 
        pass

class ANode(Base):
    a1 = a1
    a2 = a2

class BNode(Base):
    b1 = b1
    b2 = b2

class CNode(Base):
    a1 = a1
    b2 = b2
于 2013-04-03T22:02:41.857 回答
0

您的整个设计非常奇怪,您可能需要退后一步,解释您正在尝试做什么,以便有人可以帮助您进行更好的设计。

但是如果你只是想让你的设计工作,你当前的代码有两个问题:

self.a1function = a1

这设置self.a1function为常规函数,而不是绑定方法。您可以像这样显式创建绑定方法:

self.a1function=types.MethodType(a1, self, self.__class__)

或者您可以设置a1functiona1. 或者,更简单地说,动态包装,这意味着您可以使用闭包来伪造绑定方法,这可以说更具可读性:

def __getattr__(self, attr):
    if attr == 'a1function' and self.operating_mode == 'A':
        return lambda: a1(self)

同时:

尝试运行肘部.setOperatingMode('B') 会产生错误。

您确实需要发布回溯,或者至少发布错误字符串,而不仅仅是说“产生错误”。在这种情况下,它会非常明确地告诉您错误是什么,因此您无需猜测:

TypeError: __init__() takes exactly 2 arguments (3 given)

问题是在这一行:

self.__init__(self,operatingMode)

……你通过self了两次。它是您调用方法的对象,也是第一个参数。

无论如何,从另一个方法调用__init__是个坏主意,但如果你真的想要,它与调用任何其他方法一样:

self.__init__(operatingMode)
于 2013-04-03T21:31:06.723 回答