0

我有一个按钮类,你可以像这样实例化:

engine.createElement((0, 0), Button(code=print, args=("Stuff!",)))

当它被点击时,它会打印“Stuff!”。但是,我需要按钮在单击时自行销毁。像这样的东西:

engine.createElement((0, 0), Button(code=engine.killElement, args=(self,)))

但是,这只会杀死调用者,因为此时 self 指的是调用者。我需要做的是提前给班级自己的“自我”......

我只想让字符串在单击时'self'引用self变量,但是如果我想'self'在参数中使用字符串怎么办?

这样做的方法是什么?我的架构是错的还是什么?

4

4 回答 4

3

不幸的是,这是不可能的——按钮构造函数的参数在构造函数被计算之前被计算。您需要将按钮分配给一个变量,然后设置回调:

b = Button(code=engine.killElement)
b.args = (b, )

或类似的东西。

于 2012-11-20T22:44:57.600 回答
2

您基本上已经对其进行了设置,因此您需要一个对象的引用才能创建该对象,这当然是不可能的。你可以做这样的事情(列表和元组一样好用于参数解包):

arglist = []
button = Button(code=engine.killElement, args=arglist)
arglist.append(button)
engine.createElement((0, 0), button)

这是不优雅、不清楚和冗长的,但它会将对实例的引用获取到实例中。

您可以使用另一张海报建议的哨兵值。也许更好的建议是简单地使用一个约定(如 Python 本身),self它始终作为第一个参数传递给指定函数,并且不需要显式指定。然后你的回调被写成总是 take self,即使他们不做任何事情。

但通常您不会通过将对象的行为传递给对象的构造函数来指定对象的行为,而是通过继承来指定对象的行为。换句话说,您将子类 Button化,覆盖其onClick方法或其他任何东西,然后实例化子类。知道onClick它附加到哪个实例不是问题。所以我支持是的,你的架构有点错。

于 2012-11-20T22:51:00.847 回答
1

这一般是不可能的。

但是,如果您正在创建Button类,则可以传递一个特殊的标记值,即“您自己”。例如:

class Button(object):
    yourself = 'yourself'
    def __init__(self, code, args):
        self.code = code
        self.args = [self if arg is yourself else arg for arg in args]

然后:

engine.createElement((0, 0), Button(code=engine.killElement, args=(Button.yourself,)))

选择一个合适的哨兵可能会很棘手——明显的选择,比如None, 0, 或者''可能是合法值,甚至你想出的棘手的东西在调试过程中可能会变成有用的参数。在模块中创建yourself一个类变量或全局变量意味着如果您确实需要重新定义哨兵,您只需在一个地方更改它,而不是在您使用它的任何地方。

请参阅http://bytes.com/topic/python/answers/555169-sentinel-values-special-cases了解有关选择适当哨兵值的简要讨论。还有另一个博客有更多信息,但我没有在快速搜索中找到它......无论如何,这里有一些快速的想法:

  1. None如果它有效,它总是最好的答案。
  2. 定义一个空类作为哨兵。可以使用类对象或类对象的任何实例。
  3. 创建object类 ( object()) 的全局实例。
  4. 定义一个空函数并使用它(或其func_code或其他)。
  5. Ellipsis(或type(Ellipsis),这是一个名为 的类型ellipsis,但该名称不可访问)几乎总是安全的,因为它仅用于__getitem__和朋友(并且可能用于定义slice要传递给他们的对象)。
  6. 如果有一个不可能是有效值的类型,并且您已经有实例,请使用其中的一个——例如,函数的func_code成员。__init__
于 2012-11-20T22:48:13.173 回答
0

也许这样的事情会有所帮助:

class Button(object):
    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls, *args, **kwargs)
        kwargs['args'].append(obj)
        return obj

    def __init__(self, code, args):
        self.code = code
        self.args = args

    def click(self):
        return self.code, self.args

b = Button(code="engine.killElement", args=[])
print b.click()

输出:

('engine.killElement', [<__main__.Button object at 0x00B59AF0>])    
于 2012-11-21T17:34:25.793 回答