👷 Join the FREE Code Diagnosis Workshop to help you review code more effectively using my 3-Factor Diagnosis Framework: www.arjancodes.com/diagnosis
@loic16656 ай бұрын
Warning, at 4:26: never use a mutable variable as an argument! This is because the same object will be reused if you call the function/method several times! This is also a common mistake when you want an empty list. A solution is to not provide a default value, but a default factory. Apart from this, thanks Arjan for the video :) Very good, as always! The new example is refreshing and is well appropriate
@dynamicgrad38206 ай бұрын
What do you mean "when you want na empty list"?
@TheEvertw6 ай бұрын
@@dynamicgrad3820 If you pass an empty list as default argument in a function, that default empty list is created once, and then reused every time that function is called. Which means that most likely, after that first function call, that list no longer is empty. And if the list passed to the function is stored somewhere in your code, there are multiple references to that list spread around your data structure waiting to cause nasty and hard-to-debug side-effects. Your Python IDE will warn about this. A better solution is to use an `typing.Optional[List[xxx]]` argument, with a `None` as default argument. `None` is immutable, so it can be safely reused and shared between multiple calls to the function.
@TheEvertw6 ай бұрын
Seconded. I spotted that as well, you beat me to it. Besides using the factory argument, Python has the Optional typing hint, which expects a None default value.
@dynamicgrad38206 ай бұрын
Can someone explain why he added this warning?
@erikstv78026 ай бұрын
@@dynamicgrad3820 if you specify a default value to a function argument, Python constructs that object only once (together with the function), not again for every call that needs the default value. A common situation would be that you make an argument default to an empty list []. Let's say that the function's code appends something to this list. You may be surprised to notice that if the function is called a second time, the default value is no longer the empty list but the result of manipulations to the list in the previous function call! I.e. it's reusing the very same instance of the default value, not constructing a new value. A way to solve this is to use None as default value then in the beginning of the function replace None with a new empty list if that's what you wanted.
@estevaoyt6 ай бұрын
Beautifuly explained, clear as water! keep it up!! I think dependendy injection is one of the most important concepts in programming!
@ArjanCodes6 ай бұрын
I'm happy you enjoyed the video!
@edgarcarrillo38142 ай бұрын
Thank you Arjan! Clear, concise, and to the point. I now know Dependency Injection!
@ArjanCodes2 ай бұрын
Glad it was helpful!
@roger_rogerthat6 ай бұрын
This time I felt like I've already seen this video. You should talk about an auto wiring DI library like kink
@buchi84496 ай бұрын
One of the surprising things I encountered when I moved from Java to Python was the heavy usage of the service locator pattern. A typical example is Flask's "request" and "d". It is still widespread in Python to put a dependency or an accessor to a dependency in the global context and reference it inside a component. Of course, Python has enough flexibility to manage tests of such less decoupled codes. However, I have always believed that clear decoupling using DI is cleaner and more straightforward. FastAPI's DI is handly but covers only part of the DI commonly practised in Java. FastAPI supports only DI in the "request" scope. But DI frameworks in Java, like Spring, support other scopes, including the "application" scope. The lack of DI containers supporting the application scope is why people must repeat "app.include_router(...)" etc., to construct big applications. DI realises IoC (inversion of control) at the component level. However, you still need to control the construction of an application (injection of dependencies), as demonstrated in this video. The automated construction of applications using DI and CoC (convention over configuration), which is widely used in Java, is something we should consider in Python as well.
@mackymccormack84465 ай бұрын
Thanks really helpful. In this example though I couldn't see how variations in the email service protocols were catered for. The send_email method didn't show an indication of the different logic needed for different services.
@shashishekhar----Ай бұрын
Great example.
@Nalewkarz6 ай бұрын
Deja vu, You have recorded almost the same video again. Arjan it's time to go deeper into more advanced examples.
@ArjanCodes6 ай бұрын
This video was a lead up to another one that’s coming very soon, covering DI frameworks 😊
@mirkoulrich63126 ай бұрын
@@ArjanCodesi was looking in the comments, if this framework discussion has been requested yet^^. I recently used Dependency Injector, but never got really fond of it. I am looking forward to this upcoming topic.
@kvicar74196 ай бұрын
So in this case, how the email service specific arguments are going to be handled? For example the attachment argument? First we are going to create an instance of email service, pass the arguments to it and then use it to create an instance of EmailSender to actually send the email?
@NicolasChanCSY6 ай бұрын
I was just about to ask the same questions. I thought these would be answered in the video but they are not.
@audox48852 ай бұрын
yea that made no sense to me
@maleldil16 ай бұрын
Why do you use Protocols if you're going to subclass that anyway? Doesn't it defeat the purpose of Protocols (structural subtyping) in the first place?
@kaosce5 ай бұрын
Not really. Protocol are better abstract classes
@TheEvertw6 ай бұрын
"Dependency injection", as explained here, is probably the most simple OO design pattern. In OO, it is called the Strategy Pattern. You hide the details of an algorithm behind an (abstract) interface. The user of the strategy only knows the abstract interface, each implementation of the Strategy interface knows only the details it needs. I don't understand why people wanted to change the name. The name "Strategy Pattern" has been in wide-spread use for 30 years. I guess people like re-inventing the wheel. That is no critique on Arjan, he didn't coin "dependency injection". I thank him for this video, I never understood what people meant with DI. I thought it was some complex trick like the "Curiously Recurring Template" pattern. Which is similar to DI but achieves lightning fast execution & minimal memory footprint, at the cost of long compile times.
@m__426 ай бұрын
I would say, dependency injection is (usually) built upon the Strategy pattern, but goes beyond that. Your dependencies to inject will usually use the Strategy pattern, but in addition you have some concept of instantiating the dependencies, a repository to keep them, and a way to inject them as needed. This was of course the most basic example with just one dependency which is created in the main() and injected via the constructor. Really a textbook Strategy pattern. This works fine for this simple case with only one level of dependencies. However in an even moderately complex application, this simple approach soon falls apart in that it either explodes the number of dependencies you have to pass along, or forces you to create all strategies in a central place which prevents modularization. There Dependency Injection frameworks come to help...
@Naej76 ай бұрын
TL;DR : The Strategy Pattern uses the Dependency Injection principle but the Strategy Pattern is not the Dependency Injection principle, and the Dependency Injection principle is not the Strategy Pattern neither
@Lexaire6 ай бұрын
Strategy Pattern is specifically at runtime choosing different options. Dependency Injection is focused on a caller creating an object that the callee acts upon. Strategy Pattern doesn't require generic interfaces. The Before code that Arjan showed was an example of using the Strategy Pattern.
@WalterVos6 ай бұрын
All applications of the strategy pattern need dependency injection, not all cases of dependency injection are applications of the strategy pattern. (All swallows are birds, not all birds are swallows)
@Ruskialt6 ай бұрын
Yes it's a great pattern. To actually manage and reduce dependencies you need also consider where to place your abstract classes and interfaces.
@diegovargas38536 ай бұрын
Hey Arjan, thank you for your work from Spain. Would be great if you create a video with your top python books "to improve your python skills to another level", thank you!
@willemvdk48866 ай бұрын
Python has, just like many other languages, very nice libraries for dealing with DI. Very valuable in big projects with loads of modules, units, tests, deployment environments, etc. etc.
@amanlodha62606 ай бұрын
Could you share some options here please?
@capability-snob6 ай бұрын
Don't get confused when talking to Java programmers about DI. Over there, it generally means "magically inferring which service to use".
@andyk21816 ай бұрын
So, er... it's *not* about vaccinating your children?
@markcampanelli5 ай бұрын
lol!!!
@VanosTurbo6 ай бұрын
Agree your codebase gets such an improvement when you start using dependency injection.
@manonthedollar5 ай бұрын
Dumb question: In this example, the EmailService ends up hard coded (at 5:17 see Line 6-8, for example). In a more real-world example where you don't know which email service a user will need, won't there still be some big long if/elif/else block that needs to be updated when you add a new service?
@ifeanyinneji77046 ай бұрын
Recently did something like this for work. But used a general email sending function that takes in smtp type, port etc for different email providers.
@TheEvertw6 ай бұрын
I prefer SMTP as my email sender. Works every time, regardless of how a customer has configured his email server.
@heinereniscaicedo75106 ай бұрын
There's an awesome third party library called Dependency Injection, it's so good to apply this principle to any python project
@danielwhiting40175 ай бұрын
Thanks for the great video. I understand that this is a bit of a contrived example but can you explain why you use an EmailSender class at all when it only wraps a method of the service object that is passed to the initialiser? In other words, why not just call the send_email method directly?
@ytuserln49906 ай бұрын
Hello Arjan, great video as usual! I have a question why do you inherit from the protocol in a class which implements one? It's the second video in which I can see this, whereas in ABC vs Protocol you pointed out that it is not needed (duck typing) and also decouples the one who implements from the one who requires. Is there any reason for that? Thank you in advance for the response.
@alexandarjelenic28806 ай бұрын
I’m confused between the factory pattern and dependency injection. I watched both your videos. Is it the same?
@janetgauntt9039 күн бұрын
To answer your question about which email service, I'm using mailjet
@ShadiPL946 ай бұрын
I am bit confused, since when we have to inherit explicitly from Protocols? Your Smtp, SendGrid and MailChimp classes all inherit from EmailService. Or is this just to show that those classes implements the protocol?
@Lexaire6 ай бұрын
They must inherit so that his EmailSender class can call any of them. See code at 4:00
@andreas36826 ай бұрын
Inheriting from 'Protocol' is necessary to create EmailService Protocol. Whats not necessary and where i believe the confusion stems from is inheriting from 'EmailService'. A protocol in python is a typing related construct and should be used as such by using it to declare the type as done in the 'EmailSender' init method. In this example an ABC would be better suited as we have full control over the different implementations. If a third party implementation of an EmailService was imported that you could not control in addition to some of your own code alongside it or as alternative implementations you could use a protocol.
@hello_world_zz3 ай бұрын
Thanks Arjan
@ArjanCodes3 ай бұрын
Glad you enjoyed it!
@MagnusAnand6 ай бұрын
These are the best videos!!
@ArjanCodes6 ай бұрын
Thank you! Glad you like this content!
@danielschmider50696 ай бұрын
Can we see the files email_service and services? You put code there and never showed them
@Phoenix_ZA6 ай бұрын
I have been happy with Mailtrap
@calebrubalema6 ай бұрын
informative, thank you! Have to ask though, is there a Python package that can do DI the way Spring Boot does it?
@talwald16806 ай бұрын
We heavily use DI in one of our projects, and it is getting really difficult to manage. We looked and didn't find anything standalone (FastAPI has DI but not standalone, and the project isn't an http server.. ). So if someone knows a good package - lets us know!!
@Nalewkarz6 ай бұрын
We have better, something like Lagom for example.
@Lexaire6 ай бұрын
FastAPI or FastDepends have enough DI for most people. But do you mean the Beans? I've not encountered something like that in Python.
@jumper01225 ай бұрын
I'd really like a few more videos on this topic -- it seems really clever and useful but I don't totally understand it
@ArjanCodes5 ай бұрын
I have a couple of older videos talking about it already! :)
@vyacheslavkapitonov96775 ай бұрын
How will it work if I need to pass an attachment? I still need to change send_email for all of my classes
@marthinus.x6 ай бұрын
Sheesh! Fresh off the presses!
@thefattysplace6 ай бұрын
The emailSender class here is not needed imo. A better approach (imo) would be to use a common interface on the sender classes, and use DI to pass the relevant sending class to the interface object. Then just call send on the interface.
@user-lp6qm3cg6h6 ай бұрын
I don't get the real advantage of it .The lines of code you reduce in the first class you have to put them in an other file, so you end with the same (probably more) lines, more files and dependencies. I would really like to understand the advantages of it to apply it more naturally. Thanks in advance
@Lexaire6 ай бұрын
Advantage is for testing, separating construction of a service from where it's used, organizing your services better, and keeping code clean. If you can swap out one service for another without a fuss, then your code is properly decoupled!
@DanielRodriguez-lu3uu6 ай бұрын
is decency injection only applicable on Classes?
@Lexaire6 ай бұрын
No, you can inject abstract functions into other functions.
@JobertoDiniz5 ай бұрын
5:20 Hi. This is not dependency injection. You demonstrated a pattern called dependency INVERSION. Injection is on top of that. Injection means you outsource the instantiation of a class to a Container that will automatically inject dependencies to the class based on configuration.
@ArjanCodes5 ай бұрын
Yes, it is. Dependency injection doesn’t require a container. DI means you provide an object or function to another object or function, thus separating creation and use, which leads to better decoupling. Dependency inversion means you rely on abstractions instead of concrete classes, which I didn’t cover in this video.
@deViant146 ай бұрын
I've been doing this but had no idea it was a design pattern.
@WalterVos6 ай бұрын
If you've been doing something (in multiple projects, I assume) then it is by definition a design pattern ;)
@user-hk2gk7pj8h21 күн бұрын
Isn't using a mutable argument in Python a ROOKIE MISTAKE?
@ArjanCodes20 күн бұрын
Unfortunately in Python there’s no way to indicate that an argument is a const. When you pass a mutable data structure like a list as an argument, you probably should avoid modifying the list in the function or method that you pass it to. In case it’s an object with methods that is passed as a dependency, it’s a good practice that reduces coupling.
@MineStrongth6 ай бұрын
Reupload? I swear I've watched this before.
@PanduPoluan6 ай бұрын
The power of Python's duck-typing leads really well into dependency injection. Just pass an object that has the required properties/methods, and done. No need to subclass from an esoteric BaseSomethingClass first.
@Nalewkarz6 ай бұрын
Base class is esoteric for You ? 🤣
@andyk21816 ай бұрын
Can Python be used with Keychron or GMMK, or does it have to be a Ducky typing? 😂
@Naej76 ай бұрын
Convenient but a bad idea Write a Protocol to be explicit, and it’s easier to create a new implementation as you directly know what methods to write with what arguments
@darcash17386 ай бұрын
Where do the ducks come into play?
@Lexaire6 ай бұрын
You lose the benefits of typing and autocomplete if you don't at least use a Protocol.