 All right, can you hear me? Okay, so I'm sure you're all familiar with the operators in Python Not all of them are as interesting as some of the others, but the most interesting one of all is the smallest So hello, I'm Peter and I'll be diving into the depths of the dot operator Now as you know, Python has a giant standard library Where the dot is sort of the path separator? So you have some parent module and you get some child out of it Now this is a different use of the dot than I'll be speaking about but it It's a case where the dot does some kind of namespacing So what I will be talking about is Attribute access so the three things you can do with the dot is set an attribute on an object Get an attribute out of an object and delete the attribute the syntax. I hope you all know Now these are some of the most optimized operations in Python, so it's very good to use them But you always know have to know the name of the attribute you're getting if you don't know it You can use the built-in functions set adder get adder and the ladder Which actually do the exact same thing just a bit slower now to understand what the dot does we'll Introduce this very simple approximation of what an object is in Python So if you have an object it has a type which doesn't change very often And it defines the behavior of the object and then you have the dict Which contains all the data specific to that one instance and that's expected to change quite a lot Of course, there are always exceptions, but we'll go with this simple model now as an example I have some class square. I Define a method on it that gets put in the type and Then when I define an attribute on an instance of that object the attribute goes in the dict and the dict is under the hood Just a simple dictionary In Python 3. It's more than a simple dictionary, but it acts like one and Then when I want to get the attribute out I just use the dot again and Python looks in the dict and If it doesn't find the attribute in the dict then it looks on the type So I can also get the get area method, which is not not in the instance dict So here are the simple rules when you set an attribute it goes directly to the dict when you get the attribute a You try in the dict then you try the type and if it's not there then Fail And most of the stock will be about how to make this work somehow differently so the first thing you can do to override this behavior is To put a special get at her method on the type What this does is it hooks into step three here and instead of failing right away This function get called and gets called and whatever it returns gets returned as the value of the attribute So this simple class just proxies all attribute access to some other object This works. It has some limitations. For example, it won't It won't work on attributes that are already in the dict So you if you ask for underscore object here, which is already said there The get out it won't be called Now there's another method you can do which is get attribute. It has a longer name And it's more powerful. This one actually takes over the whole attribute getting process so It's a bit more difficult to use because if there's any attribute you already have on the object you have to Make a special case for it. Otherwise you can do anything you want in this function and it'll work Now That's getting attributes. There's one more thing you want to do and that's setting them and For that we can have Set out of method So what this class will do is it keeps the dictionary When you try to get an attribute from the object, it looks in the dictionary and returns Whatever it finds and if you want to set an attribute It also looks in the dictionary and Well, it's since the attribute on the dictionary as you can see I'm special casing the dict Because I'm setting the dict here, and I don't want to Set the dict that's you know use the dict. That's not set already we also have the delater which does Deleting attributes, so it's it's the same Did you have time to read it? I guess most of you are looking at me. So, uh, yeah The question is do any of these hooks run during in it? They run every time you set an attribute in Python. So if the in it has attribute setting then yeah And it there's just a function that gets called on the beginning. It's there's nothing too special about in it So yeah, I have to special special case this for the setting here in the unit now if you ever Find yourself writing something like this thing twice Because the attribute namespace is not entirely under your control you have attributes like Dunder anything You'll inevitably want to add some methods to your class. You'll want to Enable subclasses to add new attributes. So Usually when you have something like a dictionary stick to a dictionary interface and don't mess around with attributes Otherwise, you'll run into trouble pretty fast Uh Yeah, so, uh, I Haven't seen this many times actually because this sort of blanket Overriding of getting and setting attributes is not that useful Usually what you want to do is you have one attribute that needs some kind of special treatment Or you have several but each one is special in its own way So if you did the get adder you would have a nasty tree of ifs and It's it's not very nice So for this python has a very special feature called these scriptures now what descriptors do is You put a special object in the type Which will control access to the specified attributes So if I have some kind of square and I wanted to have an area I put some kind of magic special object Into the class and when I set the side The and then I look at the area attribute This descriptor will Take the side the this five here square it and give it that give that back This is pretty easy to implement the descriptor object only needs one method, which is get So double underscores get What this method to gets is the instance so that would be the square here and if the instance is set it Can return the value of the attribute if the instance is not set that means we're getting the attribute from the class itself, so that's the Usage on the bottom here and what most well behaved descriptors do is return the descriptor itself so we can use it for some other reasons Sorry, okay. Is that clear you just have special object to control access to an attribute Now what this object can also do is control setting So if you use a method called set It gets the instance and the value the user is trying to set and it's free to do anything at once in my case We want to update the side because the user set an area to something so we can Update the side to match. So anybody having trouble reading that Okay, and the last thing there is is delete The short Dell was already taken so it's longer This one isn't that useful because you don't find yourself deleting attributes all that often but for completeness. It's there Now a bit of terminology When a descriptor has this set method, it's called a data descriptor if it does not it's called a non-data descriptor This is this this set means that Pretty much you want to control all access to the attribute if you only have get you were just You're just getting that out if you have set Means there's some data you presumably want to store in that attribute So that's why it called the data descriptor Now, how many of you know the property decorator? Almost everyone. Yeah, so as you can see I've pretty much Gone the long way to do something like the property decorator and in fact The property decorator all it does is create a descriptor can actually Implement property in pure Python as a descriptor. You know, you just give it three functions and call them in the appropriate special methods and I have Example here, so I have a set area get area del area give these three functions to the property and Put that in area You can actually call the built-in property like this and it'll do the right thing if you add some more Sugar to this class then you can really re-implement all of the mechanics of the property And again this has set so it's a data descriptor Okay Yeah, so Python actually likes descriptors very much and Anytime there's something special to do on attribute access. You have a descriptor For example, if you look at a simple function If you look at the attributes it has one of them is get because functions themselves are descriptors When you have a function on a class Then and then you have an instance of that class. You want to get the function. You don't get the function back You get a method get an object that has the function itself and the self argument baked in right, so Here's a very simple class with a very simple function and when you get the when you get the attribute from An instance of that class you get a bound method if you call that it automatically provides the self argument and If you get a line from the class it gives you the original decorator Or the original function As I said most well behaved descriptors return themselves when you get them from a class in Python 2 you would get something called an unbound method Which Doesn't really do anything that useful, but it's there Now they sort of fixed it so it's just gets the the function back now if you look closely to the For this descriptor with we had it Yeah, it works pretty much the same way That's something special when you get the thing from the instance when you get it from the class It returns the descriptor itself right another thing I want to talk about is This little trick for saving memory if I had a point class and I had millions of these objects around I wouldn't want Each of them to have this dict attribute which as I said is a normal dick So it takes up memory and I know that in a point I'll only ever have an X number and a Y number and nothing else so What this special magic incantation will do is it will actually Make the type not have a dict attribute It'll have the type and it'll have directly the X and Y in the C object itself So there will be no dictionary and it'll save the memory You can of course set and get the X and Y attributes, but you cannot set anything else because there's no space In the object for anything extra All right, and if you try to get X from the class You get this descriptor So every every time there's some special attribute Python implements it with a descriptor Right, and I think now is the time to give you the whole magic formula So this is the way an attribute is gotten from an instance first You try get attribute if there is sketch attribute You just call it and get it back if it make if it throws an error The error is raised If there's no get attribute you look up The attribute on the class and if it is a data descriptor Then you call it's get method and return that Only after that only after looking for the data descriptor the dict is checked so The value is gotten directly from from the instance attributes This doesn't call any descriptors. You just get the value straight back After that you check the non-data descriptor Well, or you check if the descriptor is non-data if that's the case Then you call that if it's not a descriptor at all if it doesn't have the gender get method then you just return it directly so if on the class I have some value like You know and a class attribute constant for example, it's just returned directly After that you fall back to get at her and if that is also not there then attribute error is raised Now there are there is this weird thing about the data descriptor and non-data descriptor being in two different places What this allows is if you have a data descriptor it pretty much controls all the access to the attribute so What the Python designers thought is that if you define both get and set then you probably want to Control the access to that attribute yourself All right, if you don't define the set then you're free to override that attribute in the instance so you can put something in the dict and Then Since it's an odd data descriptor you will get get it back from the dick before the descriptors chain Right. There's a one nice use of it in the pyramid framework It's called reify some other frameworks called cached property. I've called I've heard it called lazy property What this does is you give it a function and then when you get the corresponding attribute The function is called and then the attribute set with the value You've computed so it calls the function puts the result in the in the dict and Whenever you get the attribute again, it doesn't call the function again. It doesn't go to the descriptor just returns the cached value from the dict so this is a way if you Yeah, if you want to implement a lazy property there's some discussion about adding this to the standard library and Yeah, so maybe we'll see it's under some name Is there anyone who doesn't understand Excuse me if you want to invalidate this you just remove it from the dict yet you just delete the attribute Yeah, and the magic is that you can just Set the attribute normally now if you would know the name in advance This would literally be instance dot name equals value and the setting is not affected at all with with this descriptor, so if you want to change the value in the dict you just do it Normally the only thing that's different is getting and That's only when it's not already in the dict the questions on this Yeah I'm not finished Yeah, yeah, if you have a general question then Then just wait Okay So another thing about this magic formula is this on class which I put in italics because it's not as Easy as it looks Because looking up something on the class of instance, it's not an actual attribute access. It's a bit different and It has to do with something called the method resolution order so if you have a class and you have a subclass of it you can Check for the method resolution order and it gives you the child the parent and the object Now when you look something up in the class it goes through the classes in this order So the attribute would be defined on child. It would Be returned from the child if it's not on the child Python looks in parent if it's not there Python looks in the universal superclass Now if you have some kind of weird Hierarchy of classes with multiple inheritance and stuff like that. There's an algorithm called. I think C2 Which you can look up. There's which converts this hierarchy to just a list. That's checked Linearly One more thing about this MRO It's actually an attribute defined on the meta class, I don't know if you're familiar with that, but it's defined on on the on the type meta class and If you have an instance of the object, it doesn't show up because If you have an instance you only check the instance itself and its class. It's not its meta class So this is maybe a useful way to hide Things from instances if you need them on the type you just put it in the meta class And if you don't know what meta classes are, I'm sorry, but I don't really have time to explain it Hey, that's it Time for questions Okay, thanks to Peter and we have Almost eight minutes for questions. So please raise your hand and I will come with a microphone Hi, thank you very much for the insights. It's really really interesting and one thing I actually saw Which was quite Quite interesting was the slots The slots attribute. How would you compare this to name tuple and What are the I understand what the advantages are compared to to name tuple, but then why do we need name tuple? Name tuple is actually used a bit differently. The name tuple is immutable That's the first thing and the second thing of name tuple has order in the attributes so you can actually use it as a tuple Here you don't don't have order. So Use whatever makes sense in your case right if if I wanted to add For example an iterator on this or make this an iterator I couldn't really do that with name tuple since that's already an iterator Can I return data descriptor for example Like from get attribute method. Excuse me. Can I return data this descriptor from Get attribute method Well, you can return it, but it won't the get method won't be called you can actually call the get method yourself That's that's not a problem, but it won't be called If you just return it Okay, any any more questions What there's one This Sorry the site that you implemented there with the area descriptor Could perhaps just as easily or possibly even clean early be implemented using the straight properties in that It's it's then in line in one spot, and it's easy to find What what real-world examples do you have of where descriptors are actually useful in code that if they add more than they They take I've had that I've just seen them used before where Effectively they could have been implemented in other ways But now that the descriptor class because it was separate it involved a lot more jumping around the code to try and follow the logic What was going on? Yeah, if you just have a simple case like I have here It is better to use property if you can One thing I took from this slide from the talk because of time reasons is actually examples of more complex descriptors If you have an ORM like say sequel alchemy that uses descriptors a lot And it's because the descriptor is a class in itself So it can have other behavior than just getting and setting or just controlling attribute access For example in sequel alchemy You can You can do operations with the descriptor which is a column on the database and it will generate sequel statements Right and if well if you use it on the class it generates the sequel statements if you use it on its instance It gets the data of that column right, so there are Yeah, in simple cases, it's better just to use property Which is also a descriptor it's just a simple one in complex when you need some more state or functionality built into the descriptor than Use a class and you can when you have several diff several related Attributes like that you can just create Descriptor class and reuse it But yeah, I I agree that the code is not As readable as it could be when you use descriptors because there's one more place you have to check but It's magic use it wisely And I think this was the perfect conclusion for this talk. Thanks again Peter