 It's helped you understand something that when I came to Python, really quite confused me. I mean, Python is a really cool language, easy to learn, but then you hit certain brick walls I find and you look at the documentation and you read the individual words and sentences and they sort of make sense and they try and use them. It doesn't work. And I found this with the dots because it led into all sorts of discussions with get atter and get attribute and data descriptors and stuff like that and it confused me. Now, I'm a technical trainer so my challenge is when I teach languages like Python is to try and simplify. Take these points and now for beginners give them a good starting point. I guess the organizer of the conference must have thought this was quite important because they've given you two talks on this. I don't know if you realize. If you look at the speaker after me, Andy Fundinger, he's talking on pretty much the same thing. So either it was a mark of genius or it was a big mistake. We'll assume it's genius. So Andy and I fortunately were in the building on Friday so we've actually got together and I'm really the warm up guy for Andy Fundinger so hopefully you get both. So I'll set the scene and Andy will be adding some other stuff here. Also my name is Gordon Macquarie. It's actually misspelled. I don't know why it's the first time I've seen this misspelled. If you're going to send any checks, you want to get the spelling right after the call so that's the spelling. Gordon, not Gordon, Gandon. Let me give you a look at my background. First of all, I'm old. I'm old. I used to work. My first job was a junior programmer and a cobalt compiler, worked my way through some academic stuff and then got into embedded software where the operating system was two kilobytes. So some of the micro-python stuff, three kilobytes. Then I got customer-facing through technical marketing and then laterally with technical training. So I'm a freelance technical trainer, which is a really fun job because you don't got all the bad things that engineers have got to do like document and test and have a manager to go and do another project. You get to choose your own stuff. And I've used many computer languages and I find Python the most agreeable but the most fun is actually Perl. I'll explain why Perl is actually more fun. And I have a number of heroes who really motivate my teaching in this talk and I like simplifiers. I like someone who gives a talk and takes something fairly complex and reduces the dance so you really understand what's going on and these are the people I look up to. We do obviously for a beautiful language but if you're new to Python, David Beasley and Raymond Hettinger are great simplifiers. They take fairly complex stuff and present them away. They simplifies and if you're going to the standard library, Doug Hellman is your man, Python module of the week. So my objective today is that you understand to a large degree what the dot operator does so you can use it for your use and to simplify it. So what I'm going to give you is a simplification. One of the rules of training which is training is lying but good lies. Unlike politics, where lying is mentally bad. So I abstract away some stuff and also what motivates me are use cases. So I'm going to give you some examples of use. Normally in a training course I would actually live code them. I'm not going to live code them, I've previously typed them in but if you've got a laptop available and you want to try some of them so I want to simplify them down to the most basic of all of these. And good explanation I think comes from visualization, not just graphs but good diagrams. And normally I would hate flowcharts but I came across this flowchart from a colleague of mine and I adapted the flowchart and I'm going to use this in this discussion. So what we're addressing is you have a plain old class. Imagine just pass, not an ordinary class. A plain old object, lowercase a, nothing special. And you want to do a read access. So what we're addressing is the read access after the dot. So I'd like to address two things. The first thing is when you do a print on an object, many people get very confused with the scoping rules in Python. So this is before the dot and I don't know if you come across this. This is quite a useful rule which you may have come across which is this guy. Anyone heard of this? This explains what happens when you do a print before the dot. Because it says it looks locally in the function for the variable, looks in the closing functions, looks in the module, and looks at built-ins. That's it. That's pretty much it. There's no for scope, no while scope, and people get confused. And that's before we get to the dot. So before the dot, it's pretty easy. And if you want a mnemonic, it's like before wicket and cricket. So then we come after the dot, and this is for read access. And this explains, it's a simplification, but I think it's for most people, a good simplification. Because you have a flow chart. And what Python does is it has the class from which you come from got get attribute or any base class. And if it has, you get to call it. And that's one hook, but if you look at the very bottom to confuse you, there's also something called get atta. And that really confused me, why are the two of them? What did they give me? Well, that one at the top doesn't give you a great deal, although I think Andy's going to give some useful use cases. And the one at the bottom is probably more useful for you. So I'm going to talk about these. And in the flow chart, so if you haven't over in get attribute, which initially you wouldn't, if you weren't aware of what it was, you wouldn't do it, then what it does is, Python then looks, confusingly, initially to the class. So it looks initially, so it's your attribute, but it's going to the class. That's kind of odd. Why is it going to the class? And that's because there's a hook which allows us to do all sorts of stuff you might be doing implicitly. So I'm going to explain what takes you here. But if you don't know about it, then clearly, you wouldn't be using this. And then we move down and we hit where most of you would normally go. So the dictionary, every object's got a dictionary, a function's got a dictionary, an object's got a dictionary, and that's where your attributes are. And if you had to type an underscore date to get it, you wouldn't use Python, because the underscore ones are meant to be used implicitly. So when we type a.x, that's what we get most of the time. Then, however, the confusing thing is that if it's not in the dictionary, in other words, if a.x does not exist, this guy does not exist, having traverse down here, it then goes back to the class dictionary. So you can see there's two positions. It goes to the class dictionary. Well, that's a bit odd. Why is it going twice? And it's going twice, because the top one is a tougher test. This is an and condition. So whatever's here in the class, which is me, has to conform to a protocol. It has to be of a type. And if it is a type, some magic happens. And if it doesn't happen, then it goes to the class and returns it. And then it keeps falling through. And if none of these tests are true, then what it will do is it will get at her. And if that doesn't exist, then it raises that. So that's a summary of what you have. So let's assume that the attribute x does exist. From a.x, it does exist. It is there. Then this is the hotspot. So this diagram's got two hotspots. When x exists, obviously, you have not done that. You haven't done that. You're here. And that's the hotspot. So that's where most of you, through your Python career and most Python programmers, that's what they hid as they run this. However, if you mistype and you print a.y, which does not exist, then the second hotspot is down the bottom. So that's probably where, in your Python career, certainly when you started, that's where you were. These were the two hotspots in the diagram. Also in this diagram, I'm going to describe the middle one as a kind of pivot. In fact, this will lead into discussion of the get atter and these guys here. Because very often, these people are manipulating the dictionary. Quite often, they are wrappers around the dictionary, giving you some extra behavior. So a lot of the implementations will refer to this. Maybe pivot's not quite the right word, but this is going to be used quite a lot in the examples. So the first thing, perhaps, we're going to look at some code now. And what I'd like to address is class variables. So where you've got an x with the class, as well as an x with the object. And if you do that, it will traverse down here. It will find it clearly in the class, because the next will be in the class dictionary. But because it's not a descriptor, does not support the appropriate hooks, then it will come down here. And that explains why you can get to class variables through objects. So what I'm going to do is just quickly project this example. So we have a simple class. We give it an attribute. We have an object of the class. We do print a.x and we do print a.x with lowercase. And if you put this together and run it, you'll find that, in both cases, you get 100. So that's the explanation. That's why we get this from the flow chart. And if you go back to the PowerPoints, I'd now like to address. So the class one is OK. And in most programming languages, you can get to class variables through objects. This is why we get it in Python. But then what I'd like to address is what these guys give you. So I'm saying there's two gets here. And this was probably my first confusion. Why is there get attribute and why is there gets? Well, the guy at the top is probably not as important to us as the guy at the bottom. So what I'd like to do is show you a little bit of code for this with a simplification of get attribute. So we have a class here. We've decided to implement get attribute. We've got a simple object here. And then we print a bunch of attributes that don't exist. Clearly, that's not terribly useful. So with the get attribute hook, what this means is that this method gets both the object and the attribute we're dealing with. In this case, I just unconditionally returned 42. And there's no terrible value here to have the good value for this. Well, let me just run the code and you'll see what happens. And in each case, we get x, y, z. Like this. Let me modify this a little bit. No, I don't have this example. I can't see it. So what I'm going to do is go to the get atter at the bottom. So let me run again. And let me show you a couple of things with get atter. So with get atter, we have some interesting opportunities. Now, do you remember the pivot? Do you remember the dictionary? What we get here with get atter is if you hit an attribute that does not exist, let's say meaning of life. So you've got a class. There's no attribute meaning of life. And then we do a read access. In fact, we read it twice. We read it twice. And what happens is because we've implemented get atter, it works its way all the way down the tests, gets to the bottom, and then we have the opportunity of caching. So one advantage of this approach is that if you've got something that takes a long time to calculate, you can take the hit one because it could be a database access. It could be anything. In this case, it's calculating the meaning of life. You may know from the Hitchcock as a guy. Galaxy takes thousands of years to get the meaning of life. And then you get the meaning of life. And then you say, what was the original question? So what I've done is I've got something that takes quite a long time. And we're testing here to see if it is the meaning of life. We can take different behaviors and different attributes. And we make the call. And we take the hit. And this will take a number of seconds. In this case, two seconds. And we make that as our return value. And for the other attributes, we just give an error message. So the advantage of this is the pivot point in the middle now has got the meaning of life. You've got caching behavior. So we'll see this because in the two prints at the bottom, you'll see the first one is going to take a certain length of time. In this case, two seconds. It takes a little while. But let's just run this again. So the first one will take the hit. That's the delay. That's the delay. And the second one was instantaneous. So one advantage of this hook is that we now have a caching behavior, which is really useful. Now, I mentioned Perl a little bit earlier. There is another sort of use case for this, which I'm going to call auto-vivify. Any Perl programmers among us? It's a bit like admitting you're Alcoholics Anonymous. I'm a Reformed Perl programmer. Ex-Perl programmer. Ex-Perl programmer. The Perl guys, I was with Perl for a while. And you may know that Perl's got something called auto-vivivification. Anyone here have the term auto-vivivification? Bring to life a variable. So this doesn't make a lot of sense in Python. But we can supply it. We can supply it. So what we have here is we have a class, a simple class, no initializer. So there's no attributes appearing. We have the object. And then we print what's going to appear. We're going to make this attribute appear with a default value. We choose the default value. In this case, I'm going to choose 0. And that's not terribly useful in its own. But in something like a Perl program, it would be quite useful to actually have on the fly the creation of the variable. And that's what's going to happen here. So when I run this code, you'll see that the variable new now exists. Well, you don't see it exist. You see a value of 0. You've also got a value of 4. But what we've done is we've gone to what I've called this middle pivot point to get that. So you've got auto-vivivification. I'm not saying this is a fantastic use case, but you can see that most of what happens down here reflects back on the dictionary. That could be for caching. It could be for bringing something into life for optimization purposes. So get at her does some pretty decent use cases. So again, if I go back to the diagram here like this, although I didn't have the follow up one for the one at the top, I was really going to say I'm not going to use this much. I think Andy could actually spend a little bit of time on a use case here. My main use cases would come here. So in terms of this, what do we know? I'm not going to use this very much. Most people don't. Some people say, shouldn't you have been exposed? This is kind of useful, but usually to bring things into life so that the next time down, you do not go all the way down. That's how the caching work. You have to take the hit here. But once you make the attribute exists, it's preempted on the way down. And there's all sorts of interesting stuff you can do here. We know about class values. So from objects, we can get to the class guy. And the last one to address is this one. This is where the class itself gets control over all the read, write, and delete access of objects. And this is done through having for the, so if the client wants to use x, you put the same attribute into the class. So an example probably is useful for this. So if I put up an example on that. So the first one I'm going to put up is what I called gatekeeper. So what we have is a bunch of objects, a1 and a2. And these objects want to do with x. So they have x, and they have their own x. Each one will have their own x. And they want to do things like reading and writing. So in the down the bottom, a1 is doing a read and is also doing a write. But to get the effect of the protocol, what we have to do is duplicate exactly the same name. So that's what we have here. And it's essentially a gatekeeper. So when we have this object produced, we have complete control over the getting, setting, and deleting behavior. We do not have to implement all of them. But there's some subtleties which Andy will go into. If you just do the get, you get a different behavior from having get and set. The most simple one to understand is if you have get and set because you're just doing with data access. Andy, I think, will go into another example. And if you do not implement the delete, it is denied. So if I try to delete the attributes, then this would fail. So to see this running, you'll see that we do have the get and set will get called. And we can see the setting is called multiple times, partly because we do it in the constructor. And we also do it further down. And we also do reading. And I've just unconditionally returned RV, because I'm not doing anything terribly useful here at the moment. This is just to show you're actually calling these particular things. So to get a more useful use case, we might want to add to that. And to add to that, then we might want to do things like type check it. In fact, let me not use this particular one. This is using the decorator. So before we go to the decorator, what I'm going to do is take, in fact, I'm almost straight to the decorator in the time. So we can manually assign these, set up these methods. But you may be aware that Python gives us a way of doing this, which hides the details. And we have the property decorator. The property decorator is actually a class. It's called as a function here. It's a callable thing. It is actually a class. It can be used in a variety of ways. And this is probably one of the simpler ways. So this abstracts away. You notice we don't have a separate class now. Remember there was the gatekeeper guy where we had to do the gets and sets. So with this guy, we do not have to do this, because property is a class. It does the work for us. But we have to express to it what control we want. Do we want the getting? Do we want the setting? And do we want the deleting? And you only get something called a data descriptor. So you don't have to worry about, do, do, do the get and the set. So now you've got control over the getting. You've also got control over the setting. The setting now is disallowed, and the deletion is also disallowed. But the complication is now that we have to introduce a shadow variable, because you'll notice that we have the underscore x. And as you know, in Python, a leading underscore means it's kind of hidden, or should be. We shouldn't touch it. But there's no control over this. So if someone really wants to go to this attribute, they can. And that's quite nice. So now what we have is a read-only attribute. And we can do whatever we want. We've got the simplicity. We don't need a separate class. So that's one use case. And then maybe we'll look at another use case with this, where we have computed attributes. So another opportunity that we have here, and I've shown this, this is a simplification of a bank account class that I normally use in the class. So imagine you have a bank account and you have transactions. And the use case here is that the client wants to use a balance attribute. And we start off with the balance attribute. So we have the conventional balance attribute you'd expect for a bank account. We add to this a transaction capability. So we know the deposits and withdrawals. But now we've got redundancy, because if you've got a balance attribute and you've got all the transactions, you don't need the balance attribute. You might choose to keep it for efficiency reasons, but that's entirely your choice. But in this example, I'm showing that we do not have anywhere a balance attribute. We do not have an underscore balance attribute. We simply have the ability from the client's viewpoint to use the attribute, but then we make it work for them. So the client comes along, and they do deposits. They do withdrawals. And when they do deposits and withdrawals, then all that happens is that this gets bigger and bigger. We do not need the balance attribute. And then the client needs to put up. Part of the API is the balance attribute. So the client uses it. And of course, they expect this should give us something quite useful. When we do it, it gives us hopefully the correct result, because we're depositing 110 and we're doing this. And if we want to look at a1, we can go and look at its dictionary, which is the self guy. And you'll see that you have the attribute transactions, and you have the list, and there's no balance attribute. In fact, could we combine this, do you think, and actually make the balance attribute exist dynamically? Remember the pivot point? We could actually, if we wanted to, assuming we were aware of staleness on data, we could actually add the attribute. So the purpose of my talk, really, is to introduce this diagram, which hopefully will give you a handle on what's going on, to give you motivation for the different use cases. So in terms of the use cases, the moment I haven't really talked about this, Andy will talk about this. So if you want to come back, Andy will give you some more information. This is a simplification, Andy is going to drill down a little bit more in certain areas. This is the real advantage, I think, the real advantage here, and you've got the decorator to do this for you, but some people prefer to write a class, because all you have to do is implement the right methods, and some people like the visibility of that, and it can be copied. This is your hotspot. This is your other hotspot, and this can be used for auto-vivification, and I think so. That was a great talk. I learned some stuff. All right, so you have five minutes. If you want to go upstairs to the 1 in 7, or stay here, the next talk will be by Neil Turbitt on, I'm sorry. What? Oh, OK. Next.