What is "@total_ordering" in Python?

Поделиться
HTML-код
  • Опубликовано: 5 июн 2024
  • How's it going everyone? Today we're going to be learning about a decorator in Python that can supposedly save us the trouble of defining the comparison dunder methods in our classes.
    ▶ Become job-ready with Python:
    www.indently.io
    ▶ Follow me on Instagram:
    / indentlyreels
    00:00 Learning Python made simple
    00:05 Intro
    00:25 Imports
    00:37 What is @total_ordering?
    01:56 Comparisons
    05:13 Actually using @total_ordering
    07:41 Important note #1
    08:24 Important note #2
    08:51 Where can you use this?
    09:20 Do we really save time?
    10:50 Summing it up

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

  • @cmdlp4178
    @cmdlp4178 24 дня назад +30

    I guess the reason you should define `__eq__` is because `__lt__` is called twice like: `a == b not (a < b) and not (b < a)`.

    • @TheJaguar1983
      @TheJaguar1983 21 день назад +1

      Tested that, because it seemed logical to me too, but nope. It seems that, if you don't include __eq__, there is a default implementation that, I assume, just compares object ids, which you probably don't want. For some reason, total_ordering doesn't take that into consideration.

    • @dansplain2393
      @dansplain2393 День назад

      Isn’t it just that the sort order of equivalent values would be undefined without it, leading to different results between runs?

    • @TheJaguar1983
      @TheJaguar1983 День назад

      @@dansplain2393 __eq__ is not actually undefined if not supplied in a class, it defaults to comparing whether the two compared objects are the same object.

    • @dansplain2393
      @dansplain2393 День назад

      @@TheJaguar1983 yes but if the object is being compared by value (which it normally is) then the result when values are equal will be undefined

    • @TheJaguar1983
      @TheJaguar1983 18 часов назад

      @@dansplain2393 but it is defined. Basically, for anything derived from object, A==B actually runs A is B.

  • @andreablengino6324
    @andreablengino6324 24 дня назад +20

    You only require ___lt___ and ___le___ because python can swapsobjects in the comparison. Let's say you have two instances _a_ and _b_ *of the same class* _C_ (that's important) and you implemented only ___lt___ and ___le___ . Then you perform _a > b_ comparison: python will looking for the ___gt___ method of _a_ instance but cannot find it, so it reverse the search and looks for the ___lt___ method of _b_ instance and use it. It is the same behaviour for ___mul___ and ___rmul___ .

  • @coolcodingcat
    @coolcodingcat 24 дня назад +9

    I think they reccommend defing __eq__ for efficiency, because without it: a == b, has to be: not(a < b) and not(b < a), so two calls to less than where most everything else can be just one less than call:
    a < b: a < b
    a > b: b < a
    a >= b: not(a < b)
    a

  • @calebwest9300
    @calebwest9300 24 дня назад +8

    I cracked up about the amazon part as I am an Amazon warehouse worker in Australia and I can confirm this to be true… 🤣

  • @frankhudson9846
    @frankhudson9846 24 дня назад +13

    I think it's primarily for consistency's sake, i.e. having a single implementation for every comparison to use so they don't have any unforseen consequences because a < b, b < c, but somehow a > c?

    • @Indently
      @Indently  24 дня назад +5

      I didn't think about the consistency aspect, thanks for sharing!

    • @landsgevaer
      @landsgevaer 24 дня назад

      But "a < b < c therefore a < c" (transitivity) is precisely an example of what is nót enforced by the decorator when defining only one method.
      Other inconsistencies are though.

    • @spaghettiking653
      @spaghettiking653 24 дня назад +1

      Why would it not ensure transitivity? It's not a total order if it isn't transitive lol.

  • @vorpal22
    @vorpal22 24 дня назад +1

    Interesting. I know what a total ordering is from math, but I didn't know that Python had this functionality built in.
    Once again you teach me some new and fun Python fact, @indently! Thank you!

  • @landsgevaer
    @landsgevaer 24 дня назад +7

    Towards the end of the video, an advantage of a total ordering decorator over implementing both gt (or le) as well as lt (or ge) might be that you *impose* that it has well-defined logic.
    That is, (a >= b) should always equal ((a > b) or (a == b)).
    If you define all these comparison methods separately, that is no longer guaranteed. Potential source of nasty bugs.
    Having written that, (a == b) should also equal ((a >= b) and (b >= a)), so not sure why they advice you to implement eq. Furthermore, (a >= a) should always be True, and if (a >= b) and (b >= c) then (a >= c) should be True; so there are still plenty of ways to screw up the total ordering even if you only implement a single operation. 😉 But those errors are presumably less easy to make and easier to spot.

    • @Indently
      @Indently  24 дня назад +1

      Thanks for sharing!
      There are some things I wish the docs were more explicit about and am happy when you guys can share more information regarding the topic :)

    • @abwesend
      @abwesend 24 дня назад +1

      example can be found in the video. lt implements with .lower() eq has a bug and forgets that. Duplicated code may introduce a bug, latest when you fix sth and forget all occurrences

    • @abwesend
      @abwesend 24 дня назад

      i mesnt le not eq

    • @laytonjr6601
      @laytonjr6601 23 дня назад

      As other comments mentioned, (a==b) is equal to (not(a

  • @Sclafus
    @Sclafus 24 дня назад +5

    3:09 "other" is not of type self. You can compare it with anything, so the correct type is Any.
    You can check that other is of type self with isinstance.
    def __eq__(self: Self, other: Any) -> bool:
    if not isinstance(other, Person): # unfortunately Self does not work here..
    return False
    return self.__dict__ == other.__dict__

    • @Indently
      @Indently  24 дня назад +2

      MyPy doesn't like it either and prefers something like:
      def __eq__(self, other: object) -> bool:
      if not isinstance(other, Person):
      return NotImplemented
      I personally use Self there to force the appropriate context actions into the logic inside the dunder method.

    • @IManu96I
      @IManu96I 24 дня назад +3

      You can do `isinstance(other, type(self))`. This way when you subclass `Person` you do not need to override `__eq__`

    • @DrDeuteron
      @DrDeuteron 24 дня назад

      @@IManu96I also self's dunder class attribute, but maybe that's not a clean?

  • @fr9714
    @fr9714 16 дней назад

    Some people do this to appear cool but 2months later even they can’t figure out why something doesn’t work.
    If management and debugging becomes a headache then it’s not worth doing it in the first place to look cool
    From personal experience I’ve seen that most code becomes throwaway and gets redone or updated later on anyways. While legacy code does exist most don’t want to maintain it. They’d rather rewrite it anew.
    And if you’re the one maintaining it then keep your own headache low by doing the most straightforward thing.

  • @echtertimo
    @echtertimo 24 дня назад

    nice vid

  • @horoshuhin
    @horoshuhin 24 дня назад

    8:57 you've read my thoughts. hahaha

  • @johanngerell
    @johanngerell 23 дня назад

    What's the code font in the thumbnail? (not in the clip)

  • @SU3D3
    @SU3D3 24 дня назад +12

    99% of my code is in Haskell but I continue to keep up with Python. I started with BASIC, C, and Motorola CPUs LOL!

    • @vorpal22
      @vorpal22 24 дня назад +1

      What do you code in Haskell, out of curiosity? I love FP, and I've gone through Haskell several times, but I tend to prefer Kotlin even though Haskell obviously has far better FP constructs like HKT and Kotlin's pattern matching is very weak.

    • @SU3D3
      @SU3D3 24 дня назад +2

      ​@@vorpal22I am writing a concept-oriented programming language designed for AI agent development with a NLP compiler based on LLMs, and I'm leveraging Haskell as a base language and parser. I want to maintain Haskell's purity throughout my superset language.

    • @SU3D3
      @SU3D3 24 дня назад +1

      ​@@vorpal22I am planning on providing the resources as open source.

    • @SU3D3
      @SU3D3 24 дня назад +1

      @@vorpal22
      **Multi-tenancy concept in Haskell**
      ```haskell
      -- Define an abstract data type for entities
      data Entity = Entity String
      -- Define a record type for R0N1N, which represents the collective entity
      record R0N1N (entities :: [Entity]) where
      compartmentalize :: [Entity]
      compartmentalize _ = entities
      ```
      In Haskell, we don't have direct equivalents to Python's classes or Java's records. Instead, we use algebraic data types (ADTs) and functional programming concepts.
      **Corporation concept in Haskell**
      ```haskell
      -- Define a record type for Corporation, which represents an organization
      record Corporation (entities :: [Entity]) where
      getEntities :: [Entity]
      getEntities _ = entities
      ```
      Again, we use records to represent the Corporation concept. Note that Haskell's `record` keyword is used to define a new data type with specific fields.
      These Haskell code snippets demonstrate how the concepts of multi-tenancy and corporation can be implemented using functional programming principles and algebraic data types.

    • @SU3D3
      @SU3D3 24 дня назад +1

      @@vorpal22
      **Multi-tenancy concept in Haskell**
      ```haskell
      -- Define an abstract data type for entities
      data Entity = Entity String
      -- Define a record type for R0N1N, which represents the collective entity
      record R0N1N (entities :: [Entity]) where
      compartmentalize :: [Entity]
      compartmentalize _ = entities
      ```
      In Haskell, we don't have direct equivalents to Python's classes or Java's records. Instead, we use algebraic data types (ADTs) and functional programming concepts.
      **Corporation concept in Haskell**
      ```haskell
      -- Define a record type for Corporation, which represents an organization
      record Corporation (entities :: [Entity]) where
      getEntities :: [Entity]
      getEntities _ = entities
      ```
      Again, we use records to represent the Corporation concept. Note that Haskell's `record` keyword is used to define a new data type with specific fields.
      These Haskell code snippets demonstrate how the concepts of multi-tenancy and corporation can be implemented using functional programming principles and algebraic data types.
      R0N1N is the RNN I've created for the AIOS.

  • @miguelvasquez9849
    @miguelvasquez9849 14 дней назад

    i dont know if we can get an unexpected behavior

  • @aik21899
    @aik21899 24 дня назад +1

    I guess you don't need the equals operator due to antisymmetry of total orders:
    if a>= b and b>=a then a==b
    Or, if '>' is given:
    Not(a>b) and not(b>a) is equivalent to a==b
    This needs two comparisons though

    • @Kommentierer
      @Kommentierer 24 дня назад +1

      Some languages are a bit more elegant here. The compare method you implement can either return 0 (equal), or something greater or less that 0.

    • @coolcodingcat
      @coolcodingcat 24 дня назад

      ​@@Kommentierer spaceship operator

  • @verysb
    @verysb 24 дня назад +1

    That’s going to return False
    first because the information…
    or actually we didn’t even call main
    That’s kind of ridiculous so…
    😂😂😂

  • @Programming_Of_All
    @Programming_Of_All 22 дня назад

    Normal Amazon warehouse worker 💀

  • @Hendiadyoin1
    @Hendiadyoin1 24 дня назад +1

    Surprised nobody else made the joke, so here I go...
    In communism all people are equal, well some are more than others but thats beside the point
    Also, all people need to eat? Thats news to me