Re: [Tutor] Question on implmenting __getitem__ on custom classes
On 23/04/19 10:08 PM, Steven D'Aprano wrote: On Tue, Apr 23, 2019 at 08:27:15PM +0530, Arup Rakshit wrote: You probably want: def __init__(self, list=None): if list is None: list = [] self.list = list That is really a new thing to me. I didn't know. Why list=None in the parameter list is different than in the body of __init__ method? Can you elaborate this? Try running this code and see what happens: def make_default(): print("creating a new list") return [] def function(arg=make_default()): arg.append(1) return arg Now call: function() function() function() and see if you can work out what is happening. Hint: how many new lists are created? when are they created? Hello, You are right. I didn't think on it, as it feels to me very natural as per the experiences from other language like Ruby, JS. It works differently there. A similar Ruby code gives different output than Python does. def make_default() print("creating a new list") return [] end def function(arg=make_default()) arg.push(1) return arg end # Now call: p(function()) p(function()) p(function()) And on run: ruby -v sample.rb ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16] creating a new list[1] creating a new list[1] creating a new list[1] But python gives to me: creating a new list [1] [1, 1] [1, 1, 1] Python being an interpreted language works so differently than its other 2 siblings Ruby, JS. Surprised. -- Thanks, Arup Rakshit ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Question on implmenting __getitem__ on custom classes
On Tue, Apr 23, 2019 at 08:27:15PM +0530, Arup Rakshit wrote: > >You probably want: > > > > def __init__(self, list=None): > > if list is None: > > list = [] > > self.list = list > > That is really a new thing to me. I didn't know. Why list=None in the > parameter list is different than in the body of __init__ method? Can you > elaborate this? Try running this code and see what happens: def make_default(): print("creating a new list") return [] def function(arg=make_default()): arg.append(1) return arg Now call: function() function() function() and see if you can work out what is happening. Hint: how many new lists are created? when are they created? -- Steven ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Question on implmenting __getitem__ on custom classes
On 4/23/19 8:57 AM, Arup Rakshit wrote: > On 23/04/19 3:40 PM, Steven D'Aprano wrote: >> Watch out here, you have a mutable default value, that probably doesn't >> work the way you expect. The default value is created ONCE, and then >> shared, so if you do this: >> >> a = MyCustomList() # Use the default list. >> b = MyCustomList() # Shares the same default list! >> a.append(1) >> print(b.list) >> # prints [1] >> >> You probably want: >> >> def __init__(self, list=None): >> if list is None: >> list = [] >> self.list = list > > That is really a new thing to me. I didn't know. Why list=None in the > parameter list is different than in the body of __init__ method? Can you > elaborate this? > It arises because a function definition is an executable statement, run right then. So a default value in the parameter list is created right then, and then used as needed, and if that default is a mutable (list, dictionary, etc) you get surprises. When an empty list is created in the body, it happens each time the function object is called (it's a method, but it's still just a function object). You can write some experiments to show yourself this in action, it usually makes it sink in more than someone telling you. And don't worry, this is one of the most famous of all Python beginner traps, we've all fallen in it. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Question on implmenting __getitem__ on custom classes
On 23/04/19 3:40 PM, Steven D'Aprano wrote: Watch out here, you have a mutable default value, that probably doesn't work the way you expect. The default value is created ONCE, and then shared, so if you do this: a = MyCustomList() # Use the default list. b = MyCustomList() # Shares the same default list! a.append(1) print(b.list) # prints [1] You probably want: def __init__(self, list=None): if list is None: list = [] self.list = list That is really a new thing to me. I didn't know. Why list=None in the parameter list is different than in the body of __init__ method? Can you elaborate this? -- Thanks, Arup Rakshit ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Question on implmenting __getitem__ on custom classes
On Tue, Apr 23, 2019 at 11:46:58AM +0530, Arup Rakshit wrote: > Hi, > > I wrote below 2 classes to explore how __getitem__(self,k) works in > conjuection with list subscriptions. Both code works. Now my questions > which way the community encourages more in Python: if isinstance(key, > slice): or if type(key) == slice: ? In general, we should normally use `isinstance`, because it works with subclasses. But `slice` can't be subclassed: py> class S(slice): ... pass ... Traceback (most recent call last): File "", line 1, in TypeError: type 'slice' is not an acceptable base type so there is no advantage to using `isinstance`. (There is no disadvantage either.) I would use `type(key) is slice` to guarantee[1] that the key is certainly a slice. Why use `is` instead of `==`? The `is` operator will be a tiny bit faster than `==`, but more importantly, you could have a class designed to pretend to be a slice. It isn't easy to do (you would have to write a metaclass, which makes it an advanced technique) but by using `is` we can eliminate even that slim chance. > How should I implement this if I > follow duck typing, because none of the code currently I wrote using > duck typing techiniqe IMO. Why bother? Duck-typing is good for *data* values, but a slice is not a data value, it is a way of specifying a range of indexes. > class MyCustomList: > def __init__(self, list = []): > self.list = list Watch out here, you have a mutable default value, that probably doesn't work the way you expect. The default value is created ONCE, and then shared, so if you do this: a = MyCustomList() # Use the default list. b = MyCustomList() # Shares the same default list! a.append(1) print(b.list) # prints [1] You probably want: def __init__(self, list=None): if list is None: list = [] self.list = list > def __getitem__(self, key): > if isinstance(key, slice): > return self.list[key] > else: > return self.list[key] The "isinstance" check is useless, because you do precisely the same thing in both branches. def __getitem__(self, key): return self.list[key] will do exactly the same, and more efficiently. [1] Not actually a guarantee. -- Steven ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Question on implmenting __getitem__ on custom classes
On 23/04/2019 07:16, Arup Rakshit wrote: > which way the community encourages more in Python: if isinstance(key, > slice): or if type(key) == slice: ? I think isinstance is usually preferred although I confess that I usually forget and use type()... But isinstance covers you for subclasses too. > class MyCustomList: > def __init__(self, list = []): > self.list = list > > def __getitem__(self, key): > if isinstance(key, slice): > return self.list[key] > else: > return self.list[key] The if/else test is meaningless since you return self.list[key] in both cases. You would be better off just calling it directly (and maybe wrapping that in a try block?) def __getitem__(self, key): try: return self.list[key] except : Assuming you can think of something useful to put in the except clause. Otherwise just let Python raise the exception and leave the user of the class to worry about what to do. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor