Working as a python dev and in my 1 year of practicing python... no one ever explained this well... you're a GEM TIM
I wanted to mention that the if name is main thing is frequently used for test code for libraries. Your code may have some functions to import elsewhere, then you can do examples in the main of how to use them, or try various failure cases, illustrate how to catch exceptions, etc. Also, to those getting into programming, please do yourself a favor and leave a comment in your code as to what it's for. The most likely person to be reading your code later is you, but if you wrote it 6 months ago, it might as well have been written by someone else, so be kind to yourself.
Some details skipped about *args and **kwargs: A forward slash "/" can be used to force parameters to be positional only, thereby making them required when calling and not by name. So, def function(a, b, /, c, d, *args, e, f = False, **kwargs) means a and b cannot have default values, are required to be passed when calling function, AND can't be supplied with their parameter names. e must also be supplied with a value when called. Naming the first * is not required. Doing so simply allows the function to take an arbitrary amount of positional parameters. def function(a, b, /, c, d, *, e, f = False) would require at least 5 arguments (no more than 6) passed to it: a and b are required, c and d are also required and optionally passed as keywords, e must be passed as keyword, f is completely optional, and nothing else is allowed. / must always come before *. * must always come before **kwargs. **kwargs must always be last if used.
The GIL can be bypassed by using parallelism which offers about the same capabilities as threads in other languages. This is more of a naming convention issue rather than an actual thing that you can't do in Python. Python threads are still useful for IO and similar async tasks, but they're simply not traditional threads. It's important to highlight these kinds of things even for beginners so that they don't go out into the world thinking that you can't do parallelism in Python. You absolutely can. It's just called something else.
At around the 4 minute mark you are confusing immutability with references. When you do 'y = x' what you are doing is assigning the reference of the object that x is pointing to, to y. When you assign a new object to x it drops the old reference and now refers to a new object, meanwhile y still refers to the original object. You use tuples in this example, but this is true for lists and dicts. When you change to lists, all you are really demonstrating is that x and y refer to the same object. With your get_largest_numbers() example, if you were to pass a tuple into the function you would get an AttributeError because you were passing an immutable object which doesn't have the sort method.
Because of the GIL, Python multi-threading is not useful for processor-bound computing, but it is still great for I/O bound computing (processor waits for input and output; example: disk read/write or networked data). Multiprocessing is a great way to get around the GIL, when you need to.
Certainly! In addition to multithreading, Python also provides the multiprocessing module, which allows for true parallel execution across multiple processor cores. Unlike multithreading, multiprocessing bypasses the limitations imposed by the Global Interpreter Lock (GIL) since each process gets its own Python interpreter and memory space. By utilizing multiprocessing, you can take advantage of multiple processor cores and achieve parallelism, which can significantly improve performance in computationally intensive tasks. Each process operates independently, allowing for efficient utilization of available CPU resources. However, it's important to consider that multiprocessing comes with some overhead due to the need for inter-process communication. Data exchange between processes can be more involved and slower compared to sharing data between threads within a single process. As a result, multiprocessing may not always be the best choice for every situation. To determine whether to use multithreading or multiprocessing, it's crucial to evaluate the specific requirements and characteristics of your application. If the task at hand is primarily CPU-bound and can benefit from true parallel execution, multiprocessing can be a suitable option. On the other hand, if the workload consists of I/O-bound operations or requires a high degree of coordination and shared state, multithreading might be more appropriate. In summary, the multiprocessing module in Python offers a way to achieve true parallelism by leveraging multiple processor cores. While it circumvents the limitations of the GIL, it introduces additional overhead for inter-process communication, which may impact performance. Careful consideration of the specific requirements and trade-offs is necessary to determine the most suitable approach for your use case.
At 3:45 with: x = (1, 2) y = x you are not doing a copy, it is still an assignment to an immutable object. You can check it with: print(x is y) This returns True, meaning that both x and y are referencing the same object - a tuple (1, 2). And of course print(x == y) also returns True, as we are comparing an object with itself.
Thanks. Most things I already know, so my takeaway: 1.) immutable types = C#/.NET valuetypes or Java primitive types, plain data types in C/C++, Pascal and mutable types = C#/.NET reference types or Java object types, C++ reference, dereferenced pointer data aka memory location in C/C++/Pascal/Assembler. 2.) List comprehension is reverted looping writing style (like perl?). 3.) Function arguments look similar to other languages here added dynamic argument args and * kwargs little bit like C's ... period argument and function. 4.) __name__=="__main__" unique feature? Easy, but unique, as I didn't saw dynamic caller backreference in another language. 5,) I thought GIL is about single threading
Great content. Keep it up. However, I believe there is a mistake at 3:34. You mention that we have some sort of automatic "copying" going on with "y = x" when using immutable types. This is actually not correct. The assignment still works exactly like with any other object - the reference x is assigned to y. Identifiers x and y are simply referring to the same 2-tuple object. After that, you change what identifier x is referring to (another 3-tuple) and print out the two individual objects. The identifiers are still references - even if using immutable objects.
Threading just takes advantage of GIL "idle time". (aka I/O wait-states) The Python "Multiprocessing" module allows you to run exclusive processes in multiple cores. (ie CPU-bound applications.). And (believe it or not) you CAN use threading inside an M/P function if it is coded properly. (according to the rules of MP functions and threads...)
I initially rushed through learning of Python's fundamentals. Whilst these things were mentioned, I didn't grasp the concepts until this video. Thanks.
At around 11 mins another cool thing you could know mention is that if you provide a default variable that is mutable, say a = [], and say you modify the list to look like within the function to say a= [1,2,3], that default varraible is actually now a = [1,2,3] and could create problems if you call that function twice without giving the a argument
I am currently doing Python courses and i struggle a lot, i like that you distinguished parameters and arguments correctly and basically everything else what you've said is exactly the same things, that i got myself/what i've been told. But it is good to refresh upon those conceprts and methods to proceed with my further studying, because i when i am given a task almost everytime i find it hard to came up with the right solution and fail to get the right approach to it. Thank you for the video. Subscribed!
Fiiiiinally I understand those *args/**kwargs!!! Thank youuuuuuu!! 🎉🎉
At 3:30, your description of why changing x does not change y is incorrect and seemingly makes the same mistake many new Python developers make when working with mutable objects such as lists. The assignment `y = x` does NOT create a copy of the original tuple in y. y and x both point to the exact same tuple object in memory. This can be shown with either `y is x` (outputs true) or by printing `id(x)` and `id(y)` which will be identical. When you subsequently assign x to a new tuple, x now points at a new tuple object at different location in memory, which you can see by checking id(x) before and after that assignment. All variables in Python are references to objects. Doing an operation like `y = x`, for any type of object in x, simply makes y a reference to the same object, which is why mutable objects passed as arguments to a function can be mutated by that function. Likewise, anytime you assign a new value to a variable referencing an immutable object, you get a brand new object. if a = 1000, and then a += 1, you also change the id of a to a brand new object of <class 'int'> For some more interesting examples, if you do something like `for i in range(-1000, 1001, 50): print(i, id(i))`, you'll see the id value change for each value, but in most implementations it alternate back and forth between a couple of ids as the interpreter reuses the memory block that was just freed by the garbage collector from the value in the previous loop. The exception is for ints in the range of -5 to 255 (at least in CPython) you'll get a different set of ids because those int objects are pre-allocated when interpreter starts and remain in memory to improve performance, as do the None object and True/False.
00:02 Conceptos importantes de Python Se presentan cinco conceptos importantes de Python que los programadores principiantes e intermedios suelen confundir o cometer errores al leer código de producción. Estos conceptos son fundamentales para comprender y escribir código en Python de manera efectiva. 01:45 Mutable vs Inmutable Se explica la diferencia entre los tipos de datos mutables e inmutables en Python. Los tipos de datos inmutables no pueden ser modificados una vez que se han creado, mientras que los tipos de datos mutables pueden ser modificados. Se proporcionan ejemplos de tipos de datos inmutables (como cadenas, enteros y tuplas) y tipos de datos mutables (como listas y diccionarios). 06:23 Comprensiones de lista Se introduce el concepto de comprensiones de lista en Python. Las comprensiones de lista permiten crear listas de manera concisa y eficiente utilizando una sintaxis compacta. Se muestran ejemplos de comprensiones de lista simples y más complejas. 10:33 Tipos de argumentos y parámetros en Python Se explican los diferentes tipos de argumentos y parámetros en Python. Se cubren los parámetros necesarios, los parámetros opcionales con valores predeterminados, los argumentos posicionales, los argumentos de palabras clave y cómo utilizar el desempaquetado de argumentos y parámetros. 14:15 Uso de asteriscos en Python Se muestra cómo utilizar el asterisco (*) en Python para desempaquetar listas y diccionarios en argumentos y parámetros de funciones. Se explican los usos de *args y **kwargs para aceptar un número variable de argumentos posicionales y argumentos de palabras clave. 17:43 El Global Interpreter Lock (GIL) Se explica el concepto del Global Interpreter Lock (GIL) en Python. El GIL es un mecanismo de bloqueo que permite que solo un hilo se ejecute a la vez en un intérprete de Python. Esto significa que, a pesar de tener múltiples hilos, solo uno puede ejecutarse a la vez, lo que limita el rendimiento en aplicaciones que requieren un alto grado de concurrencia.
Please do a global interpretor lock, love your explanation style, clear and concise. Keep it up
The statement you made at about 3:30 was not correct. Writing y = x (where x is a tuple) does not create a copy of the object, as you can tell by looking at their ids -- they are identical. So, there is no difference between mutable and immutable objects in this respect. That line only creates a new variable that points to the same object as x did.
@TechWithTim