I was wondering, Could you make some sort of code review type videos ? I know it probably takes more time but at the same time you could also explain a lot of other stuff, like how to handle big sized projects, how to make code more professional on a larger scale ... This could really be cool I think
Eschewing long function names simply makes naming much harder. You end up having to make important distinctions with fewer words, so grammar comes into play. This function, for example, should be named get_discounted_total or get_discounted_price, because that's what it's returning -- not the sum of all discounts to be applied to a product. Playing grammar nazi with code is nobody's idea of a good time, and it's particularly difficult on teams where people have different native languages. Better to make your peace with longer names, especially since any IDE worth the name will offer to autocomplete it for you.
While I’m opining from a position of extreme novice in coding, I have absolutely noticed myself using more detail/length in my function names when needed. This helps me and my neurodivergence keep things understandable when going back to review or continue working on a project. I imagine it would be just as helpful, if not more, for a group/team.
I like how I came to watch the video thinking it would just be normal stuff i would already know and ended up learning how to create function documentations
7:23 I'm gonna do a sad frikkin "errm, actually" here, so technically it should drop an exception or segfault if the locale is missing or corrupt, in which case you could return a generic time format like %H:%M:%S (there seems to be no built-in support for standard ISO 8601 formats).
This function has two responsibilities. Sum and percentage discount. Better to split / extract to 2 simple generic functions and create another one that combines both. Better code reuse. And what about validating percentage value? Thank you
there is already a generic function for sum: the sum function. It is also faster, because it's implemented in C. The function he wrote already combines both functionalities. There is no need to write a separate one liner function to apply a percentage, it is literally just a multiplication
@@ziul123 True, but his point still stands. Why pass in a list of prices when you could simply pass in the total already summed? And it should be called something like apply_discount(price, rate).
I think documentation has a double side: useful but terrible if it's not updated. And it's easy to forget to update, even in the video the documentation needed to be updated. I prefer comments in the hard parts so I understand what the programmer wanted to achieve or do..
Valid point about documentation needing to be maintained. That's an argument for keeping docstrings simple and concise (unlike in this video), _not_ and argument for not using them at all. Comments and documentation have different purposes. Both are useful and should be employed where appropriate. The convention is that docstrings explain the _what_ while comments explain the _how._
totalAfterCalculatedDiscountWithLocalisationAndRebates(), which is overridden in DiscountAndRebateCalculationInstantiationFactory. Java.............. 🙄 But in case, you were serious: Java uses camel case, Python uses snake case. If one of my peers uses the former format in the latter language, I will not approve their PR. I see that a lot among more junior, fresh-out-of-uni coders.
05:46 i'm not sure it's pep but probably you write dosrctring in a wrong way. it starts with a verb. like "get current time" instead of "a function that returns you a current time".
Why do you need to specify the type of the "now" variable? Even in static type language lile c++ you can write "auto" and let the compiler figure out the variable type. Here - almost any IDE will know that the returned value is "datetime" and will give you same intellisense support without the surplus verbosity.
Compiler wouldn't warn you if the function would start, after some modification, returning strings. If you write it explicitly, then you get proper warning if you modify something and the return type is wrong.
In this case, either the rest of the code will be compatible with the new type which means the new type has the same protocol or is a subclass of datetyme type, or the intellisense will alert me of incorrect/incompatible usage.
@@ArtyomKatsapActually, yeah, you're right. I thought you talked about function signatures somehow, but yeah, the variable typing is imo kinda pointless there, the datetime.now() is already a typed function. If you were to reassign "now", it would make more sense to type it, but here, it seems purely fluff.
@@gJonii In most cases you do not need to type the variable type. (I wouldn't do it either.) But typing variable type is sometimes helpful, like the following code: from datetime import datetime now = datetime.now() today = datetime.date(now) # Get today's date if today == now: print('today is now') else: print('today is not now') # Print this line because the type of "now" is different from the type of "today". If you type variable type it is easier to understand the type of the variable.
@@gJonii If you type variable type it is easier to understand the type of the variable. now = datetime.now() isoNow = datetime.isoformat(now) print(f'{now=}, {isoNow=}') if isoNow == now: print('isoNow is now') else: print('isoNow is not now') # Print this line because the type of "isoNow" is different from the type of "now". But I usually don't type variable type because it's very troublesome.
The overall idea of this is great, but the example has issues. 1. You use Iterable, but you iterate over it twice, which is unsafe, because an Iterator, which can only be looped once is also an Iterable. 2. You declare float as the sub-type for prices, but check for int or float later. Just use SupportsFloat as the hint instead and explicitly cast later, e.g. via map(float, prices). This will also have the benefit of doing the type validation for you and raise if needed, instead of even needing to call isinstance.
Its a convention, not a real getter as per Java or similar. You could call a function that calculates coefficients for a neural network get_coefficients. Why do you care?
I don't like it when people duplicate the parameter types in the docstring. You have the type clearly specified in the function signature so no need to repeat it. (And if you're using tools to process the docstring that don't use the function signature types get better tools.)
For the function name I would say: 1. As short as possible, but as long as needed. And if the name is too long, then the function might need to be divided. Otherwise LGTM !
If i put all my functions in 1 file, and the "executable" code in another, is there some general guideline for where I should put fixed variables? like, if i call them in the "executable" file, then put them there, otherwise, put in the function file...?
Putting all your functions in one file makes your code hard to read and makes debugging a pain. If your code is clogged up with util functions then putting those in a file can be ok as far as variables please on behalf of everyone that will read your code define them in the main file
but the point of dunder name == dunder main is that you don't need to separate the code like that, unless another script also needs the function--but then you're writing a package. "fixed variables" is just not pythonic..."module constants" go after imports, before def's.
The first example was not a good choice (ok, it's an example only), because as a rule, we should NEVER write a function which only purpose is call another function. get_time() is completelly useless since we can simply use directly datetime.now() Also, inside the useless function, we create a useless variable now, where we could return datetime.now() directly. Second example is very good. Great video!
I think you took the short function names too far. Based on the name `get_time`, I expect the *time* and not a string. I’d do `get_time_locale` or something, even with the return type.
also and/or emphasis on what you did: 1) one point of return (if you must have branches) 2) don't have branches (except for guard clauses) 3) Use guard clauses: raise exceptions early. Most important: Be pure: No side-effects. Don't modify arguments! e.g.: >>>sorted(list_) returns a sorted list w/o modifying the argument. Modify objects only in their one methods: >>>list_.sort() and don't have a state: same arguments means same result (rand and date time notwithstanding).
about the type annotations; i think they're use- and surely helpful BUT, for me as a not very experienced coder who's still figuring out how to do stuff the best way and which techniques are available, and whilst discovering new modules and their functionalities, it can be somewhat distracting to already start using type annotations as much as possible, so my take at it is to use them as long as it stays simple, so to at least get used to them for now and to have a base to build up on later, specially once my scripts start to become bigger. same for docstrings btw..
Use Python because it it quick and pithy. Once you start adding in this pseudo-typing, error handling and extensive documentation you lose that, and it is a sign that you should be choosing a different language. Right tool for the job.
@@DrDeuteron Look before you leap is not left out of the discussion in terms of error handling. While LBYL can be redundant or expensive in terms of performance, it doesn't nullify the fact that if done correctly, it gives you a "safer code" and in some cases, a much cleaner or clearer error handling through provision of meaningful feedback.
@@michealakinkuotu8637 I get the POV, but that gets back to OP's point: this is python: Lighten up! The only place I allow branchy code is in error handling. When everything is working, I want minimal cyclomatic complexity.
I do find the excessive hints annoying, the worst is type hinting strongly typed magic methods, like: init(self) -> None: str(self) -> str: I just can't....
The G you pronounce at the end of words (due to accent) is easy to fix... it's silent, simply do not say it! And bingo, your pronounce will get even better!
If your functions is simple enough and had a proper name, a documentation is not needed. Besides keeping documentation up to date double your work load (rewrite the doc, update the example,... every time you refactor) Most IDE can infer input and output so that's a complete waste of time. Documentation is only useful in a library and only for exposed methods.
For the function name I would say: 1. As short as possible, but as long as needed. And if the name is too long, then the function might need to be divided. Otherwise LGTM !
I agree. If my func/method is getting to be more than a screen (and I use a big screen) or around 50 lines (incl copious whitespace), I refactor. Even if it's a helper method used once, with a leading '_' ( to make it "Python Private(tm)").
I was wondering, Could you make some sort of code review type videos ? I know it probably takes more time but at the same time you could also explain a lot of other stuff, like how to handle big sized projects, how to make code more professional on a larger scale ... This could really be cool I think
This would be great!
Eschewing long function names simply makes naming much harder. You end up having to make important distinctions with fewer words, so grammar comes into play. This function, for example, should be named get_discounted_total or get_discounted_price, because that's what it's returning -- not the sum of all discounts to be applied to a product. Playing grammar nazi with code is nobody's idea of a good time, and it's particularly difficult on teams where people have different native languages. Better to make your peace with longer names, especially since any IDE worth the name will offer to autocomplete it for you.
I agree. With modern IDEs there isn't a lot of drawback for long function names.
While I’m opining from a position of extreme novice in coding, I have absolutely noticed myself using more detail/length in my function names when needed. This helps me and my neurodivergence keep things understandable when going back to review or continue working on a project.
I imagine it would be just as helpful, if not more, for a group/team.
I like how I came to watch the video thinking it would just be normal stuff i would already know and ended up learning how to create function documentations
i was disappointed the way i expected to, i knew all of this :c
Been programming with Python for 6 years, but after going through your video, I am hoping to elevate my Python skills!
Thanks for the video. There are several standards for documentation. Making a review of those with its pros and cons would be nice.
3:23 this is commonly referred to as Dependency Injection (DI)
7:23 I'm gonna do a sad frikkin "errm, actually" here, so technically it should drop an exception or segfault if the locale is missing or corrupt, in which case you could return a generic time format like %H:%M:%S (there seems to be no built-in support for standard ISO 8601 formats).
This function has two responsibilities. Sum and percentage discount. Better to split / extract to 2 simple generic functions and create another one that combines both. Better code reuse.
And what about validating percentage value?
Thank you
there is already a generic function for sum: the sum function. It is also faster, because it's implemented in C. The function he wrote already combines both functionalities. There is no need to write a separate one liner function to apply a percentage, it is literally just a multiplication
@@ziul123 True, but his point still stands. Why pass in a list of prices when you could simply pass in the total already summed? And it should be called something like apply_discount(price, rate).
I think documentation has a double side: useful but terrible if it's not updated. And it's easy to forget to update, even in the video the documentation needed to be updated. I prefer comments in the hard parts so I understand what the programmer wanted to achieve or do..
Valid point about documentation needing to be maintained. That's an argument for keeping docstrings simple and concise (unlike in this video), _not_ and argument for not using them at all. Comments and documentation have different purposes. Both are useful and should be employed where appropriate. The convention is that docstrings explain the _what_ while comments explain the _how._
So you can use : instead of = when defining a variable?
name: str = ‘bob’
Variable: type = value
: allows you to assign the type
I learnt a lot of Python techniques from this channel. Thanks Mr. Indently 🙂
Shouldn’t the discount function be renamed to totalAfterDiscount?
totalAfterCalculatedDiscountWithLocalisationAndRebates(), which is overridden in DiscountAndRebateCalculationInstantiationFactory.
Java.............. 🙄
But in case, you were serious: Java uses camel case, Python uses snake case. If one of my peers uses the former format in the latter language, I will not approve their PR. I see that a lot among more junior, fresh-out-of-uni coders.
@@michaelhoffmann2891 Case is usually shop specific. Good on you for enforcing your standard!
@@uruloki True, but I would look *very* askance at a shop that dictated camel case for Python in defiance of PEP.
05:46 i'm not sure it's pep but probably you write dosrctring in a wrong way. it starts with a verb. like "get current time" instead of "a function that returns you a current time".
Why do you need to specify the type of the "now" variable? Even in static type language lile c++ you can write "auto" and let the compiler figure out the variable type. Here - almost any IDE will know that the returned value is "datetime" and will give you same intellisense support without the surplus verbosity.
Compiler wouldn't warn you if the function would start, after some modification, returning strings. If you write it explicitly, then you get proper warning if you modify something and the return type is wrong.
In this case, either the rest of the code will be compatible with the new type which means the new type has the same protocol or is a subclass of datetyme type, or the intellisense will alert me of incorrect/incompatible usage.
@@ArtyomKatsapActually, yeah, you're right. I thought you talked about function signatures somehow, but yeah, the variable typing is imo kinda pointless there, the datetime.now() is already a typed function.
If you were to reassign "now", it would make more sense to type it, but here, it seems purely fluff.
@@gJonii In most cases you do not need to type the variable type. (I wouldn't do it either.)
But typing variable type is sometimes helpful, like the following code:
from datetime import datetime
now = datetime.now()
today = datetime.date(now) # Get today's date
if today == now:
print('today is now')
else:
print('today is not now') # Print this line because the type of "now" is different from the type of "today".
If you type variable type it is easier to understand the type of the variable.
@@gJonii If you type variable type it is easier to understand the type of the variable.
now = datetime.now()
isoNow = datetime.isoformat(now)
print(f'{now=}, {isoNow=}')
if isoNow == now:
print('isoNow is now')
else:
print('isoNow is not now') # Print this line because the type of "isoNow" is different from the type of "now".
But I usually don't type variable type because it's very troublesome.
The overall idea of this is great, but the example has issues.
1. You use Iterable, but you iterate over it twice, which is unsafe, because an Iterator, which can only be looped once is also an Iterable.
2. You declare float as the sub-type for prices, but check for int or float later. Just use SupportsFloat as the hint instead and explicitly cast later, e.g. via map(float, prices). This will also have the benefit of doing the type validation for you and raise if needed, instead of even needing to call isinstance.
I don't like get methods in Python but I like everything else in the video
Its a convention, not a real getter as per Java or similar. You could call a function that calculates coefficients for a neural network get_coefficients. Why do you care?
I would also recommend that you make the validation as function.
I don't like it when people duplicate the parameter types in the docstring. You have the type clearly specified in the function signature so no need to repeat it. (And if you're using tools to process the docstring that don't use the function signature types get better tools.)
Amen. It's redundant. And then you need to remember to update it in both places if something changes. DRY.
I would suggest adding one last step: a test for the function. 😊
Good tips for any programming language!
For the function name I would say:
1. As short as possible, but as long as needed.
And if the name is too long, then the function might need to be divided.
Otherwise LGTM !
If i put all my functions in 1 file, and the "executable" code in another, is there some general guideline for where I should put fixed variables? like, if i call them in the "executable" file, then put them there, otherwise, put in the function file...?
put them where they are gonna be used most, and where it makes sense for them to exist
Putting all your functions in one file makes your code hard to read and makes debugging a pain. If your code is clogged up with util functions then putting those in a file can be ok as far as variables please on behalf of everyone that will read your code define them in the main file
but the point of dunder name == dunder main is that you don't need to separate the code like that, unless another script also needs the function--but then you're writing a package.
"fixed variables" is just not pythonic..."module constants" go after imports, before def's.
I'd put all the code in one file, until you identify some island of functionality that you can separate into its own file with a smaller API.
can you do some tutorial in dart/flutter?
thanks
Beautiful!
my money don't jiggle jiggle, it folds
Seems like :type ...: doc is not reflected in the popup (I mean it doesn't mention anything about the type of the params)
how would I handle a function if I return several value? would I do that as a list and - - > list[Str, into, df. Dataframe()] for example?
tuples! Or a dict.
Especially if it's part of a library API, use a NamedTuple or dataclass, so the callers can access members by name.
Only ever abstract over an EXPRESSION, whatever it's arguments...! Simples (:-)
The first example was not a good choice (ok, it's an example only), because as a rule, we should NEVER write a function which only purpose is call another function.
get_time() is completelly useless since we can simply use directly datetime.now()
Also, inside the useless function, we create a useless variable now, where we could return datetime.now() directly.
Second example is very good.
Great video!
Redundant docs just clutter up the code unless you are making a library api
Brilliant:)
I think you took the short function names too far. Based on the name `get_time`, I expect the *time* and not a string. I’d do `get_time_locale` or something, even with the return type.
also and/or emphasis on what you did:
1) one point of return (if you must have branches)
2) don't have branches (except for guard clauses)
3) Use guard clauses: raise exceptions early.
Most important:
Be pure:
No side-effects. Don't modify arguments! e.g.:
>>>sorted(list_)
returns a sorted list w/o modifying the argument. Modify objects only in their one methods:
>>>list_.sort()
and don't have a state: same arguments means same result (rand and date time notwithstanding).
what vs code extensions are you using? thanks
He is using Pycharm, not VS Code.
about the type annotations;
i think they're use- and surely helpful BUT, for me as a not very experienced coder who's still figuring out how to do stuff the best way and which techniques are available, and whilst discovering new modules and their functionalities, it can be somewhat distracting to already start using type annotations as much as possible, so my take at it is to use them as long as it stays simple, so to at least get used to them for now and to have a base to build up on later, specially once my scripts start to become bigger. same for docstrings btw..
Which IDE are you using?
I don't like calling fractions "percents"; that is a source of self-documenting error or ambiguity.
your first tip of not naming things thoroughly is definitely just an opinion, and arguably a bad one.
comment
Error handling is ok basically, but your example so overloaded
Use Python because it it quick and pithy. Once you start adding in this pseudo-typing, error handling and extensive documentation you lose that, and it is a sign that you should be choosing a different language. Right tool for the job.
This is not true. Documentation and error handling is a crucial part of any software, whether it's statically typed or dynamically typed.
@@michealakinkuotu8637 but LBYL type checking?
@@DrDeuteron Look before you leap is not left out of the discussion in terms of error handling. While LBYL can be redundant or expensive in terms of performance, it doesn't nullify the fact that if done correctly, it gives you a "safer code" and in some cases, a much cleaner or clearer error handling through provision of meaningful feedback.
@@michealakinkuotu8637 I get the POV, but that gets back to OP's point: this is python: Lighten up!
The only place I allow branchy code is in error handling. When everything is working, I want minimal cyclomatic complexity.
I do find the excessive hints annoying, the worst is type hinting strongly typed magic methods, like:
init(self) -> None:
str(self) -> str:
I just can't....
The G you pronounce at the end of words (due to accent) is easy to fix... it's silent, simply do not say it! And bingo, your pronounce will get even better!
I can't hear the G you talked about?
If your functions is simple enough and had a proper name, a documentation is not needed. Besides keeping documentation up to date double your work load (rewrite the doc, update the example,... every time you refactor) Most IDE can infer input and output so that's a complete waste of time. Documentation is only useful in a library and only for exposed methods.
For the function name I would say:
1. As short as possible, but as long as needed.
And if the name is too long, then the function might need to be divided.
Otherwise LGTM !
I agree. If my func/method is getting to be more than a screen (and I use a big screen) or around 50 lines (incl copious whitespace), I refactor. Even if it's a helper method used once, with a leading '_' ( to make it "Python Private(tm)").