15

TL;DR:必须为每个 property() 的变量定义一组唯一的 getter 和 setter 很糟糕。我可以定义通用的 getter 和 setter 并将它们与我想要的任何变量一起使用吗?

假设我用一些不错的 getter 和 setter 创建了一个类:

class Foo
    def getter(self):
        return _bar+' sasquatch'

    def setter(self, value):
        _bar = value+' unicorns'

    bar = property(getter, setter)

非常棒,对吧?

现在假设我放入了另一个名为“baz”的变量,我不希望它被这个野人/独角兽的乐趣所遗漏。好吧,我想我可以制作另一组 getter 和 setter:

class Foo
    def bar_getter(self):
        return _bar+' sasquatch'

    def bar_setter(self, value):
        _bar = value+' unicorns'

    bar = property(bar_getter, bar_setter)

    def baz_getter(self):
        return _baz+' sasquatch'

    def baz_setter(self, value):
        _baz = value+' unicorns'

    baz = property(baz_getter, baz_setter)

但这不是很干,并且不必要地使我的代码混乱。我想我可以让它更干燥一点:

class Foo
    def unicornify(self, value):
        return value+' unicorns'

    def sasquatchify(self, value):
        return value+' sasquatch'

    def bar_getter(self):
        return self.sasquatchify(_bar)

    def bar_setter(self, value):
        _bar = self.unicornify(_bar)

    bar = property(bar_getter, bar_setter)

    def baz_getter(self):
        return self.sasquatchify(_baz)

    def baz_setter(self, value):
        _baz = self.unicornify(_baz)

    baz = property(baz_getter, baz_setter)

尽管这可能会使我的代码更干燥,但这并不理想。如果我想将另外两个变量进行 unicornify 和 sasquatchify,我将不得不再添加四个函数!

必须有更好的方法来做到这一点。我可以跨多个变量使用单个通用 getter 和/或 setter 吗?

Unicorn-less 和 sasquatch-less 实际实现: 我正在使用 SQLAlchemy ORM,并且希望在从数据库中存储和检索数据时转换一些数据。一些转换适用于多个变量,我不想让我的类与 getter 和 setter 混淆。

4

5 回答 5

15

怎么样:

def sasquatchicorn(name):
    return property(lambda self: getattr(self, name) + ' sasquatch',
                    lambda self, val: setattr(self, name, val + ' unicorns'))

class Foo(object):
    bar = sasquatchicorn('_bar')
    baz = sasquatchicorn('_baz')

更笼统地说:

def sasquatchify(val):
    return val + ' sasquatch'

def unicornify(val):
    return val + ' unicorns'

def getset(name, getting, setting):
    return property(lambda self: getting(getattr(self, name)),
                    lambda self, val: setattr(self, name, setting(val)))

class Foo(object):
    bar = getset('_bar', sasquatchify, unicornify)
    baz = getset('_baz', sasquatchify, unicornify)

或者,只需稍加工作,您就可以使用完整的描述符协议,如agf 的回答中所述。

于 2012-04-13T23:04:03.313 回答
6

这就是描述符协议 property所基于的用途:

class Sasicorn(object):                              
    def __init__(self, attr):                        
        self.attr = "_" + attr                       
    def __get__(self, obj, objtype):                 
        return getattr(obj, self.attr) + ' sasquatch'
    def __set__(self, obj, value):                   
        setattr(obj, self.attr, value + ' unicorns') 

class Foo(object):                                   
    def __init__(self, value = "bar"):               
        self.bar = value                             
        self.baz = "baz"                             
    bar = Sasicorn('bar')                            
    baz = Sasicorn('baz')                            

foo = Foo()                                          
foo2 = Foo('other')                                  
print foo.bar                                        
# prints bar unicorns sasquatch
print foo.baz                                        
# prints baz unicorns sasquatch
print foo2.bar                                       
# prints other unicorns sasquatch

虽然property对于您的玩具示例来说,工厂函数可能很好,但听起来您可能需要对实际用例进行更多控制。

于 2012-04-13T23:11:56.630 回答
5

使用getattributesetattr您可以为过去和未来的所有属性定义它。

class Foo(object):                                                                                                                           

  x = 3 

  def __getattribute__(self, attr):
    return str(object.__getattribute__(self, attr)) + ' sasquatch'

  def __setattr__(self, attr, value):
    object.__setattr__(self, attr, str(value) + ' unicorn')

print Foo.x
f = Foo()
print f.x 
f.y = 4 
print f.y 

这打印:

3
3 sasquatch
4 unicorn sasquatch
于 2014-06-06T18:54:43.420 回答
3

我的一位同事建议使用闭包来返回 getter 和 setter 函数,这是我决定使用的。

class Foo(object):
    def setter(var):
        def set(self, value):
            setattr(self, var, value+' unicorn')
        return set

    def getter(var):
        def get(self):
            return getattr(self, var)+' sasquatch'
        return get

    bar = property(getter('_bar'), setter('_bar'))

f = Foo()
f.foo = 'hi'
print f.foo

但是谢谢大家的回答:)

于 2012-04-14T03:05:56.003 回答
-1
# coding=utf-8
__author__ = 'Ahmed Şeref GÜNEYSU'


class Student(object):
    def __init__(self, **kwargs):
        for k, v in kwargs.iteritems():
            self.__setattr__(k, v)

if __name__ == '__main__':
    o = Student(first_name='Ahmed Şeref', last_name='GÜNEYSU')
    print "{0} {1}".format(o.first_name, o.last_name)
    print o.email

Ahmed Şeref GÜNEYSU
  File "/Users/ahmed/PycharmProjects/sanbox/abstract_classes/object_initializer/__init__.py", line 13, in <module>
    print o.email
AttributeError: 'Student' object has no attribute 'email'

Process finished with exit code 137
于 2015-12-05T18:56:29.100 回答