制作一个可以在lambda中使用的属性的最pythonic方法是什么?

D K*_*D K 5 python oop tkinter

更具体地说,我希望能够支持lambda: <some_or_other_setter>,但我希望保持代码清晰,简洁.我必须验证值,所以我需要一个某种类型的setter.我需要使用lambda,因为我需要将回调传递给Tkinter事件.我还需要能够修改绑定之外的属性值.

在我的以下示例中,假设spam_button已全局声明了一个名为的按钮窗口小部件.还假设该类Eggs将具有至少10个属性,而不是以相同的方式访问所有属性(我喜欢一致性).

我能做到的第一种可能的方法是使用getter和setter:

class Eggs(object):

    def __init__(self):
        self._spam = ''
        self.set_spam('Monster')
        print self.get_spam()
        spam_button.bind('<Enter>', lambda: self.set_spam('Ouch'))

    def set_spam(self, spam):
        if len(spam) <= 32:
            self._spam = spam

    def get_spam(self):
        return self._spam
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用此方法并具有许多属性,则代码可能会花费太长时间来管理.

我可以做的第二种方法是使用属性,并在回调中使用setter:

class Eggs(object):

    def __init__(self):
        self._spam = ''
        self.spam = 'Monster'
        print self.spam
        spam_button.bind('<Enter>', lambda: self.set_spam('Ouch'))

    def set_spam(self, spam):
        if len(spam) <= 32:
            self._spam = spam

    def get_spam(self):
        return self._spam

    spam = property(get_spam, set_spam)
Run Code Online (Sandbox Code Playgroud)

直接访问属性时,这种方式比第一种方式简单,但在使用lambda时则不一致.

第三种方法是使用get和set方法创建一个额外的类:

class Spam(object):

    def __init__(self):
        self._value = ''

    def set(self, value):
        if len(spam) <= 32:
            self._value = value

    def get(self):
        return self._value


class Eggs(object):

    def __init__(self):
        self._spam = ''
        self.spam = Spam()
        self.spam.set('Monster')
        print self.spam.get()
        spam_button.bind('<Enter>', lambda: self.spam.set('Ouch'))
Run Code Online (Sandbox Code Playgroud)

这个方法比第一个方法更有条理,但我需要为每种类型的验证创建一个类.

我可能做的最后一种方法是使用方法而不是属性(属性是第二个例子):

class Eggs(object):

    def __init__(self):
        self._spam = ''
        self.spam('Monster')
        print self.spam()
        spam_button.bind('<Enter>', lambda: self.spam('Ouch'))

    def spam(self, spam=None):
        if spam != None: 
            if len(spam) <= 32:
                self._spam = spam
        else:
            return self._spam
Run Code Online (Sandbox Code Playgroud)

这种方法可能是最短的,但是一目了然地告诉我是否正在进行或设置.

哪种(如果有的话)这些方法是首选的?

agf*_*agf 2

使用闭包返回一个用作回调的函数,并将每个条件定义为一个函数(使用lambdadef,您的偏好),而不是将每个setter定义为一个函数。

class Eggs(object):

    def __init__(self):
        self.spam = 'Monster'
        def spam_condition(string = None):
            return (string is not None) and (len(string) <= 32)
        self.spam_setter = self.set('spam', 'Ouch', spam_condition)
        spam_button.bind('<Enter>', self.spam_setter)
        self.spam_setter(val='Horse')


    def set(self, name, value, condition):
        def setter(val):
            if type(val) is not .... :  # fill this in with the TYPE of the event
                value = val
            if condition(value):
                setattr(self, name, value)
        return setter
Run Code Online (Sandbox Code Playgroud)

编辑:现在您可以从任何地方调用设置器,它将检查条件。

编辑2:这样,setter 将检查它是否收到事件,如果没有,则使用它传递的值。您还可以使用:

if not isinstance(val, ....) :  # fill this in with the CLASS of the event
Run Code Online (Sandbox Code Playgroud)