"JavaScript classes for the Python Programmer" - Curtis Maloney (PyCon AU 2023)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign who will be speaking to us about JavaScript classes for the python programmer over to you [Applause] good afternoon I'm going to be spending a lot of time standing this way because those lights are quite aggressive um thank you just a quick introduction of who I am I've been working with python for about 25 odd years I've been working with Django for about 16 years long enough that they um they actually invited me onto the core team at some point and I'm here with many thanks to my employer who is the reason I've had to do the investigations that led to me coming to the realization this content needed to be shared I'm going to cover a lot of the differences and similarities between how classes and objects work in JavaScript versus python because that helps us all especially those of us who work in the web space let's start off with some very basic fundamentals in Python we have explicit classes you say class you create name you define your class in there it is in JavaScript it's a little more subtle every object can be thought of as a class pretty much when it comes to scoping in Python we have self and that is explicitly passed in to your methods it's injected for you you don't have to remember it's just attached and this is done I discovered a couple of years ago using the descriptor protocol so anyone who's familiar with at property the same functionality in classes that lets that work is how functions know to inject self when they're called as part of a class in JavaScript it's a little different what happens is you have it this object which is the scope from which you were called if you are called via looking up another object then that object is your this you can actually um play with that and lose that if you're not careful when passing functions around in Python we can actually trick python into injecting a different this or a different class as around and we can call a method on another class without this by actually calling the cost method not the instance method on JavaScript they have this thing called bind which is a method on every function so you can say when this gets called I want this object that I'm passing to you now to be my scope to be my this next is Properties or attributes on our objects in Python every instance has a type which is its class and when you look up a property that doesn't exist on your instance python will then go look it up on your class and then its parent clause and so on and so on until we reach object at which point we say oh you haven't got one in JavaScript okay I've got my fragments out of order here we do we can in Python actually test if there is a direct attribute on our class by looking at the dunder dict of the class to say if this name is in there then it has that on itself it's not inheriting it oh in JavaScript every object has a prototype just one when you look up the property it doesn't exist on your current instance or your current object JavaScript will go and look at the Prototype and then they'll prototypes prototype and so on and so on until you reach the null object or there's no more prototypes to go up to so it's very similar in way to the pythons climbing up the tree except it's directly on your object rather than the type of your object additionally in similar allergy we can ask the object class itself and they provide us a static method to say hey does this object actually have its own instance its own attribute or is it inheriting it of from its prototype tree next we'll step on to Constructors now in Python we're all familiar with the dunder init method which is we can Define on our class to say hey let's get set up and let's get ready to go in JavaScript you you actually write a function that is not directly part of your class which constructs your object instance pretty much the same way very similar as we can see you can do the same things you assign values to this in Python we can create our object using the Constructor by calling the class in that gets called implicitly when we do this in JavaScript you invoke the Constructor function and it returns you the newly constructed object inheritance again it's a little different in basic objects in Python we actually say that my new sorry every I've got the wrong glasses on I'm not having trouble reading any uh any attributes on our class are inherited by the instance this way that when we've put a method there which is an attribute on a class we can access it that way in JavaScript objects inherit via their prototype of their Constructor so my class instance on the left has inherited the Greet function from its class on the right the JavaScript function is inheriting the Greek function from the Prototype of the function we've had actually added it that way and so instead of when it's constructed it inherits the object prototype of the object it inherited it inherits the Prototype of the function that constructed it static methods methods on the class itself or on the Constructor very similar patterns in Python we actually have a decorator to say this is a static method so it won't be passed a class or an instance and we can often use that as Factory functions to produce new instances in JavaScript because it's inherited from the Prototype of the parent or with the Prototype itself we can attach objects and methods and attributes directly to the function which is an object very much like in Python so invoking this here we would get a mock object from a python class and here in JavaScript we call it the same way it looks very much the same we get an object back it's just a method a function attached to the function object which is our Constructor a subclassing in Python is a very explicit thing because python explicitly supports classes so if we just say them in my definition of my class well it's one of these with these changes and when I wanted to go and say well do what the parent class would do I call Super in JavaScript it requires a little bit more effort because it's a constructed concept rather than a native part of the language so we have to tell our Constructor that we're creating now that its prototype has a prototype of the Prototype of the parent classes Constructor and that sounds a little bit roundabout and actually doing that is also a little bit roundabout so here we've defined our new Constructor and it calls the parent classes Constructor using call which is similar to to bind but it actually you pass it the scope and then the arguments as a list and then we have to say can we create a new copy of our parent classes prototype but add to it this Constructor which is this is a very explicit and detailed way of saying I want to put another property on there very tedious next we come to a very noticeable difference in terminology and functionality between Python and JavaScript Python's init function although we often refer to it as a Constructor is not a Constructor it's the error in the name it's an initializer and this difference means that it's only invoked after the instance object is actually created and by the time that we get to the instance and we get to our initializer all the properties are declared on this instance all the properties have been inherited from the class the parent class the parent class all the way back and all of those attributes are visible to even the superclasses methods once they're called and invoked via super so here's an example if we have a python class called Unit and it has a static a property called Foo and they now initializer we get bar and we ask for the amount and multiply them when I create a chunk as a subclass of that if I create unit with a two value it's two times one we get two chunk two times five we get 10 pretty straightforward if we tried the same in JavaScript and we call new what we get what happens is we get a blank object created then its prototype is set to the Constructor function's prototype then the Constructor is called with this new object cast as it's this I've got my slides out of order I'm sorry about that next we enter es6 or es2015 JavaScript released in 2015 which introduced a whole bunch of things but one of the nicest things it introduced was class syntax this allows us to redo all those things we've done before in a syntax that looks a lot more like other languages classes now we have an explicit Constructor function we can define static methods and static properties and inherited functions for everybody else to use now subclassing becomes a nice direct clean this class extends that class my Constructor calls the superclasses Constructor and then does whatever it's local Things Are unlike Python and very much like a lot of other languages JavaScript does not support multiple inheritance you can go up the chain one by one but you can't say that this class mixes in multiple classes another important difference and this is actually different from the Constructor functions we saw earlier is that you must con must call your superclass Constructor before you do any modification of your this object if you try to do it you'll get an error like this to say exactly that again static properties can be declared just like they were before very much like it in Python now we just put it inside the class declaration and InFocus directly from the object itself The Constructor rather than as a member and prior to es6 it would have looked very much like this so it actually hasn't changed a lot it's very very similar next I want to talk about what I'm calling subclass overrides so their example before where we have an object which takes a factor a scaling Factor and then we pass it an amount and it'll tell us an amount comes out and then we have a subclass of it and it gives us a different amount because the init function has gone off okay I'll put that number in I'll multiply them and out we come with our amount in JavaScript if we tried the same thing looks almost identical we have our Constructor and we have an amount it's time to factor and how we get is a two but if we try the subclass um why did we get five why did we get two the wrong number comes out why does the wrong number come out part of the problem and part of the big conceptual difference and what I was talking about with the Constructor versus initializer before is that JavaScript Constructors are called in order because you have to call your parent Constructor before you do any work that goes all the way back to the root object from the bottom all the way back up to the top there's this layered concept and each layer can only see what's being defined so far what it has attached to the construction which means that all the methods all the overrides all the shadowed attributes you've got on your subclasses aren't there yet additionally public fields which is like a factor one here are added just before calling the Constructor function so what has happened in our example is that factor was actually one when the scale Constructor was was called and therefore when it is set this dot amount it is gone and multiplied it by one then when the bigger class gets its static attributes or it's its class members set up before its Constructor is called then the factor is set to five this is a bit of a trick that catches you out sometimes so how can we fix this what patterns can we follow to avoid this problem in future first you can use it as a static member and then explicitly reference the Constructor that was used to trigger this Construction in the first place rather than your current version of the of the truth this way we stash the static property on the Constructor and then we go into reference whichever one was there first so here's the example of that code Rewritten we have a static Factor instead of factor and here in our code we see we say this dot constructor.factor we're referring to whichever Constructor was used during the construction initially of this object so it will always be the Constructor that was passed to new rather than the current Constructor that we're calling so we can actually use this layering effect to our advantage okay since we know that they're going to get called in that order and that the object's going to exist in the particular State as we get there we can use a static initialized fields um as they're evaluated during construction so as it's a layered thing we can use this to provide helper methods for next classes down to access this is a natural thing in Python because we already know that all those methods are put together already but we can do this as a deliberate effort in in JavaScript to make things a little easier to use so as an example we might on our Base Class have a setup things method and then as a static initializer during uh child class called that to say what this field should be now notably in this scope this is referring to the object that's under construction and super is our parent class or the Constructor just like when we're using Constructor function static initializers public Fields just like we saw with facta and the class can have its own static initializers as well so we've already seen a very basic case of this with static initializers being methods and properties that we Define on the Constructor object itself or the base class but they can also be methods that include whole code blocks with conditional work and so on to make it initialization of of things that do not depend on the arguments passed into your Constructor or may only depend on arguments that have already been handled by parent classes this is a nice way to make your your Constructor functions a little tighter a little smaller so that they are more focused on what the user has decided rather than what you've decided as a general practice came to include here a nice practical example um of by using the static initializers our Base Class can actually provide helper functions for the other class to set up its own static methods here is an example of an enum class and we say that we've got setup values as method and then our enumclass does in a static Constructor block that we're going to call that method with a bunch of values here we can see it's simply Maps over the values and tries to set on this the uppercase version of that name and then the index back to the value and the product of this output is that we now have an e num very much like python where I can look it up by name or I can look it up by index right and this has gone just a little bit faster than I was hoping but there we are undone any questions please [Applause] thank you thank you Curtis um yeah we have time for some questions oh we have on there oh it's a Russell of course it's a raffle thanks very much um a lot of the issues or the causes of confusion in the JavaScript class World seem to stem from which this is this and which one is that and so on any tips trip tricks suggestions hints for how to either diagnose or prevent error when you get into that kind of situation so the biggest one was actually mentioned early on uh here we're talking about how and I I did want to provide more detail on this this is good um this when you call a function is the scope you were called from and if you looked up via an object as I show here x dot Foo then in this case X is the scope of it is this once you're called so if you remember to always look up fire function then you can control your scope if you are passing a callback to which is very common in in JavaScript for a long time like we're doing down at set timeout you have two options either you can wrap it in a new function that deliberately looks up your object to get that function because if you pass the function on Excel on its own you've lost this the other is bind bind creates a new function which always has in this case X has its scope as it's this it's bound it's fixed it's done you cannot undo it except unless you call bind again or or a call as I showed later on is another option that way you can say always I want this and you'll see this a lot in older react code where the Constructor of the class will go through and grab all of its methods and say on the instance the same name equals that function dot bind this that way doesn't matter if you pass them as a callback or use them in any other way they're always bound to the current instance to make sure that that scope doesn't creep away on you and disappear do we have any other questions foreign struggle with context switching between Python on the server and JavaScript on the client does my head in can you talk through the pros and cons of doing that just suck it up versus node on the server versus a python to JavaScript transpiler oh that's an interesting one so my personal view is if I had the choice I would not use JavaScript but in the browser we currently don't really have the choice there have been some great examples shown at this conference that it's it's there I would much rather have a single language so I definitely understand why node happened as a thing because all the people who already had all the familiarity and expertise in JavaScript moved over to the server and went well I'm going to bring my language with me perfectly valid choice I like the idea of going the other direction which Russell has helped with and various other people have helped with in bringing python to the browser at the moment I find your best cleanest option is really to understand both languages and use each one in its field um I have not played with any of the transpilers but I understand that some of them have been around a couple of decades now I don't feel that you're really going to get the best performance results if you're just trying to shim one to look like the other and a lot of the times when we're working in the web the performance can really really matter so there's a lot of different takes on on how to do that JavaScript has definitely improved a lot over the last decade I now find it much much closer to python a much more cleanly defined and they are actually in some places dropping some of the um some of the old things that they found very painful to deal with there's actually a speaker's note on this slide to talk about with which is no longer in fact if you go to the Mozilla developer Network they say don't use this some browsers have even stopped supporting it where you could say with X call Foo and it would make X the current this so that's an option that is in JavaScript but no longer there so JavaScript is maturing and growing and involving python is 2 and I think JavaScript is a lot less painful than it used to be and a lot less scary than I used to find it but I was hoping with this talk to get people a little more familiar with what you're going to stumble across when you start trying to use it and why the things are constructed the way they are because it's important to recognize that the new class structure stuff that was there is really the old Constructors and functions and and prototypes with a new syntactic sugar on top do we have any other questions guess not um thank you so much Curtis um thank you [Applause]
Info
Channel: PyCon AU
Views: 144
Rating: undefined out of 5
Keywords: CurtisMaloney, pyconau, pyconau_2023
Id: h-y1usZaK-w
Channel Id: undefined
Length: 24min 12sec (1452 seconds)
Published: Thu Aug 24 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.