Avoid These BAD Practices in Python OOP

Поделиться
HTML-код
  • Опубликовано: 22 ноя 2024

Комментарии •

  • @ArjanCodes
    @ArjanCodes  2 месяца назад +1

    💡 Get my FREE 7-step guide to help you consistently design great software: arjancodes.com/designguide.

  • @lunalect
    @lunalect 2 месяца назад +111

    Man I love these “slashing over engineered OOP cruft into nice little functions videos” 😂

    • @ArjanCodes
      @ArjanCodes  2 месяца назад +8

      Haha, glad you enjoy them 😎

  • @yickysan
    @yickysan 2 месяца назад +9

    I really enjoy Arjan code content. I found this channel late 2022 and it's helped me deeply. A lot of time when you are being taught clean Code, they make it seem like OOP is the way to go. But obviously as Arjan has pointed out, in python, there are times when you are better off with a module or with just functions.

  • @maleldil1
    @maleldil1 2 месяца назад +51

    The difference between getters/setters in Java and Python is that in Java, if you don't use get/set and make the member itself public, you cannot change that in the future: you're stuck with a public member forever as part of the interface. In Python, you can start with a public member, but if you want to refine the behaviour later, you can make it private and add a property. The interface doesn't change for users.

    • @dalehagglund
      @dalehagglund 2 месяца назад +4

      This is heretical, but the presence of get methods for attributes is itself a bad sign. Mostly, your attributes should not be private and modified only by the regular methods. Set methods are less problematic but using them a lot is also a bad sign.

    • @brandonblackwell1216
      @brandonblackwell1216 2 месяца назад +7

      Technically speaking, there’s no such thing as a “private” member in Python.

    • @dalehagglund
      @dalehagglund 2 месяца назад +2

      @@brandonblackwell1216 Yeah,.I know. But thinking about state as private is still mostly the right thing. And the leading underscore convention to mark an instance variable as hands off seems reasonablely well understood in python.

    • @jonaskarlsson5901
      @jonaskarlsson5901 20 дней назад

      why compare it with Java and not with C#? C# has 100 times better getters/setters than Java

  • @mdanish6221
    @mdanish6221 2 месяца назад +12

    Great video! I have a request: could you create a follow-up video explaining when it makes sense to move from using just functions to adopting OOP, particularly when you should start incorporating methods (not just properties) in your classes?

  • @loic1665
    @loic1665 2 месяца назад +4

    I think that I suggested to you in the discord the bad practice of a class only containing static methods. Really happy to see that it got included in a video aha 😀

    • @ArjanCodes
      @ArjanCodes  2 месяца назад +4

      Yes!👍🏻 That discussion in Discord was actually my motivation to do this video in the first place 😁.

  • @MikeCorvin-x4p
    @MikeCorvin-x4p 2 месяца назад +3

    Another excellent presentation, Arjan! I've recommended it to our team as a good refresher. Some of your refactoring also was a good demo of dependency inversion. SRP definitely is the single (pun intended) most important guide star I stress to my colleagues - and to refactor, repeatedly and brutally, until you almost giggle because your code is so concise, readable and beautiful. Which means it's most likely also much more maintainable and reusable, perhaps even in ways you haven't planned for.

  • @thomasroberts6008
    @thomasroberts6008 2 месяца назад +44

    So, a lot of these focus on people using classes where they should perhaps use something else, like functions & modules, which is valid, but something I see quite a lot is people using something else when they should actually use a class. For example, using a dictionary to structure complex, nested data when that data structure is known to the developer at compile (write) time, like requests with a known return structure and config files where I feel like you as the developer should really be prescribing how it is structured. So instead of having to hunt around a code base to find what keys are being accesed, classes allow for a much more declarative way of defining how the data should be structured. Another, albeit rarer example, is a module with a set of functions and a global variable that the other functions are reading and updating. Dont do that, please use a class.

    • @garrywreck4291
      @garrywreck4291 2 месяца назад +7

      100%. I create a class even when my config has one parameter :)
      Type hinting + data wrappers is really the way to go.
      class Config:
      a: str
      b: int
      @classmethod
      def from_dict(cls, data: dict) -> "Config":
      return cls(...)
      When I see a class that accepts "config: dict", I wanna cry.

    • @BRLN1
      @BRLN1 2 месяца назад

      @@garrywreck4291 I totally agree with you. Another example: If i read a csv i usually gather the column names in a class:
      class CSVHeader(object):
      date: str = "date"
      id: str = "id"
      name: str = "name"
      with open(pl.Path("data.csv"), mode = "r") as in_stream:
      dr: csv.DictReader = csv.DictReader(in_stream)
      for line in dr:
      print(f"date: {line[CSVHeader.date]}")
      So I can reuse them as often as i want (e.g. CSVHeader.date) ... and if i need to change a column name in my csv-data later on, then there is exactly one place where i need to cahnge my code (namely in my class). Hence I don't need to go through my code line by line and by hand and by [CTRL]+[F]. Plus my IDE (pycharm) can support me better with code completion on the csv header names.

    • @marlan__
      @marlan__ 2 месяца назад

      @@garrywreck4291 don't forget about `@dataclass`

    • @vladimirtchuiev2218
      @vladimirtchuiev2218 2 месяца назад

      @@garrywreck4291 It's all good until you reach a situation that you have different initialization parameters for, for example, neural networks, and on the project you're doing experiments, change and add parameters constantly. It's much simpler to manage all these configuration via something like Hydra, and while the resulting DictConfig is opaque, it saves a lot of time rather than trying to trace where each dataclass is called. Doing dataclass configs are good when you are 100% certain about what goes there.

    • @astronemir
      @astronemir 2 месяца назад +2

      Protip: TypedDict
      I only add config classes when I actually need some functionality of a class otherwise just a typed dict for passing typed data around to functions works great.
      But say you want to encode defaults, add some calculated fields, etc. Then turn it into a data class (or even better pydantic model/dataclass)

  • @barmus90
    @barmus90 2 месяца назад +5

    One of the eye openers for me was tarting to think domain centric, so thinking of what aspect you're trying to represent in the real world and then copy that in the code. So if you do a library system, the book may be objects, but checking in and out could be functions, rather than an object. Doing this made my code cleaner and more robust

  • @SangaPommike
    @SangaPommike 2 месяца назад +12

    Not entirely OOP related, but rather general python related.
    Whenever I am refactoring or dealing with bug fixes or new features I find myself dreading methods that return a tuple of objects. Most of the time this is only 2 different things, which isn't going to be too problematic. But if there's more than 2 elements in a tuple, especially if some of them are of the same type, this will soon become problematic. Sure, we can use (e.g) `mypy` to check for types, but if there's multiple elements of the same type, these types of checks won't find the error in the intent of the code (though tests should do). So I find myself then creating data classes to make sure these things are handled correctly.
    And while on the other hand, the underlying issue might have to do with poor design, sometimes the coupled natured of the code doesn't allow for an easy fix for this within the confines of the current maintenance task. Other times even changing the return type could be problematic.

  • @thisoldproperty
    @thisoldproperty 2 месяца назад

    Thanks for sharing re: Mixin. I like how you keep coming back to what is simple, effective and easy to understand.

  • @DataPastor
    @DataPastor 2 месяца назад +1

    I had huge discussions about topic 1 (wrapping functions into classes just because it looks “more professional”) with my team mates, who are computer scientists (and I am a data scientist). CS people are socialized on Java and they are educated to wrap the full world into classes, whether it is actually needed or not.

  • @DrGreenGiant
    @DrGreenGiant 2 месяца назад

    Composition over inheritance! My old C++ job had a load of code that was at least 10 levels deep of inheritance on embedded code. Debugging and reasoning was impossible to learn, you had to have grown up with it.
    Superb video!
    And of course, don't forget that sometimes these bad practices are the right tool for the job, it's just rare. A good example is _global_, it's almost always bad apart from the rare time when it isn't (e.g. logging library logger mapping) but you must be very aware of the caveats (e.g. they're process local, not truly "global.")

    • @ArjanCodes
      @ArjanCodes  2 месяца назад +1

      Glad you liked the video! And good point regarding that in rare cases, doing these things might make sense.

  • @ssmith5048
    @ssmith5048 2 месяца назад

    Love it! Anything to remove unecessary oop is always welcome! Great examples.

  • @WilliamWatkins-o6z
    @WilliamWatkins-o6z 2 месяца назад +1

    17:12, you need to learn ctrl+d whilst selecting some text, it will create multiple cursors enabling you easier editing

  • @praysonwilfreddaniel4775
    @praysonwilfreddaniel4775 2 месяца назад

    I love this one 🎉. I noticed minor issues on the first example (pathlib has its own open … path.read_text :) so there is no need for `with open …`) . What would be cooler for Bank example is using setters and getter(return self._balance). with setter on balance, we could create checks without introducing extra function). Beyond that, I loved everything

  • @priteshsingh4055
    @priteshsingh4055 Месяц назад

    Amazing ,thanks Arjan, already using all these practices

  • @hoseynamiri
    @hoseynamiri 2 месяца назад

    I love your OOP stuff/mindset. It changed my life.

    • @ArjanCodes
      @ArjanCodes  2 месяца назад +1

      Glad to hear you find it helpful!

  • @ulyssep2997
    @ulyssep2997 2 месяца назад

    Thank you, very helpful video! Your clarity is unmatched.

  • @EmilioGagliardi
    @EmilioGagliardi 2 месяца назад

    good stuff. definitely going through these issues. didn't know about the callable or protocol so I'm going to look into those more.

  • @mohammadhosain960
    @mohammadhosain960 Месяц назад

    good content i just subscribe! (just a tip: English its not my first language and see your videos with subtitle so when you type something in bottom of screen its goes under the subtitle please try up the screen if possible)

  • @sethmachine268
    @sethmachine268 Месяц назад +1

    In the sixth example with getters and setters, you should not really have setters at all. I think it’s better practice to only have immutable data structures. Why would someone instantiate a Person and then change the name ? Just make a new Person. In Python this is hard to enforce but you can encourage it with underscore names and the absence of “public” methods to do the mutation.

  • @evlezzz
    @evlezzz Месяц назад

    1. Classes with a single method and init can still be useful in situations when initializing and action are controlled by a different code. Say, you need to load some data from file and you query filename in one function and actually read it way after. You could pass around raw filename, but often it's safer to wrap it in a class with a reasonable interface. It will be easier to mock for testing or enchance for some other format later. Basicaly it replaces string filename with a protocol with one load method that can have different implementations.
    2. Using modules instead of classes with static methods is for sure a good idea, but there are rare cases when you actually can't do that easily. For example if you need alternative implementations of those functions and could benefit from inheritance. Something like pathlib with identical interface for manipulating with paths on different platforms.
    3. I disagree that converting an attribute to a property by itself improves encapsulation in any way. What does improve it is domain-specific method like "withdraw", but leaving external interface as is and implementing limitations in methods like __iadd__ is fine as well.

  • @nothingisreal6345
    @nothingisreal6345 Месяц назад

    For the inheritance and role: but if you create a lib then the enum is under your control. So adding addtional roles will be hard for someone using you lib. If you keep a virutal function getRole -> string someone can derive from you class and add a new role

  • @kevinpham6658
    @kevinpham6658 2 месяца назад +8

    FunctionClass: a class with a lowercase verb describing the core operation, which is implemented in the __call__ method of it’s metaclass, and invariant operations in static methods of the main class, named as adverbs, nouns or qualifiers that compose with the class’s verb name.
    Usage looks like:
    from utils import crop
    crop(img)
    crop.with_margins(img)
    crop.without_headers(img)
    crop.as_png(in)
    crop.fit_to_page(img, page)

    • @hansdietrich1496
      @hansdietrich1496 2 месяца назад +2

      Yeah, that sounds like an excellent case for a module named crop with a bunch of functions inside.

  • @colinhiggs70
    @colinhiggs70 2 месяца назад

    Thank you, I enjoyed this videao. I would have liked to see some coverage of property setters in the encapsulation section.

  • @bartuslongus
    @bartuslongus 2 месяца назад

    Inner me is crying as I have to deal with Java daily and it's boilerplate oriented programming. I am so happy when "I have to adapt some Python scripts" for data analysis :)
    Thank you for the great video!

  • @HarshVerma-k9z
    @HarshVerma-k9z 2 месяца назад

    Hi Arjan, I've finally implemented CI/CD pipeline using github actions into my python libraries. Can you please discuss about `act` to run github workflows locally - specifically running tests on different python versions.

  • @oromogamer1431
    @oromogamer1431 Месяц назад

    You are so settle and easy on explanation wow, thanks 👍

  • @mmasa1
    @mmasa1 2 месяца назад

    Very good summary, Sir! Thank you

  • @apmcd47
    @apmcd47 2 месяца назад +38

    Regarding functions masquerading as a class: I once found a RUclips video in which the presenter said, "If a class contains 2 methods and one of them is __init__ it probably isn't a class". Which is effectively what Arjan said of his DataLoader class.

    • @dynamicgrad3820
      @dynamicgrad3820 2 месяца назад +1

      PROBABLY! is the key word here

    • @francosbenitez
      @francosbenitez 2 месяца назад

      Good comment man!

    • @hulavux8145
      @hulavux8145 2 месяца назад +1

      The default checking for class in Pylint has something like: Your class has too few public methods (

    • @nibblrrr7124
      @nibblrrr7124 Месяц назад +2

      "The signature of 'This shouldn't be a class' is that it has two methods, one of which is init. Anytime you see that, you should probably think: 'Hey, maybe I just need the one method.'"
      --Jack Diederich, "Stop Writing Classes", PyConUS 2012

    • @stepanivanov3557
      @stepanivanov3557 18 дней назад

      One ok-ish example are interpolators. At construction they find coefficients of polynomials and store them. Then the only method interpolates using these polinomials. So that coefficients are not recomputed at each interpolation.

  • @RageOrangeBG
    @RageOrangeBG 2 месяца назад

    Will there be a video about all modern python tooling, comparison and use cases? For example: Poetry, Hatch, uv, rye etc.

  • @BrunoGallant
    @BrunoGallant 2 месяца назад

    When I was learning Java, I couldn't internalize all the loops, smoke and mirrors that you had to go through to "emuilate" functions and procedural code. Python refreshingly gives you the option of using both at the same time. But like anything, you can abuse the system. Thanks for your wisdom!

  • @vladimirtchuiev2218
    @vladimirtchuiev2218 2 месяца назад

    As for complex inheritence structures, sometimes you are kind forced to do this instead of repeating the code a bunch of times. For example if working with (Pytorch) Lightning, you create a custom Lightning Module by inheriting from a L.LightningModule class, and in itself it contains a lot of functionality that you need in order for it to train your neural network. You can get easily into situations that you have multiple models that use share some basic methods between them, but differ in others, like for example a custom "forward" method per each model. It can get even more complicated if you're building a meta-learning model or a GAN, but you still need the basic L.LightningModule functionality so you may find yourself with multiple layers of inheritance.
    If your lowest level classes don't rely on inheriting from outside packages then I agree, better not to have this hierarchy and strive to inherit only from a ABC.

  • @ApprendreSansNecessite
    @ApprendreSansNecessite 2 месяца назад

    In Typescript I like hard currying dependencies like saver and logger to create a readymade processOrder function that is easier to use, then in tests I can inject other things to the original processOrderFactory function.
    It kind of looks like inheritance but I found that it does not lead to the same problems as a proliferation of classes does, because they all have the same type (generics will be evaluated differently) and they don't require their own initializer or method overrides, so they are very lightweight.
    This is the same kind of difference between a function decorator and a higher order function. everytime you use a HOF as a decorator you loose flexibility.
    The only problem with this pattern is the naming convention.

  • @cparks1000000
    @cparks1000000 Месяц назад

    I absolutely love "functions as classes". I use them for partial application though.

  • @alejandrocarmena8767
    @alejandrocarmena8767 2 месяца назад

    Really nice video! What code formatter do you use? I have Black configured in VS Code and it does not highlight the code when the function parameters have no type

  • @rohanreddyalleti
    @rohanreddyalleti 2 месяца назад

    The only reason I chose using a class over a function even thought it is static, is Dependency injection. I use FastAPI quite often, and more often than not, I inject service classes into other services or routes. Unittesting is much easier when you inject a class instead of a function. Yes, you can use patch/monkeypatch, but that is a skewed way of mocking (IMO). I would like to hear what your thoughts are on this.

  • @rokaskarabevicius
    @rokaskarabevicius 2 месяца назад

    As far as I know, the use of typing is being phased out in favor of using the actual objects directly, rather than their proxies through typing. For example, instead of from "typing import Callable", it's better to use from collections(dot)abc import Callable. Similarly, instead of from typing import Tuple, you should simply use tuple without any imports.

  • @codee_script
    @codee_script 2 месяца назад

    Your content is very good. I am proud to be your subscriber.Wish best luck❤❤❤❤❤❤

    • @ArjanCodes
      @ArjanCodes  2 месяца назад

      Thank you so much! ❤

  • @mmilerngruppe
    @mmilerngruppe 2 месяца назад +1

    7:27 Arjan, do you have more examples of code, that goes better with composition. I think I kind of get the concept, and then I realize I haven't really figured out how to do it.

  • @markhaus
    @markhaus Месяц назад

    My thinking is that:
    - If this module describes data, use a class
    - If that class doesn’t use a lot of methods inherent to that data, that isn’t just data validation, use a data class
    - If you must use inheritance, keep it really flat and stick to interfaces where possible to define expected behavior. Abstract classes can really help here.
    - Otherwise use modules with functions

  • @deidyomega
    @deidyomega Месяц назад

    note with the `_balance` example, if you use two underscores it becomes effectively protected. Try it out :D

  • @maloukemallouke9735
    @maloukemallouke9735 2 месяца назад

    thank you so much
    can i ask you a video about decorators?

  • @alecvinent
    @alecvinent Месяц назад

    Great tips!!

  • @bhbr-xb6po
    @bhbr-xb6po 2 месяца назад +1

    14:40 Every viewer who has ever worked on banking software just yelled at their screen

    • @codures
      @codures 27 дней назад

      Already happened long before, because a debit account can't be created with a negative amount.

  • @lolikpof
    @lolikpof 2 месяца назад

    What vscode extensions do you use? The interface for renaming a variable seems different from what i get. Also, what autocomplete shadow hints are you using?

  • @polychad
    @polychad 2 месяца назад +1

    A module can still contain static methods on a class. Say you wanted 3 sets of related but distinct functions available. You might create a module and simply use the class name as a namespace.
    The reason why static methods are useful is because they provide another level of abstraction. As long as your style is consistent, there are no issues with them. They can even improve readability.

    • @__christopher__
      @__christopher__ 2 месяца назад

      If all you want to do is structuring, you can simply use submodules. Then it is the user who can decide which names should remain and which shouldn't. Or whether an abbreviation of the name should be used.

    • @polychad
      @polychad 2 месяца назад

      @@__christopher__ Sure you can use a sub-package, and you should anyway. It's a matter of personal preference.
      Static methods provide another layer of abstraction without creating yet another level to a package, so there is no reason not to do both when it seems right.
      There are many approaches and as long as it's readable, reusable and minimal, these choices can vary.

  • @TheEvertw
    @TheEvertw 2 месяца назад

    In some languages, you ALWAYS create getters and setters for data members, because of the pain that will be incurred when you change the underlying data structures and / or add algorithms.
    In Python, this is absolutely not necessary. If at some point you decide that accessing an attribute needs to be replaced with a function call, in Python you can make the attribute a `property`.

  • @Novikovrus
    @Novikovrus Месяц назад

    What about double underscore for private fields? I think it has more protection against accidental changing.

  • @RadAlzyoud
    @RadAlzyoud 2 месяца назад

    Very useful. Thanks

    • @ArjanCodes
      @ArjanCodes  2 месяца назад

      Glad it was helpful!

  • @DrDeuteron
    @DrDeuteron 2 месяца назад

    Regarding Employee, Manager, etc. I would have them all inherit from a base class and return a class attribute that describes roll.

  • @ENTMusic-cj7wt
    @ENTMusic-cj7wt 2 месяца назад

    when I have a project and do the yet know how big it’s gonna be, I usually write procedural, then functional first and only start to introduce OOP when that’s actually helpful

  • @sethmachine268
    @sethmachine268 Месяц назад

    What is the reason to avoid namespacing imported methods ? I find it much easier to read code if an imported method is namespaced to a class, e.gx StringProcessor.uppercase vs from stringutils import uppercase.
    With the namespace qualifier you immediately know where the method is coming from anywhere in the code. And it cannot conflict with a variable accidentally named the same way.

  • @RocketLR
    @RocketLR 2 месяца назад

    6:46 Does this method work with ORM objects like when you use sqlalchemy?

  • @block4671
    @block4671 2 месяца назад +1

    wow thanks for sharing.

  • @snehotoshbanerjee1938
    @snehotoshbanerjee1938 2 месяца назад

    I guess, we can change the self._balance to self.balance in the init method so that we can call the property in the init. In that case any change in the property will be applied to init as well.

  • @rafiullah-zz1lf
    @rafiullah-zz1lf 2 месяца назад +1

    Can we use data classes instead of sqlalchemy data class

  • @marcin2x4
    @marcin2x4 2 месяца назад

    I would suggest another topi to cover Arjan: "underscores in Python"

  • @kaskilelr3
    @kaskilelr3 2 месяца назад +1

    3:36 classes should have instances
    6:46 Proceeds to use Enum

    • @ArjanCodes
      @ArjanCodes  2 месяца назад

      Of course, while abiding to the regular way of doing things in Python.

    • @kaskilelr3
      @kaskilelr3 2 месяца назад

      @@ArjanCodes By the way, have you ever considered doing a Kivy tutorial series? I recently made a mobile app and was really struggling because there arent any videos out there that get you to the finish line of having an app on the play store.
      I'd be happy to share everything i know for free but I don't have an audience :)
      I'm pretty confident Mobile app development in Python is gonna get huge, but right now information scarcity is holding people back. Quite a shame really

    • @evlezzz
      @evlezzz Месяц назад

      Fields of enum are actually it's instances, so no contradiction here.

    • @jonaskarlsson5901
      @jonaskarlsson5901 20 дней назад

      a class can't be used without making an instance of it so idk what you mean lol

    • @evlezzz
      @evlezzz 20 дней назад

      @@jonaskarlsson5901 It can. Class methods and static methods could be used on class directly, same for class attributes. That should be avoided, but it's possible for sure.

  • @mikefochtman7164
    @mikefochtman7164 2 месяца назад

    I always like 'getter/setter' when there are restrictions on what values should be allowed. Like your bank balance example. If an instance of a class would be 'invalid' in some way when one of its member elements has a bogus value, then don't trust users of said objects to modify directly.

    • @simonhaines7301
      @simonhaines7301 2 месяца назад +1

      a setter with validation is the most fundamental example of "business logic" and is exactly what classes are intended for

  • @terrencemoore8739
    @terrencemoore8739 29 дней назад

    Usually your program isnt going to be just a main function and some classes/functions, what happens when you have a function that takes a class call another function that calls a class, i should add both class instances at the main function level? It seems like it could get out of hand after 3 or so class instances being passed in

  • @Stabbles
    @Stabbles 2 месяца назад +2

    13:57 AI caught stealing our money in 4k

  • @yomajo
    @yomajo 2 месяца назад

    Has Arjan, covered situations where different providers (protocol implementations) rely on different arguments? Can anyone link a vid if he did?

  • @MicheleHjorleifsson
    @MicheleHjorleifsson 2 месяца назад

    in the email service example if you had more than one email service how would the protocol know which one to use ?

  • @digiryde
    @digiryde 2 месяца назад

    Dataclasses in Python can be a fantastic way to start and are fairly easy to convert to a class if need be. Normally, though, you never need to. :)

  • @kaskilelr3
    @kaskilelr3 2 месяца назад

    Related to type annotations: I often end up passing all of my **kwargs to the same inside function, but then you are basically blind when you call the outside function. Is there a way to wrap a function like this and preserve type and documentation info?

  • @ApprendreSansNecessite
    @ApprendreSansNecessite 2 месяца назад

    I'm having a lot of trouble using Protocol.
    There is something about it that does not work with mypy, or maybe is it Pylance.
    I start with a Protocol, it seems to be working for a while, but then comes a scenario in which type narrowing fails, or type inference maybe, then I have a useless and painful code poking session and I end up replacing the Protocol with a normal base class and it works as expected.

  • @ramimashalfontenla1312
    @ramimashalfontenla1312 2 месяца назад

    Superuseful!

  • @adityaalmighty1
    @adityaalmighty1 2 месяца назад

    3:12 when I try to use relative imports I get the relative import error. I don't quite understand why this worked in your case when I also have the same folder structure

  • @djl3009
    @djl3009 2 месяца назад

    Nice! 👌

  • @darkbluewalther
    @darkbluewalther 2 месяца назад

    It's worth noting that TypedDict can be a lighter alternative to dataclass when you don't need to have a class.

  • @GBOAC
    @GBOAC 2 месяца назад

    1:59 line 9: using a list comprehension when you only need a generator expression is also bad practice

  • @CppExpedition
    @CppExpedition Месяц назад

    i am recomending you so much

  • @kaskilelr3
    @kaskilelr3 2 месяца назад

    My rule of thumb is always:
    use classes if something has a state that changes
    Use a function otherwise

  • @codures
    @codures 27 дней назад

    But, since both "process" and "cancel" are referring to the Order, shouldn't better to have them inside Order?

    • @ArjanCodes
      @ArjanCodes  27 дней назад

      Not necessarily. Cancelling an order, maybe, but processing (or fulfilling) an order might involve many steps (packing, shipping, inventory management etc) and have many dependencies. IMO that should not be the responsibility of the Order class.

    • @codures
      @codures 26 дней назад

      ​​​@@ArjanCodesI was referring to the order's inner data only (like delivery/billing, status, eta, etc). I wasn't trying to stuff unrelated processing inside. My question was made in this sense, my apologies if it wasn't detailed enough in the first place.

  • @r75shell
    @r75shell 2 месяца назад

    First example with "composition" about managers and employees - is not composition in common sense. Second example with "composition" about mixins is more like it, because of most popular languages nowadays use references for all objects, for example: Python, JavaScript, Java and so on. But initially, composition is when object have everything of other objects as its parts. What you show was called "delegation" some time ago. I don't know what it's called nowadays. The difference is that your object delegate some work relying on other objects, which often shared by other objects. Easier to explain it for C/C++ users: composition is when you have other class as a field, delegation is when you have a pointer or reference to other class as a field.
    In the end, the video is most about which patterns to choose, and how to use them correctly.

  • @nickolayfetlistov4416
    @nickolayfetlistov4416 2 месяца назад +2

    The second is not completly correct, I'm a lazy, and want to import with autocomplete and forget about module name, actually second case, it's if I have a few methods with the same name

  • @rontheoracle
    @rontheoracle 2 месяца назад

    If one can start from A and finish at B by just using function, then why use class? Classes look and feel complicating, more codes are needed to use classes, with no major benefit compared to functions. Seems like classes are only useful in some really edge cases.
    Thanks for listening to my rants.

  • @QazaqCode
    @QazaqCode 2 месяца назад

    So, quit using oop and write functions instead. What a Joy!)))

  • @vkc102
    @vkc102 2 месяца назад

    A pet peeve of mine is seeing a dataclass with application methods and it's own __init__ constructor. Like why even make it a dataclass when plain old python class would do. Another one is a property getter that mutates class state.

  • @c.michaelfisher1123
    @c.michaelfisher1123 2 месяца назад

    New Drinking Game to really retain the learning: Take a drink every time he says 'code'.

  • @nordexo
    @nordexo 2 месяца назад

    isn't a python module signified by the fact that it's a folder that contains __init__.py?
    a folder with just python files is just a bunch of files or am i wrong? 🤔

    • @ArjanCodes
      @ArjanCodes  2 месяца назад +1

      In Python, a module is a file. A package is a folder normally containing a __init__.py file and other files and subfolders.

  • @dirtdart81
    @dirtdart81 2 месяца назад

    typing.Callable is deprecated since Python 3.9. The docs say it is now an alias to collections.abc.Callable.

    • @ArjanCodes
      @ArjanCodes  2 месяца назад

      Good point. I’ll use the new Callable location in upcoming videos (even though I don’t find ‘collections.abc’ a logical place for something like Callable, which is neither an ABC nor a collection).

    • @dirtdart81
      @dirtdart81 2 месяца назад

      @@ArjanCodes agreed! But I'm not a core python dev so who knows 🤪

  • @Dyanosis
    @Dyanosis Месяц назад +1

    Your employee is a a bad example of how to simplify since an employee cannot do the same things as a manager.

  • @TN-cx4qi
    @TN-cx4qi 2 месяца назад

    The copilot is strong with this one 😂

  • @mojotmn
    @mojotmn 2 месяца назад

    you should have started with "stop using print in your prod"

  • @francescoanastasio2021
    @francescoanastasio2021 2 месяца назад

    3:50 He destroyed Java in a classy manner 😂😂

  • @astronemir
    @astronemir 2 месяца назад

    I’ve missed this kind of video where you really hack away at code 😊

  • @ingframin
    @ingframin 2 месяца назад

    I never heard of mixins before this video and I am utterly horrified by them. 😐

  • @dmbrv
    @dmbrv 2 месяца назад

    👍

  • @IanAllans
    @IanAllans Месяц назад

    enterprise-ai AI fixes this. Avoid these bad practices OOP.

  • @cyAbhishek
    @cyAbhishek 2 месяца назад

    Wait wait wait, but Arjan was the OOP guy, no?

  • @dynamicgrad3820
    @dynamicgrad3820 2 месяца назад

    Imo almost all data should be verified, even the name should note contain numbers

  • @EW-mb1ih
    @EW-mb1ih 2 месяца назад

    I still don't get why you don't like OOP anymore. Even in your example, OOP would be a better choice. Like "process order" and "cancel_order" could be reduced as two methods ("process" and "cancel") from the Order class... Or maybe am I missing something?

    • @ArjanCodes
      @ArjanCodes  2 месяца назад

      The thing is that both processing and cancelling an order in the real world is probably quite a few lines of code. If you put all of that in a single Order class, this quickly becomes hard to work with.
      By the way, I still like OOP, but I do try to keep classes small. If functionality is complex (like in the case of processing or cancelling an order), I prefer to put that in a separate function. That also allows you to introduce an abstraction layer so writing tests for those functions becomes easier.

  • @rma-nm5vb
    @rma-nm5vb 2 месяца назад

    There is an old rule to all of this: KISS :-)

  • @BrainInAVat7
    @BrainInAVat7 Месяц назад

    If the class is just data why use a class at all when a dictionary would do?

  • @jonaskarlsson5901
    @jonaskarlsson5901 20 дней назад

    19:29 your preferred solution about Mixins just seems like more work?
    "They can create all sort of problems" is not enough of a statement because any fool can say that but only a genius can explain why. And in your example I don't see any problems with it

  • @cheebadigga4092
    @cheebadigga4092 2 месяца назад

    I love "fake" or "proxy" classes. Python lets you do all the things, so just creating a static or data class to use it purely as proxy for some other underlying technology (executing a command, listening or writing to a socket, etc) is a great fit for the debate for whether it makes sense to make it a class ends with "yes" :D

  • @LeaTex
    @LeaTex Месяц назад

    mmmm.... but if you are using OOP, it's not so good to mix it with modules and functions. I know python gives us a lot of freedom, but the final code could be a mess. in your last example you have a pretty nice model, and then you change it completely, remove the classes, and create functions and types!! really?? the final code is much more complex and less readable than the initial code. ¯\_(ツ)_/¯
    actually you don't need "process_order" or "cancel_order". following your ideas, you can put everything into "main". and the "saver" is unnecessary because it doesn't have any parameters, so calling it has no effect on any order.
    so, I got your point, but the examples are really bad, and won't work on a real and complex software.