I would like to write a custom list class in Python 3 like in this question How would I create a custom list class in python?, but unlike that question I would like to implement __get__
and __set__
methods. Although my class is similar to the list, but there are some magic operations hidden behind these methods. And so I would like to work with this variable like with list, like in main
of my program (see below). I would like to know, how to move __get__
and __set__
methods (fget
and fset
respectively) from Foo
class to MyList
class to have only one class.
My current solution (also, I added output for each operation for clarity):
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
Thank you in advance for any help.
How to move __get__
and __set__
methods (fget and fset respectively) from Foo class to MyList class to have only one class?
UPD:
Thanks a lot to @Blckknght! I tried to understand his answer and it works very well for me! It's exactly what I needed. As a result, I get the following code:
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()
I don't know, that's Pythonic way or not, but it works as I expected.