Тёмный
No video :(

5 Things You're Doing Wrong When Programming in Python 

Jack of Some
Подписаться 30 тыс.
Просмотров 417 тыс.
50% 1

Опубликовано:

 

21 авг 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 666   
@StanislavSchmidt1
@StanislavSchmidt1 4 года назад
Instead of "if isinstance(aggregate_list, type(None))" it should simply be "if aggregate_list is None"
@Tospaa
@Tospaa 4 года назад
Or just use 'if not aggregate_list:' since an empty list evaluates to false.
@RainerDreyer
@RainerDreyer 4 года назад
I write `aggregate_list = aggregate_list or []` because it's a single line per parameter
@JackofSome
@JackofSome 4 года назад
Oooh this is a good one. Never even thought to do this I always just do `x = in_x if in_x else 0` or something stupid like that
@kered13
@kered13 4 года назад
@@RainerDreyer ​ Tospaa Be careful using things like "if not aggregate_list" and "aggregate_list or..." because these will capture all falsey types. You need to think carefully about whether it will be correct to treat all falsey values the same.
@RogerValor
@RogerValor 3 года назад
"is None" was also my first thought. however if it is generally to prevent any kind of empty dataset of wrong type, another simple one is x = x or []
@afvallejos
@afvallejos 3 года назад
This is the simplest explanation of ”if, name, main” I’ve seen
@moemanm1202
@moemanm1202 3 года назад
i was immediately sold after i heard that explanation. subscribed
@theRealtensigh
@theRealtensigh 3 года назад
Me too!
@immortaljanus
@immortaljanus 3 года назад
It's the only explanation that makes sense so far. I have a feeling most people that tried to explain this one to me don't really know why, they just pass the knowledge on. This is the WHY that very few people actually know.
@Quisl
@Quisl 3 года назад
However he didn't use the first tip in any other example in this video :D
@sahej97
@sahej97 3 года назад
Couldn't agree more Now, I'll never forget it lol
@marksverdhei
@marksverdhei 3 года назад
Number 6: never give your variables a name that also happens to be a reserved function name such as 'list, iter, str...' as can be seen at 5:40
@DanEllis
@DanEllis 3 года назад
Came here to point this out! `str` is used in the very next example, so it should be clear how this could bite you in the ass.
@myzel394
@myzel394 3 года назад
Lol I thought you would write "Never gonna give your variables up, never gonna let them down..."
@PMA65537
@PMA65537 3 года назад
See Also RFC1178
@davemittner5911
@davemittner5911 3 года назад
This would have been a good one but I do want to say how much I hate how Python claimed names that are so dang useful. I'm *always* having to check my use of "type" as a variable name.
@marksverdhei
@marksverdhei 3 года назад
I agree that this sometimes can be annoying. A typical getaround, other than picking a different name is adding an underscore at the end. e.g. type_ . Otherwise if you happen to use reserved names too much it might just be that you're not specific enough in the naming
@timotejbernat462
@timotejbernat462 3 года назад
0:22 - if __name__ = “__main__” 2:12 - KeyboardInterrupt Exception is an exception 4:40 - Error traceback 6:57 - Membership check via sets 9:02 - Mutable defaults
@woodfun6570
@woodfun6570 3 года назад
By the way "KeyboardInterrupt Exception is an exception" is not the only problem. Also when bare except is used there are many problems with any other errors which might arise but you cannot recognize them
@charlubermensch2395
@charlubermensch2395 3 года назад
3:38 control+backslash is amazing, thanks you for this tip!
@JackofSome
@JackofSome 3 года назад
Something something great power and great responsibility. This will not allow your program to clean up, which can become a problem
@LordRenegrade
@LordRenegrade 3 года назад
@@JackofSome - actually that's simply SIGQUIT, you CAN catch it. Er, well, you can in C. sigaction(2) or such can change the behavior. There HAS to be python interfaces to that...
@JackofSome
@JackofSome 3 года назад
@@LordRenegrade there's signal handling but it's a hit or miss.
@lawrencedoliveiro9104
@lawrencedoliveiro9104 3 года назад
Or just do a “kill” from another terminal session.
@aadarshkumarshah8795
@aadarshkumarshah8795 3 года назад
You can even force shutdown your PC 🙃
@Ganerrr
@Ganerrr 3 года назад
i somehow didn't know about sets, #4 is really nice
@Rabixter
@Rabixter 3 года назад
Yea that was my favourite one out of all the examples. Didn't realise they were more efficient.
@OwletRL
@OwletRL 3 года назад
Ayeee it's ganer
@kausthubkrishnamurthy2410
@kausthubkrishnamurthy2410 3 года назад
yeah i had no idea myself - that's a nice little hidden speedup. I thought I'd set it up vs list comprehensions as well and you're still talking significant speedup. Method A: in_names_loop | Elapsed time is 0.000108 seconds. Method B: in_names_set_loop | Elapsed time is 0.000027 seconds. Method C: in_names_list_comp | Elapsed time is 0.000089 seconds. Method D: in_names_set_list_comp | Elapsed time is 0.000019 seconds.
@gokharol
@gokharol 3 года назад
Yeah but a set will not hold duplicate values
@Rabixter
@Rabixter 3 года назад
@@gokharol Yea true. Its good when you want to iterate through unique set of values . Otherwise I would just use numpy arrays and apply some transformations to that.
@JackofSome
@JackofSome 4 года назад
Some necessary clarifications: 1) the use of .format in the first example was intentional since I assumed f strings to be less known (and for some reason thought they were introduced in 3.7), looks like I was mistaken in that assumption. 2) Thanks to all that pointed out that the isinstance was unnecessary in the last example. I think I got burned by not using it with numpy types at some point and since have almost exclusively defaulted to it but I can't find the exact reason now... **shrug** 3) Desktop environment is xfce4, window manager is i3-gaps :D 4) *sigh*, yes I accidentally shadowed str in one example. Don't be like me.
@JackofSome
@JackofSome 4 года назад
I've looked into it but haven't had the chance to try it in detail. Definitely interested but will only switch if there's significant benefit and if I can take my i3 workflow with my without any changes.
@BarHarel
@BarHarel 4 года назад
TLDR: 1. Use if name == main 2. Don't except: without exception 3. Don't print(exception), cause it only shows message and not traceback 4. Don't loop O(n^2) on lists, use sets. 5. Don't use mutable default arguments in function definitions.
@xtra9996
@xtra9996 4 года назад
6. Be careful with sets if your list contains equal elements.
@aouerfelli
@aouerfelli 3 года назад
@@xtra9996 If the purpose is only testing membership, then sets are the most suitable for that.
@JackofSome
@JackofSome 3 года назад
Exactly. It's not about the construction cost of about the cost of checking membership a million times. If that's not the use case then you're not gonna get a noticeable improvement.
@morgengabe1
@morgengabe1 3 года назад
Mutable defaults can be useful in some cases, particularly when you want to use a cache like when recursively scraping links from a website without repeating yourself. I think it's for dynamic programming.
@lawrencedoliveiro9104
@lawrencedoliveiro9104 3 года назад
@@morgengabe1 There are better ways to do that, like with class variables.
@radeksvoboda7629
@radeksvoboda7629 3 года назад
Much more interesting issue with python: create a random float list with millions of data. Add single NaN value into the list. Call sorted(). The list returns without any exception, the list appears sorted, but under thorough investigation there are chunks in the list that are not sorted! Don’t expect python documentation to tell you about this behavior. Lesson to be learned: you must always check your float lists for NaNs before calling sorted()!
@gesuchter
@gesuchter 3 года назад
Are you talking about numpy or plain pyhton? Sounds like a floating point error while comparing the numbers
@radeksvoboda7629
@radeksvoboda7629 3 года назад
@@gesuchter Python list, not numpy arrays.
@a.b.c.d.e...
@a.b.c.d.e... 3 года назад
Good to know, but adding NaN to a list of numbers sounds like a generally bad idea anyway.
@radeksvoboda7629
@radeksvoboda7629 3 года назад
@@a.b.c.d.e... Looks like you never worked with an external sensor data.
@a.b.c.d.e...
@a.b.c.d.e... 3 года назад
@@radeksvoboda7629 it should almost always be your priority to replace or remove NaN values from your data, before doing anything else with it. Otherwise, countless problems can arise from working with your dataset, if you don’t keep checking for NaN values every time you use the data.
@tkachenko9584
@tkachenko9584 3 года назад
One more idea about the last one: instead of having 'aggregate_list = []' we can write 'temp = ()', and 'aggregate_list = list(temp)' inside the function. This works because tuples aren't mutable
@Xaphanius
@Xaphanius 4 года назад
The 5th mistake was indeed subtle!
@badoli1074
@badoli1074 4 года назад
I'm sure i ran into it not knowing how it happened or how to fix it and just abandon the default values for that function...
@mudkip_btw
@mudkip_btw 3 года назад
That one took me 3 hours to realise during a computational physics assignment. Not fun.
@Matt-dk3wl
@Matt-dk3wl 3 года назад
That last one is a darn PYTHON BUG in my book.
@JonathanRossRogers
@JonathanRossRogers 3 года назад
I learned to avoid using mutable types as default values the hard way. It would be great if mutable types were disallowed by the runtime, but unfortunately, I don't think there's a way to check whether an arbitrary value is mutable.
@ricosrealm
@ricosrealm 3 года назад
That last one is counter intuitive. Python should generate a new list for each call, not recycle the initial default value
@KungFoolFighting
@KungFoolFighting 3 года назад
Being a relatively infrequent user of python, all of these tips were new to me and pretty useful, thanks a lot!
@0x1e02
@0x1e02 4 года назад
Just had to debug the 5th mistake. Just costed me a couple hours... Never again
@k_drive
@k_drive 3 года назад
i love reading through these comments! they're the types of code reviews u just dont get if the team u work on doesn't really care about code quality or you're not working professionally in code yet. i honestly miss seeing semantics debates like these
@royz_1
@royz_1 3 года назад
11:21 on line 9, "if aggregate_list is None:" should also work just fine
@avonray9147
@avonray9147 3 года назад
Thanks for the last one. Seems quite like a potential mistake I could make in the future, and rip my hair off trying to debug it.
@gloweye
@gloweye 2 года назад
For those unfamiliar with the broader names of python language constructs, when this guy talks about a "hashtable", he means a python dict. (which is an implementation of the hashtable concept. Python sets are basically dicts without values.)
@michaelcrosby7715
@michaelcrosby7715 3 года назад
Very helpful! I'm new to coding and I'm finding that, with these types of videos, if I have to rewatch to understand it, I'm stretching myself more mentally. Keep it up!
@zdwlees
@zdwlees 2 года назад
I actually found out the first one the hard way and it was a great example to me of how no matter how many tutorials u read, u have to do something wrong to understand why it is wrong. It wasn't game breaking but by doing a small project and making a small error I taught myself an incredibly useful concept and that has been my approach to coding since.
@aadarshkumarshah8795
@aadarshkumarshah8795 3 года назад
This guy started with a bang..he is going to make a big hit in future as the people will come to know about this channel ❤️
@willjohnson4579
@willjohnson4579 3 года назад
2:14 I try to avoid infinite loops as much as possible. They have their place, but there's almost always a for or built-in that can be used
@alpine_chr
@alpine_chr 4 года назад
this is invaluable for where I am currently at. I appreciate this video.
@JackofSome
@JackofSome 4 года назад
Glad I could help :).
@gapedandamazed6988
@gapedandamazed6988 3 года назад
the name == main situation was extremely well explained. THANK YOU
@JonathanRossRogers
@JonathanRossRogers 3 года назад
6:00 I usually use the logging module, which has built-in support for including tracebacks in logged messages. You don't even need to define a variable in your except statement. Just add "exc_info=True" to your logging call. docs.python.org/3/library/logging.html#logging.Logger.debug
@ylyassun
@ylyassun 3 года назад
The best explanation for if name == main function so far.
@kirkgraham6469
@kirkgraham6469 3 года назад
I've watched this 2 or 3 times now. Each time I learn more because I'm more experienced and this makes more and more sense. Very well done and helpful. Thanks!
@filipe_paixao
@filipe_paixao 3 года назад
"thank God it's only 5 mistakes. after solving them I'm gonna sleep"
@achilesmatrix8543
@achilesmatrix8543 3 года назад
I never thought a video like this would ever be useful to me. I've been programming in python for more than a year now and everything said in this video cleared up a lot of questions I never thought I had
@krists666
@krists666 3 года назад
Nice video, makes it very easy to understand some common Python pitfalls with this eli5 way of explaining things. One note about data structures - hash sets in Python are called Dictionaries ie. `kv = {"key": "value"}` and also set can be initialized with `mySet = {"seven","8","nine"}` instead of `mySet = set("seven","8","nine")`
@JackofSome
@JackofSome 3 года назад
I prefer the explicit syntax for sets myself because I'm my experience dicts are more common and if you're quickly perusing code it's easy to mistake a set for a dict. Thanks for watching.
@vic9380
@vic9380 3 года назад
Beautiful presentation. Very helpful to zoom in so much on the screen.
@xc_gwpl
@xc_gwpl 3 года назад
What are the benefits of using "isinstance(x, type(None))" over "x is None" ?
@Diego01201
@Diego01201 3 года назад
Well... None.
@Actanonverba01
@Actanonverba01 3 года назад
1.Great demo of 'name=main' usefulness, 2.except Exception - Good, 3.Traceback module Also Pretty Good, 4.Use sets more -Good, 5.Aggregated lists - Cool
@isnakolah
@isnakolah 3 года назад
The mutable defaults really gave me a headache a couple of months ago. I couldn't tell my code was failing. I can't remember how I fixed it, but at least now, I can't repeat the same mistake. Thanks Jack👍👍
@chunheguo9230
@chunheguo9230 3 года назад
regarding the trace back 4:40 , if you are using the std logging module, set exc_info=True. This will automatically grab the traceback and you don't need to import a second library
@chrisalexthomas
@chrisalexthomas 3 года назад
number 5, regarding the aggregate_list argument, sounds like a really dumb mistake on behalf of the python language developers. It's not logical for this behaviour and it just sounds like a quick memory/performance hack that should never have happened.
@erumabo
@erumabo 3 года назад
I guess that's to make it consistent, every time you pass a list or a mutable object it's passed by reference
@chrisalexthomas
@chrisalexthomas 3 года назад
@@erumabo alright, so that’s a good rationale. However why the SAME object every time? Couldn’t they create mutable objects each invocation and get mutability and avoid this problem at the same time? For a language as dynamic as python, this is kind of a weird thing to do, everything else is dynamic, why not this? See what I mean?
@erumabo
@erumabo 3 года назад
@@chrisalexthomas I agree, its a really weird and unexpected behaviour, I suppose that at the moment of declaring the function a reference to an object gets stored in it so when you call it it's the same, which would be quite dumb and even a safety risk so probably I'm wrong. Still, the fact that it even happens at all is really weird, better to simply tests for None as the video recommends.
@geraldthaler8880
@geraldthaler8880 3 года назад
The default value is an expression that gets evaluated when the function definition statement is evaluated. The result is remembered by the function as the default argument. Storing the expression itself instead and evaluating it on every function call would be more expensive: An immutable default like (1, 2, 3, 4) or even load_default_tuple() would need to be evaluated every time creating a new object which would be expensive. To make this fast, you would have to define a global name caching the value which is ugly. And even then a global name lookup would be required at every call. The way it is is the most performant in the common case.
@chrisalexthomas
@chrisalexthomas 3 года назад
@@geraldthaler8880 yes, we already established that, but it’s still broken and it’s still bad behavior. It’s not logical to do this. Like I said in the first comment, it’s just for performance. But I would prioritize correctness over performance any day of the week and this looks like a mistake that should never have happened but now we are stuck with it ¯\_(ツ)_/¯
@ricardolima5206
@ricardolima5206 3 года назад
This last example was something I imagine doing a lot, but I can't remember experiencing the issue. Nice video.
@JSDudeca
@JSDudeca 3 года назад
OMG - The last example was one that I did not know about!! Why that is considered a good language feature just boggles my mind. I know that Python 2 was very wacky in lots of places, but why this persisted into Python 3 is just baffling.
@shrddr
@shrddr 3 года назад
11:10 why so fancy, can't you just do if aggregate_list is None?
@RogerValor
@RogerValor 3 года назад
german keyboards struggle with ctrl+\ - but luckily in a shell you can also go ctrl+z and kill %1
@rubixtheslime
@rubixtheslime 3 года назад
I always forgot which symbol it is kill $ 1 # Nope kill & 1 # still wrong kill ! 1 # wow look at this idiot kill @ 1 # what even is that kill % 1 # okay yep
@D0Samp
@D0Samp 3 года назад
^\ or SIGQUIT is Ctrl+4 on a German keyboard.
@crashraynor7291
@crashraynor7291 3 года назад
Actually pretty useful. I don't know if ill ever run into passing mutable variables into functions but now I'm ready for what otherwise could've been a very tough bug to sort out. Do you know why we call them 'bugs'? Fun fact: back before everything was micro and transistors were baseball sized, computers were huge and created tons of heat. This led to computers being housed in very open buildings for air-flow, which in turn gave way to problems with bugs... moths mostly would land and nest in the warmth. They were large enough and conductive enough that they could short transistors together, meaning you literally had to go "find the bug" that was hosing your system :) in modern systems of course due to the enormous change in power consumption and overall component size and also large-scale refrigeration (rather than ceiling fans and screen doors lol) we don't have insect problems anymore, only 'bugs'...and bit flipping solar flares lol
@lolokm3
@lolokm3 3 года назад
for the last one I usually do : def add_names_to_aggregate_list(names, aggregate_list=None): aggregate_list = [] if aggregate_list is None else aggregate_list Nice api, easy to ready and one lined
@atussentinel
@atussentinel 3 года назад
And when using the multiprocessing module, the "if name == main" is a must.
@jacob_90s
@jacob_90s 3 года назад
I applaud you for pointing out the sets/lists tip. Something I encountered a few years ago in Coldfusion which has greatly sped up many scripts for me. Just to point out for people using other languages as well, in Coldfusion we don't have sets (at least not natively), just arrays & structs (which are essentially just hash tables bts anyway). Structs can be use for much the same purpose. Just do Struct[string] = true or just some default, small value. One thing that I'll do especially if the struct will be used very heavily and if the list of strings is managed by myself or a person, is to store all the strings initially in an array, where it's a bit more straightforward what you're doing, but then afterwards create a struct using all the values in that array, and then use the resulting struct essentially as a set as described above.
@abebuckingham8198
@abebuckingham8198 2 года назад
Sets are implemented as hash tables with value None.
@requiembay5411
@requiembay5411 4 года назад
Thanks so much Jack of Some. I can finally read the entire error with traceback instead of just the type of error. Extremely useful for my bug that only happens at night so I can't figure out what is happening by running it.
@JackofSome
@JackofSome 4 года назад
Nice. Like I said in the video most logging systems handle this case correctly by default so really look into using one.
@user-kz3kh8bt2k
@user-kz3kh8bt2k 4 года назад
I finally understood if name eq main
@Gunstick
@Gunstick 3 года назад
I even did not know this exists. 🤷‍♂️
@xxmythmakerxx
@xxmythmakerxx 3 года назад
okay finally understood what the if main name this is for...
@akkisdiary
@akkisdiary 3 года назад
I literally faced the same last mistake. Thanks for the solution. 🤩
@canardeur8390
@canardeur8390 3 года назад
Hi, thank you for this video. I particularly appreciated the last part with the mutable default. I am far from being a Python expert but when trying sorting a list according to three different ways, using three different functions plus measuring the running time for each, I have noticed that when calling functions 2 and 3, I was passing the already sorted list. I didn't understand it the way you explained but rather that lists were being passed by reference while variables were being passed by value. So I just copied the list before calling each sort function.
@brpawankumariyengar4227
@brpawankumariyengar4227 3 года назад
This was a very useful and informative video. Sadly I am guilty of all 5 mistakes that were mentioned but I will use the tips in this video to improve my code. Thank you so very much for this video ….this is very very good 🙏🏻🙏🏻🙏🏻
@jkobain
@jkobain 3 года назад
I actually prefer doing like _result = parameter_passed _*_or_*_ some_default_value # This way the value of the right side on the _*_or_*_ will be used if the left side has been evaluated to an empty string, a zero, None or False._
@MrPiradoHD
@MrPiradoHD 3 года назад
I just saw it also happens on diferent objects of same classs. class Foo: def foo(self, x, y = []): y.append(x) return y a = Foo() b = Foo() a.foo(2) b.foo(3) prints [2,3] Thats interesting. But only works on lists, not on ints for example
@JackofSome
@JackofSome 3 года назад
Yep. Same reasons too. Ints are immutable so that's why it doesn't happen. All mutable types are susceptible
@googlesellsmydata
@googlesellsmydata 3 года назад
Even better way to handle default None value: def add_names_to_agg_list(names, aggregate_list=None): aggregate_list = aggregate_list or [] ...
@Wineblood
@Wineblood 2 года назад
For the mutable default arg, I use a syntactically lighter version: default_arg = default_arg or []
@SiddharthMandhata
@SiddharthMandhata 3 года назад
Dude!! You're really good. The way you talk... seems so naturally funny and pleasing. I'm subscribing right away. 🙂😊
@shivamidolboy1
@shivamidolboy1 3 года назад
For the last mutable list problem, it can also be solved by creating a deep copy of the passed list into another variable (as the first step of the function). This will ensure that the argument that was passed does not get changed in place
@erichstocker8358
@erichstocker8358 2 года назад
One has to be careful with converting lists to sets as lists ALLOW and may WANT duplicates. However, a set will not allow duplicates so you can find if something in the list via a set but can't check whether it appears more than once in the list via a set.
@pablogarin
@pablogarin 3 года назад
#5 happened to me once... and it was that bug that I spent a lot of time trying to solve (weeks actually), and my solution at the moment was to make sure to pass an empty array as an argument, and not use the default... eventually, I got to a similar solution, but it kind of bugged for a long time that this happened... and I have to admit until now I didn't know this happened to every mutable type! Thanks!
@sameriskander8275
@sameriskander8275 3 года назад
Thank you for this tutorial. In fact, I have the following comment: Problem #4) You mentioned that set is a HashTable. But, the set is the HashSet, and the dictionary is the HashTable or HashMap. Thanks and Regards.
@marcgirard475
@marcgirard475 3 года назад
Very nice explanation of "main" if, thanks!
@goldfishbrainjohn2462
@goldfishbrainjohn2462 3 года назад
All of these are very helpful. Now I know how to deal with those old behaviors. Thank you!
@nikschuetz4112
@nikschuetz4112 3 года назад
use if aggregate_list is None: aggregate_list = [] and you can even say aggregate_list = aggregate_list or []
@PaulA-kr1nl
@PaulA-kr1nl 3 года назад
None in Python is a singleton. You can use “is” operator to ensure identity check.
@NorfolkCatKickers
@NorfolkCatKickers 3 года назад
6) round rounds 1.5 to 1. also in 5 def func(x=None): if x is None: x= [] I prefer that
@Marcuinhos
@Marcuinhos 3 года назад
I recently learned about if name = main at work and it could've changed my life if I knew this when I was taking Python courses, thanks for spreading knowledge!!!
@andrewspanopoulos1115
@andrewspanopoulos1115 3 года назад
For #5, you could have the following: def add_names_to_agg_list(names, aggregate_list=None): aggregate_list = aggregate_list or [] ....
@11yoyomama
@11yoyomama 3 года назад
Why check “isinstance” for type(None) rather than just saying “if aggregate_list is None”? Genuinely curious
@codegeek98
@codegeek98 3 года назад
I'm pretty sure I've seen official documentation recommend "is None"; it's like checking if "ptr == NUL" in C
@danielazulay4936
@danielazulay4936 3 года назад
I used to do it too. That's crazy, It's so accurate.
@herp_derpingson
@herp_derpingson 4 года назад
8:30 I think you should also talk about the CPU/Memory tradeoff. Sets eat more RAM but less CPU. But since RAM is a lot cheaper than CPU, it is usually the correct choice.
@MrWorshipMe
@MrWorshipMe 3 года назад
The more pythonic way of dealing with default list parameter is setting that default to None, but in the function write aggregate_list = aggregate_list or []
@Revlos
@Revlos 3 года назад
Python is such a useful coding language. I'm not experienced but have done a fair few projects and found python can accomplish most tasks easily.
@timlind3129
@timlind3129 3 года назад
Great vid.... considering I'm newer to python this was cleanly and concisely stated.... wish all guides were as clean.
@JackofSome
@JackofSome 3 года назад
That's the primary goal of this channel so glad to see it worked :)
@the-old-channel
@the-old-channel 3 года назад
I would definitely blame the language design for the last one. It feels so unintuitive for arguments to be initialized at the definition time... I wonder why did they implement it this way? Is there a pattern where it is somewhat useful?
@JackofSome
@JackofSome 3 года назад
That's honestly a pretty fair stance to take. Within the current design why this happens makes perfect sense to me, but I can't for the life of me think that the current design is good.
@shanedixon3539
@shanedixon3539 3 года назад
Python doesn't really have static variables so it is kind of useful in any situation where your typical static variable would be useful. (function objects can have member variables as an alternative implementation, but it's ugly).
@DanEllis
@DanEllis 3 года назад
@@shanedixon3539 I disagree, because it doesn't generalize enough to be a useful pattern. I'm surprised they didn't fix this when they had the opportunity in Python 3.
@JackofSome
@JackofSome 3 года назад
I personally prefer member variables for this. It's much more explicit and easier to grok (which is more in line with the zen of python).
@user-dy4nj1cd2d
@user-dy4nj1cd2d 3 года назад
@@DanEllis Techically I see no ways to avoid it, because it will break default arguments. For example user could put some function as default argument. But functions are also mutable in a way. But nobody probably will say that this is bad idea because people usually do not mutate functions. And I see no way to distinguish what user wanted exactly. It is possible to check specifically for list/dict/etc. but it is road to hell.
@Mateusz-Maciejewski
@Mateusz-Maciejewski 2 года назад
5. example shows (if I understand it correctly) that default arguments in a functions are like static variables.
@bob_jones
@bob_jones 3 года назад
Instead of if isinstance(aggregate_list, type(None)), you can simply do if aggregate_list is None
@TheSauxer
@TheSauxer 3 года назад
The last one, about the mutable defaults, had to learn it the hard way during a course project. It was in OOP where I assigned each client a list. The list repeated itself for each client, it was as if every client shared the same list. It took me quite a few hours until I found something about it in stackoverflow.
@davemittner5911
@davemittner5911 3 года назад
Really like #4 & #5. Been doing Python for 4 years and didn't realize those.
@erumabo
@erumabo 3 года назад
That last one sounds like something that should happen to other languages that automatically pass mutable objects by reference, yet this is the first time I've ever saw of it
@JackofSome
@JackofSome 3 года назад
It's not quite just about mutability. The default list becomes part of the locals of the function which is different and could be avoided while keeping passing by reference.
@MrRyanroberson1
@MrRyanroberson1 3 года назад
I would also note that the final program you sampled will in-place modify any list you pass into it, so you don't even need a return statement if the list was pre-defined. This can be really annoying but at the same time really useful, and i wish there was an easier way to know when or if anything is being changed in-place
@JackofSome
@JackofSome 3 года назад
There's this for analyzing mutation in your codebase github.com/boxed/mutmut
4 года назад
TIL about Ctrl+\
@JackofSome
@JackofSome 4 года назад
It's a life saver some times, but I absolutely hate having to use it. Out of curiosity what brought you to this video? I've had a sudden rush of viewers in the last two hours and my analytics is not being helpful about the source.
@du42bz
@du42bz 3 года назад
@@JackofSome I know that this one year old but the yt recommendations brought me here
@JackofSome
@JackofSome 3 года назад
That's awesome. I've been wondering what's driving all this traffic again. Did you get the video on your home page?
@du42bz
@du42bz 3 года назад
@@JackofSome Yes. The holy RU-vid-Recommendations have choosen you
@JackofSome
@JackofSome 3 года назад
Praise the algorithm
@jftsang
@jftsang 3 года назад
I prefer to do: import logging; try: ... ; except Exception as exc: logging.exception(exc)
@danieljensen2626
@danieljensen2626 3 года назад
I'm a bit confused about how checking if a string is in a set can be an order one operation? How does that work computationally?
@JackofSome
@JackofSome 3 года назад
The set is keeping a vanilla array under the hood (say, with 1000 slots). The string (or really any input) is put through a hashing function that's designed to produce as unique an answer as possible for different inputs. The hash is then mapped to a number between 0 and 1000, and that becomes the index of the element (there's more details here in how collisions are handled but this is the gist). So it's more memory intensive, and there's more overall computation involved compared to just looking up an index, but the time complexity does not depend very strongly on dataset size
@danieljensen2626
@danieljensen2626 3 года назад
@@JackofSome Ahhhhhhh. I was sort of thinking "unless it knows which specific memory location to check based on the content of the string?", but I failed to make the jump to hashing and using the hash to generate an index. I'm glad big brain people come up with clever tools like that for the rest of us to use, haha. And thanks for replying!
@matthieud.1131
@matthieud.1131 3 года назад
I didn't know about the last point, and it really makes me think that Python creators must have been drunk when making this choice. I can't think of any situation where it is useful to have a default argument implicitly behave like a static variable. I can't think of any other language where this is the case.
@HeraldoS2
@HeraldoS2 2 года назад
For the last issue, I have found useful to use the list method it would look like: list(aggregate_list) = []
@Coolrishi20
@Coolrishi20 4 года назад
Just wanted to say thank you and keep up your good work.
@JackofSome
@JackofSome 4 года назад
Thanks so much for watching. Out of curiosity what brought you to this video? I've had a sudden rush of viewers in the last two hours and my analytics is not being helpful about the source.
@a.b.c.d.e...
@a.b.c.d.e... 3 года назад
I thought this video was rather uninteresting until I saw the last one. This is the type of behavior that creates bugs that you can spend hours fixing them on, because everything looks so logical and normal
@Daniel_Zhu_a6f
@Daniel_Zhu_a6f 3 года назад
There is also one common beginner mistake in python: using inheritance outside of frameworks/metaprogramming tasks. Python makes interfaces and compositions very easy and intuitive, so one should use them instead.
@dew9103
@dew9103 3 года назад
number 6 use f strings instead of .format, it will be slightly shorter but will add up very quickly
@JackofSome
@JackofSome 3 года назад
Pinned comment
@jhonatanmaia5652
@jhonatanmaia5652 3 года назад
OH god, the change between a list to a set wil lhelp me a lot right now. Thank you
@arkadiuszmazurek8898
@arkadiuszmazurek8898 Год назад
About __main__ first time somebody explained me what is function of this mechanics. Thank you :)
@slookify
@slookify 3 года назад
wow, after 2 minutes i already learned the best time saver. now i know where those weird behaviors came from
@aryanmn1569
@aryanmn1569 2 года назад
hey I suggest you two way to fix that ugly solution to agg list 1st one: a = a or [] 2nd one (readability explosion): a = a if a is not None else list()
@Hulan6
@Hulan6 3 года назад
Mutable default parameters plagued me for a long time. It's one of only two places where python's underlying interpreter rules explicitly differed from what I would consider "reasonable" expectations. The other is the unfortunate way that python scoping rules interact with "closers" (python does not have true closures, hence the problem): # Take this (very contrived) sample code def foo(): ls = [] for verb in ["start", "end", "play", "stutter"]: ls.append(lambda x: f"{x} {verb}") for fn in ls: print(fn("I")) Because of the "there can be only two" scoping of python (global and local), the variable which should be stored in the closer (verb), is instead stored in the local scope, and is overwritten on each iteration. Most people, especially coming from any sort of functional programing background would look at this and say "Oh it prints 'I start', 'I end', 'I play', and 'I stutter'". Nope, just prints 'I stutter' four times. It's not something that comes up very often; I doubt more than one percent of python programs ever encounter it, but if you're expecting lexical scoped variables (which is what python *seems* like most of the time), it can really throw you for a loop... It certainly threw me for one when I stumbled upon it. I'd almost go as far as calling both bugs in the language, but there are rational justifications for persistent default parameters and the python scoping rules, and changing either would require fundamental changes to the language. Still it's frustrating for the developer when the language seems to - at first glance - break it's own rules in unexpected ways. Edit (a bunch of times): That's what I get for changing my example half way through writing.
@JackofSome
@JackofSome 3 года назад
That's a very interesting example. Thanks for sharing. I must say I actually did expect the outcome we got since verb is more like a pointer which is being changed but I do agree that not having an obvious solution is frustrating.
@Hulan6
@Hulan6 3 года назад
@@JackofSome Yeah, in that example, the problem isn't as pronounced I think, but a real-world example is *a lot* more wordy. Simply put though, let's say you have a constructor that builds a bunch of callback functions and returns them. It builds the callbacks in a loop for code brevity. The caller receives a list of functions, each of which enclosing a different seed (based on the iterator), but because of the closure weirdness, they actually all end up with the same seed, instead of different seeds. Here's a more direct contrast, since you would expect code written in a function to work the same as code written inline. This works as expected: --------------------------------------------------- ls = [] def factory(a): def cb(x): return a + x return cb for i in range(10): ls.append(factory(i)) for fn in ls: fn(5) --------------------------------------------------- But this doesn't --------------------------------------------------- ls = [] for i in range(10): def cb(x): return i + x ls.append(cb) for fn in ls: fn(5) --------------------------------------------------- Which, from an first-blush perspective is like "aren't they the same, except cb is defined in a different function in the first example?" Hence why it broke my brain when I encountered it.
@BladeOfLight16
@BladeOfLight16 3 года назад
Converting to a set only makes sense if you're going to do multiple membership checks. Building the set has its own performance overhead, so you need to make sure it's worth paying that up front cost.
@JackofSome
@JackofSome 3 года назад
That ... was the whole point 😅
@codeman99-dev
@codeman99-dev 3 года назад
I would actually argue that "Not logging errors correctly" is wrong for printing exceptions. Instead create a logger and use logger.exception("msg") ... it effectively calls traceback.print_exc() but now you have the option of turning off that debugging.
@MrAwesomenes5
@MrAwesomenes5 4 года назад
I hate that python does that thing you described in the fifth example. It also does it if you work with dicts. Ich you want to duplicate a dict, you have to use .copy(). Can you tell me why this is not like this by default? What's the benefit of having multiple dict names pointing at the same dict?
@JackofSome
@JackofSome 4 года назад
Python by default does not pass things by value but instead by reference (except for some basic primitives). This idea is fundamental to the language design and, in my opinion, gels quite well with the intention of the language. By doing this they also avoid complicating the language by removing a layer of decision making in most situations but of course that has a few unfortunate side effects. For me the biggest benefit is a sort of efficiency this provides. Nothing is ever copied without my explicit say so. I like that.
@MrAwesomenes5
@MrAwesomenes5 4 года назад
@@JackofSome Thanks for the reply. Why am I then able to just duplicate a list or a value without the .copy() command? To me this seems a bit inconsistent.
@JackofSome
@JackofSome 4 года назад
How are you duplicating?
@xXneorlinXx
@xXneorlinXx 4 года назад
This is partly for saving some memory. All mutable types are passed by reference
@badoli1074
@badoli1074 4 года назад
​@@xXneorlinXx Also performance, no? The data would need to be cloned before executing a function, which would slow down the execution with huge data structures...? Passing a pointer is cheap.
@Mr1995Musicman
@Mr1995Musicman 3 года назад
I use this to make the solution to #5 a bit less ugly: aggregate_list = aggregate_list or []
@JackofSome
@JackofSome 3 года назад
Yep, I learned this after making the video. Definitely nicer.
@Lolwutdesu9000
@Lolwutdesu9000 3 года назад
While the last error is no doubt important to look out for, the example given wasn't the best. You can literally add lists, or use the extend method, instead of needlessly iterating through list elements and adding them individually. This might throw off people and think they need need to make needlessly complicated functions like the one shown.
@JackofSome
@JackofSome 3 года назад
It's a demonstration done with the idea that the people watching have some reasonable familiarity with the language. Literally no one will look at this and go "gee I better stop using extend from now on".
@TheKafaniKirarim
@TheKafaniKirarim 3 года назад
BTW, to make the example of Mutable Defaults a bit prettier, you could've just said *if not aggregate_list:* instead of *if isinstance(aggregate_list, type(None)):*
@dannymurphy2823
@dannymurphy2823 4 года назад
i know i am real late to this channel, but love the clear simple examples..awesome
@JackofSome
@JackofSome 4 года назад
No time like the present 🙂 Trying to get a new video out before the heat death of the universe
@ddarkodev2923
@ddarkodev2923 3 года назад
Thank you for sharing your experience! This is very useful 💪
Далее
Make Python code 1000x Faster with Numba
20:33
Просмотров 442 тыс.
Zombie Boy Saved My Life 💚
00:29
Просмотров 8 млн
FizzBuzz - You Suck at Coding [0]
12:35
Просмотров 404 тыс.
Five Amazing Python Libraries you should be using!
17:19
Should you learn C++?? | Prime Reacts
20:29
Просмотров 349 тыс.
The Complete Guide to Python Virtual Environments!
15:52
Top 18 Most Useful Python Modules
10:50
Просмотров 928 тыс.
Premature Optimization
12:39
Просмотров 790 тыс.
25 Nooby Pandas Coding Mistakes You Should NEVER make.
11:30