Representing Monetary Values in Python

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

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

  • @evgeniyevgeniy8352
    @evgeniyevgeniy8352 Год назад +64

    5:12
    You should have used sting argument in constructor Decimal('1.1') instead of Decimal(1.1).
    You have lost all you precision when created float 1.1, because float 1.1 is not exactly equal to 1.1 And that is because floats are represented in binary values, but value 1.1 in binary system is periodic, so it cannot be written precisely.
    And that is the reason of getting not exact values at 5:46 when setting precision equal to 50.

    • @kenhaley4
      @kenhaley4 Год назад

      Thank you. I was wondering about that.

    • @ArjanCodes
      @ArjanCodes  Год назад +5

      Good point - totally missed that!

  • @SaniSensei
    @SaniSensei Год назад +49

    Note, if you pass the values to Decimal as *string* instead of float, you won't get those garbage values at the end.

  • @kenhaley4
    @kenhaley4 Год назад +19

    Agreed. Integers is the way to go. I have done this way for years. And I hate it when I see implementations using floats for money. You'd think it wouldn't matter since the float value is extremely close to the proper value, but programmers get tripped up when they run into things like testing a + b == c fails unexpectedly (for example, when a = 1.1, b = 1.2 and c = 1.3.)

    • @MagnusAnand
      @MagnusAnand Год назад

      "fails unexpectedly"
      It's totally expected if you understand binary representation 😜

  • @user-us8th9zn1g
    @user-us8th9zn1g Год назад +15

    Arian, you can write large numbers such as 10000 as 10_000. Much easier to read

  • @fkapps
    @fkapps Год назад +13

    Storage of the values is almost always a concern. If you can’t store the format directly, that’s a big strike against the Decimal format.
    I worked with the Stripe API for two years. It integrated with other code that didn’t store it that way, but ultimately i was convinced that integers were the cleanest solution.
    Creating a class for representing currency as an int under the hood while providing display methods makes a ton of « cents » haha sorry. I often prefer not to make wrapper classes but in this case since storage and display are different it’s a good place for conversion methods that would probably otherwise go in a « util » class.

    • @bn_ln
      @bn_ln Год назад

      great dad joke

  • @FenBender01
    @FenBender01 Год назад +4

    I was surprised to see a tail of garbage digits on Decimal value at 5:33. But this is because you initialise Decimal value with float literal 1.1, which is not equal to 1.1. You shall use string "1.1" instead.

  • @FenBender01
    @FenBender01 Год назад +4

    Using integers as currency value makes sense in simple application. But in trade it is often required to use amounts smaller than 1 cent (i.e gas price with 1/9 cents in the tail). So, Decimals is the way to go.

  • @hcubill
    @hcubill Год назад

    Very useful Arjan! I do have those sorts of issues in my programs. Very nice to see that example with the money class, might also help with conversion between currencies!

  • @szymczakow
    @szymczakow Год назад

    that summation in the end is great! Keep doing that!

  • @manomancan
    @manomancan Год назад +1

    Arjan's two passions: Money and representing money adamantly on Python. That's a man who knows his life's priorities, damn.

  • @JumaleAbdi-tu3zh
    @JumaleAbdi-tu3zh Год назад +1

    Thank you for your impressive tutorial. I am learning Django and made some projects but I wanted to dig deeper and understand how the framework works internally.
    I checked the source code but it was intimidating for me. Would you mind making tutorials on building such a framework from scratch? including template engine, views, routing,db integrations, etc.

  • @loic1665
    @loic1665 Год назад +5

    I think that representing money with integers is quite widely used. In my company we do that for other physical values like speed (25.10 km/h becomes 2510 [100km/h]) or anything which has a unit (Volts become mV, amps become mA etc...)
    One advice to avoid confusion for us programmers when dealing with such representations is to include the units in the names of the variables /function etc... For instance with a function "def calculate_average_current(currents_mA: list[int]) -> int", it's clear that the list of currents to give to the function should be in mA. I like this a lot but it breaks the PEP8 naming conventions, which is not great...

    • @rhard007
      @rhard007 Год назад

      shouldn't that be 2510 m/h ?

  • @silaseul3186
    @silaseul3186 Год назад +1

    Hey Arjan, great video.
    Is it possible that you could make a video about the pint package for representing scientific units? It would be especially interesting to see yourvtake on typehinting and error handling in that case :)

  • @PravNJ
    @PravNJ Год назад

    Another great video thanks Arjan

  • @thesyd1982
    @thesyd1982 Год назад

    You're very helpful, thank you very much.

  • @MrDowntemp0
    @MrDowntemp0 Год назад

    Super helpful! Would've liked to've seen the timeit results of your custom class at the end though.

  • @bigutubefan2738
    @bigutubefan2738 Год назад +1

    Using ints for cash amounts is even easier in more recent Python versions, as underscore_separators can be added anywhere between digits of numeric literals (e.g. for thousands separators). So the cents can be distinguished visually in your source code from the Euros, by writing 100_00 instead of 10000. Hardcoding prices in source code is not a good idea however, but maybe it's useful for storing other fixed cash amounts (e.g. a threshold for money laundering checks?) and making test code more readable.

  • @ksrsundar
    @ksrsundar Год назад

    I think this approach makes more sense.. I do a lot of things with money in pyspark applications I will try this method and add more comments..

  • @fg87fgd
    @fg87fgd Год назад +1

    Two remarks: You partly test Python's velocity to call functions, thus a loop within the function would be better, next you should int() the Integer, round(,2) the float result and around() the numpy result. This changes the result quite significantly, larg int being the fastest, and numpy and VL floats somewhat five times slower...

  • @Fodela
    @Fodela Год назад +1

    Wooow🧠, Thanks a lot. This approach that is not language dependent🦾. You just cured my money handling headache in not just python but all programming languages.👏

  • @ravenecho2410
    @ravenecho2410 6 месяцев назад

    Dude! This is crazy i wish i could share u our git repo, i watch all ur vids but havent seen this one!
    Decimal being slow and incorrect is halarious, we in our use case had to use fractional cents because of LLM cost per 1000 tokens was like 0.00025, we um settled on closest like 50 (rounded) was good enough, but i might make a PR to raise it to the token, just by going from 1e6, to 1e8
    I guess it makes sense my code emulates urs as i watch a bit, still eerie tho

  •  Год назад

    Amazing

  • @EvanYoung-xo8kd
    @EvanYoung-xo8kd Год назад +1

    @arjan A couple of asks for recent python update... The Ruff linter is rising rapidly in popularity, as is the black formatter and poetry. All together this changes project startup significantly as there are configuration settings for Ruff and Black, to add to pyproject.toml. Then, docker seems to have issues with dealing with poetry configurations? Enjoying your work.

    • @ArjanCodes
      @ArjanCodes  Год назад

      Good suggestions, Evan, am already looking into these things!

  • @cuturbs
    @cuturbs Год назад

    Another great video, loving all the python information you give out for free. Could you do a video talking a little about pyspark? =)

  • @cosmicblack
    @cosmicblack Год назад

    as always, very good video

  • @metal571
    @metal571 Год назад

    I believe that for the dunder methods for add and sub you should say if not isinstance: return NotImplemented if you want those to be more "standardized" but for this example yeah, not strictly required at all

  • @PraecorLoth970
    @PraecorLoth970 Год назад

    How would you deal with problems such as interest and taxes? Store everything as ints, but when doing those calculations use the max precision floats, then store the final results as ints?

  • @pancernymisiek
    @pancernymisiek Год назад

    Looking at the comments it seems that one more, more advanced video on that topic would be useful. I would like to see more details on division of floating point numbers and also rounding.

  • @zackwootensc
    @zackwootensc 10 месяцев назад

    Awesome video, thanks

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

      Glad you enjoyed it!

  • @make749perday
    @make749perday Год назад +1

    "All progress takes place outside the comfort zone." -Michael John Bobak

  • @rydmerlin
    @rydmerlin Год назад

    What about space complexity with using a Money class.

  • @vedambala
    @vedambala Год назад

    Arjan, please please put together a Python course from Basic to Advanced. I am sure there will be a lot of people who would be interested

    • @ArjanCodes
      @ArjanCodes  Год назад

      Hi Bala, my channel focuses on more advanced and intermediate programming concepts. There are tons of other channels that focus on beginners. I don't think that fits with my audience.

  • @dont_wanna_tell
    @dont_wanna_tell Год назад

    A long time ago, someone imported this model of information to me: when, doing financial computation, always use a type that implements, the same rounding rules as your tax office uses.
    Cause if you disagree, you’re just asking for the world of hurt

  • @bigutubefan2738
    @bigutubefan2738 Год назад

    Aha, no longer Arjan the Blue, but Arjan the Grey and Arjan the Black!

  • @shaisegev570
    @shaisegev570 Год назад

    I had similar code and found that multiplications and division were not accurate. Int(24.23 * 100) gave 2422 as a result. Solution was to use round before converting to int

  • @abhigyansrivastava4247
    @abhigyansrivastava4247 Год назад

    is 0 the same as 00 in python?

  • @DenizDemirsoy
    @DenizDemirsoy Год назад

    How do you deal with tax calculations? Add 19% tax to 1,71€ is 171*119/100=203,49. Round, truncate?

    • @rezwhap
      @rezwhap Год назад +2

      Typically it will be specified by the relevant law/regulations. Devs don’t get a choice here.

  • @digiryde
    @digiryde Год назад

    Remember BCD (Binary Coded Decimal)? Those were the days. ;)

  • @RAMII19780529
    @RAMII19780529 Год назад +1

    Calculating interest is a pain. We would need more precision, at least 5 places after the decimal point, so instead of using a multiplier of 100 we would need to use a multiplier of 100000. Or you can just use floats and round to the place you need before comparisons.

  • @MagnusAnand
    @MagnusAnand Год назад +1

    I just use the decimal type in Django 😜

  • @meryplays8952
    @meryplays8952 Год назад

    I prefer Integer + Money class, this is the actual domain modeling approach.

  • @edgeeffect
    @edgeeffect Год назад

    Could you talk NumPy in the future... I've just met it for the first time and the documentation is like "hey where the hell is the actual documentation?"

  • @digiryde
    @digiryde Год назад

    This is how Richard Pryor stole all the half pennies in Superman 3.

  • @fabricehategekimana5350
    @fabricehategekimana5350 Год назад

    Great video ! Did you heard about mojo from modular ? It's a new language with a syntax that is a superset of python. It's for AI computing but it's faster than python by default (and integrate other features like ownership, parallelism, hardware finetuning, etc.). It can be a future language that can replace python

  • @adrianzuur5589
    @adrianzuur5589 Год назад +1

    Arjan, your videos are great but also terrible. I used to be happy, but then I watched your channel, and now I hate everyone's code. :)

  • @ingframin
    @ingframin Год назад +1

    No person on Earth should be allowed to own more money than the amount representable by a 64 bit number.