在实例化时给一个类自己的`self`?

时间:2012-11-20 22:42:50

标签: python class instantiation self

我有一个你可以实例化的按钮类:

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 个答案:

答案 0 :(得分:3)

不幸的是,这是不可能的 - 在评估构造函数之前,会评估按钮构造函数的参数。您需要将按钮分配给变量,然后设置回调:

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

或类似的东西。

答案 1 :(得分:2)

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

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

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

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

但通常你不会通过将对象的行为传递给该对象的构造函数来指定对象的行为,而是通过继承来指定对象的行为。换句话说,你子类 Button,覆盖它的onClick方法或其他什么,并实例化子类。让onClick知道它附加的实例是非问题。所以,我站在了一边,你的架构有点错误。

答案 2 :(得分: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,)))

挑选合适的哨兵可能很棘手 - 明显的选择,例如None0''可能是合法的价值观,甚至你提出的棘手的事情可能会变成调试时有用的参数。将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__成员。

答案 3 :(得分: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>])