Author | Message |
---|---|
rabbott
Posts: 1649
|
Posted 20:38 Jan 25, 2019 |
Kevin Marlis asks this question. This is from the code for Hearts in Hjelle's Type tutorial. (The full code is here.) This is a method in
def __getitem__(self, key: Union[int, slice]) -> Union[Card, "Deck"]:
When the key is an instance of Last edited by rabbott at
20:40 Jan 25, 2019.
|
rabbott
Posts: 1649
|
Posted 20:48 Jan 25, 2019 |
The key is that a The line What is returned is a In other words, this retrieves a slice of the Last edited by rabbott at
20:53 Jan 25, 2019.
|
kmarlis
Posts: 35
|
Posted 13:25 Jan 26, 2019 |
The return statement makes sense to me, the type annotations are really helpful with that. Is the cls of Deck initially Sequence, as far as typing is concerned? I think that is where my confusion is. |
jpatel77
Posts: 44
|
Posted 14:34 Jan 26, 2019 |
The class Deck inherits from Sequence of Cards. Therefore, Desk is a Sequence of Cards, with some added functionalities like play, deal, add_card (essentially everything that is defined in the class def of Deck) that are not available to the normal Sequence[Card] class/object. If you remove everything from the class def of Deck, it is just as good as the Sequence[Card]. And so, yes you can say Desk is a Sequence of Cards (all the time; not just initially) but not the other way around. That is how I understand it. Last edited by jpatel77 at
14:34 Jan 26, 2019.
|
kmarlis
Posts: 35
|
Posted 14:49 Jan 26, 2019 |
Right, I understand that, but I'm still not sure why the cls = self.__class__ line is needed. Isn't cls already Deck without the need to call for self.__class__? |
jpatel77
Posts: 44
|
Posted 15:01 Jan 26, 2019 |
Oh I see what you're saying. Actually it is a clever way to avoid hard-coded initialization. cls(self.cards[key]) actually creates a new object of Deck, equivalent to the statement Deck(self.cards[key]) , however, to avoid explicitly stating the class name Deck, he fetched it from self.__class___ . Because if Deck is renamed to something else, or some other class inherits from Deck and object of that class invokes __getitem__ then it should create an instance of appropriate class. I am pretty sure that is why he did this, however I would really want others to comment on that. Last edited by jpatel77 at
15:01 Jan 26, 2019.
|
rabbott
Posts: 1649
|
Posted 15:05 Jan 26, 2019 |
cls is just a local variable. It has no default value. Since we know we are in a Deck object, we could have skipped that line and used Deck in the next line instead of cls. |
rabbott
Posts: 1649
|
Posted 15:07 Jan 26, 2019 |
Just read Jay's comment. Makes sense as a way to be extra cautious. |
kmarlis
Posts: 35
|
Posted 15:11 Jan 26, 2019 |
Ah okay, that makes sense. I couldn't find anything else explicitly declaring cls in that way before using cls() to create a new instance, and couldn't think of why it would be necessary, but that is pretty clever (and very forward thinking in a way that I wasn't expecting). Thanks for clarifying! |
rabbott
Posts: 1649
|
Posted 16:06 Jan 26, 2019 |
This discussion is going on for quite a while, but ... we can make a teaching moment out of it. One can make a good case for the One of the basic principles of good programming style is known as DRY (Don't repeat yourself). Suppose you have some code that does a computation and you find that you need that same computation elsewhere in your program. You might be tempted to copy and paste the code. But that's bad style -- and marks whoever does it as a poor programmer. Instead of copying and pasting, extract the code and make, e.g., a function out of it. Then refer to that function from both places where you need that computation. The reason not to copy and paste is so that if you ever need to change the code, you won't have to remember to change it everywhere you copied it. Consider these two versions of the portion of the code in question.
The problem with the second version is that it results from copying and pasting Writng the code as Hjelle did respects DRY because it refers to the class name rather than copying it. Since Hjelle is a strong coder and cares about the quality of his code, he may have decided that not violating DRY, even in a minor case like this, was worth the extra line. One can also make a good case against the The second version of the code is simpler and easier to understand than the original. One of the principles of writing Pythonic code is to write code that is simple and easy to understand. So the code that Hjelle wrote is not as Pythonic as it might be. How should the conflict between these principles be resolved in this case? You tell me. Last edited by rabbott at
20:21 Jan 26, 2019.
|
kmarlis
Posts: 35
|
Posted 13:13 Jan 27, 2019 |
I just realized what was tripping me up, and it is a pretty obvious mistake on my part. __getitem__() is passed self, not cls as an argument. For some reason I kept seeing that first argument as cls. Whoops! |