Python: универсальные получатели и сеттеры
TL; DR: необходимо определить уникальный набор геттеров и сеттеров для каждого свойства() 'd variable sucks. Могу ли я определить общие геттеры и сеттеры и использовать их с любой переменной, которую я хочу?
Скажем, я делаю класс с некоторыми хорошими геттерами и сеттерами:
class Foo
def getter(self):
return _bar+' sasquatch'
def setter(self, value):
_bar = value+' unicorns'
bar = property(getter, setter)
Довольно здорово, правда?
Теперь позвольте сказать, что я ввел другую переменную под названием "baz", и я не хочу, чтобы ее не оставляли в стороне от этой забавы sasquatch/unicorn. Ну, я думаю, я мог бы сделать еще один набор геттеров и сеттеров:
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)
Но это не очень СУХОЙ и бесполезно загромождает мой код. Думаю, я мог бы сделать это немного DRYer:
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)
Хотя это может сделать мой код DRYer, он не идеален. Если бы я хотел unicornify и sasquatchify еще две переменные, мне пришлось бы добавить еще четыре функции!
Должен быть лучший способ сделать это. Могу ли я использовать один общий приемник и/или сеттер для нескольких переменных?
Без единой и безсмысленной реализации реального мира: Я использую ORM SQLAlchemy и хочу преобразовать некоторые данные при их хранении и извлечении из базы данных. Некоторые из преобразований применимы к нескольким переменным, и я не хочу загромождать свои классы с помощью геттеров и сеттеров.
Ответы
Ответ 1
Как насчет просто:
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 answer.
Ответ 2
Это то, что протокол дескриптора 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
в функции factory может быть прекрасной для вашего примера с игрушкой, это звучит, как будто вам нужно больше контроля для вашего реального использования.
Ответ 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
Но спасибо всем за ваши ответы:)
Ответ 4
Используя getattribute и setattr, вы может определить это для всех атрибутов прошлого и будущего.
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
Ответ 5
# 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