【发布时间】:2017-04-03 02:30:55
【问题描述】:
我想在 Python 3 中编写一个自定义列表类,就像这个问题 How would I create a custom list class in python? 一样,但与那个问题不同,我想实现 __get__ 和 __set__ 方法。虽然我的类与列表类似,但是这些方法背后隐藏着一些神奇的操作。所以我想使用这个变量,就像我的程序的main 一样(见下文)。我想知道,如何将__get__ 和__set__ 方法(分别为fget 和fset)从Foo 类移动到MyList 类,使其只有一个类。
我当前的解决方案(另外,为了清楚起见,我为每个操作添加了输出):
class MyList:
def __init__(self, data=[]):
print('MyList.__init__')
self._mylist = data
def __getitem__(self, key):
print('MyList.__getitem__')
return self._mylist[key]
def __setitem__(self, key, item):
print('MyList.__setitem__')
self._mylist[key] = item
def __str__(self):
print('MyList.__str__')
return str(self._mylist)
class Foo:
def __init__(self, mylist=[]):
self._mylist = MyList(mylist)
def fget(self):
print('Foo.fget')
return self._mylist
def fset(self, data):
print('Foo.fset')
self._mylist = MyList(data)
mylist = property(fget, fset, None, 'MyList property')
if __name__ == '__main__':
foo = Foo([1, 2, 3])
# >>> MyList.__init__
print(foo.mylist)
# >>> Foo.fget
# >>> MyList.__str__
# >>> [1, 2, 3]
foo.mylist = [1, 2, 3, 4]
# >>> Foo.fset
# >>> MyList.__init__
print(foo.mylist)
# >>> Foo.fget
# >>> MyList.__str__
# >>> [1, 2, 3, 4]
foo.mylist[0] = 0
# >>> Foo.fget
# >>> MyList.__setitem__
print(foo.mylist[0])
# >>> Foo.fget
# >>> MyList.__getitem__
# >>> 0
提前感谢您的帮助。
如何将 __get__ 和 __set__ 方法(分别为 fget 和 fset)从 Foo 类移动到 MyList 类以只有一个类?
UPD:
非常感谢@Blckknght!我试图理解他的回答,这对我来说效果很好!这正是我所需要的。结果,我得到以下代码:
class MyList:
def __init__(self, value=None):
self.name = None
if value is None:
self.value = []
else:
self.value = value
def __set_name__(self, owner, name):
self.name = "_" + name
def __get__(self, instance, owner):
return getattr(instance, self.name)
def __set__(self, instance, value):
setattr(instance, self.name, MyList(value))
def __getitem__(self, key):
return self.value[key]
def __setitem__(self, key, value):
self.value[key] = value
def append(self, value):
self.value.append(value)
def __str__(self):
return str(self.value)
class Foo:
my_list = MyList()
def __init__(self):
self.my_list = [1, 2, 3]
print(type(self.my_list)) # <class '__main__.MyList'>
self.my_list = [4, 5, 6, 7, 8]
print(type(self.my_list)) # <class '__main__.MyList'>
self.my_list[0] = 10
print(type(self.my_list)) # <class '__main__.MyList'>
self.my_list.append(7)
print(type(self.my_list)) # <class '__main__.MyList'>
print(self.my_list) # [10, 5, 6, 7, 8, 7]
foo = Foo()
我不知道,这是否是 Pythonic 方式,但它按我的预期工作。
【问题讨论】:
-
"但与那个问题不同,我想实现
__get__和__set__方法" - 你为什么要这样做?你确定你了解__get__和__set__是什么吗? -
不要问如何使用
__get__和__set__,你能解释一下你想要实现的行为吗?为什么在现有示例中使用__get__和__set__?如果您只是删除Foo并直接使用MyList实例,您希望您的列表类能够做什么? -
@RomanAlexeev:你甚至想象那会做什么?如果你认为你可以做类似
x = MyList([1]); x = [2]的事情,然后让x成为MyList,那么不会。 Python 不是这样工作的。您不能像在 C++ 中那样覆盖赋值运算符。 -
你想要什么还不清楚。你说你想“只有一堂课”,但你也说你想做
foo.mylist = ...。如果没有foo与foo.mylist不同,你显然不能做foo.mylist = ...。那么,如果你“只有一个类”,你想怎么用呢? -
@RomanAlexeev 你不能那样做。
__get__和__set__方法覆盖类/实例属性的分配,而不是作为本地或全局命名空间中的变量。
标签: python python-3.x oop