🔺 BIG Python Sin: Using a mutable default argument Don't use a mutable object as a default argument. Default arguments in Python are evaluated once, at function definition time, not each time the function is called. If you have a default argument like: items=[], it will be shared across all calls, and you will get an accumulating state you didn’t ask for. # Mutable default argument def add_item(item, my_list=[]): my_list.append(item) return my_list Output print(add_item(1)) # [1] print(add_item(2)) # [1, 2] print(add_item(3)) # [1, 2, 3] 👑 The best way is to have an immutable object as a default argument. That way, each call will get a fresh list as in the example below. def add_item(item: int, my_list: Optional[List[int]] = None) -> List[int]: if my_list is None: my_list = [] my_list.append(item) return my_list Default arguments are evaluated at function definition time, not call time. When in doubt, use None as the default and create the mutable object inside the function! Learn About Python classes. Full Classes video on YouTube. Link below Link: https://lnkd.in/eJ_zMQis
Benjamin Bennett Alexander’s Post
More Relevant Posts
-
F-strings in Python — Not Just Cleaner. Fundamentally Better. Python has had three ways to format strings over its history. If you’ve only learned the language recently, you might not have encountered the older two — but you will, because they still appear in legacy codebases, documentation, and tutorials written before Python 3.6. The first was % formatting, borrowed from C: name = "Andres" print("Hello, %s. You have %d messages." % (name, 5)) It works. But the syntax is cryptic, the order of arguments is error-prone, and it becomes harder to read as soon as you add more than one variable. The second was .format(), introduced in Python 3.0: print("Hello, {}. You have {} messages.".format(name, 5)) An improvement — more explicit, more flexible. But the variables and the placeholders are still separated. To understand what goes where, your eyes have to travel back and forth across the line. Then Python 3.6 introduced f-strings: print(f"Hello, {name}. You have {5} messages.") The variable lives inside the string, exactly where it appears in the output. No positional arguments. No external references. The code reads the way the sentence reads. Beyond readability, f-strings also evaluate expressions directly inline — which means you can do this: hours = 7.5 print(f"Weekly total: {hours * 5} hours") No intermediate variable needed. And in terms of performance, f-strings are consistently faster than .format() because they are parsed closer to compile-time rather than evaluated fully at runtime. Knowing all three methods matters. Understanding why f-strings became the standard tells you something about how Python evolves — always toward clarity. #Python #PythonMOOC2026 #BackendDevelopment #SoftwareEngineering #LearningInPublic #UniversityOfHelsinki
To view or add a comment, sign in
-
-
Diving Deep into Python Magic Methods . Recently, I started exploring the internals of Python’s magic methods — those special methods that begin and end with double underscores (__). These aren’t typically called directly; instead, Python invokes them behind the scenes to enable powerful behaviors. These methods can be broadly categorized into: * Callable Objects → __call__() * Iterator Pattern → __init__(), __iter__(), __next__() * Finite Iterators * Context Managers ¥ Understanding the for Loop Internals A for loop in Python is actually built on the Iterator Protocol. Under the hood, it relies on three key magic methods: __init__() → initializes the object __iter__() → returns the iterator object (usually self) __next__() → returns the next value in the sequence ⚙️ How the for Loop Works Internally 1)iter(obj) is called automatically This invokes __iter__() and returns an iterator 2) next(obj) is called repeatedly This invokes __next__() and fetches values 3)Loop continues until StopIteration is raised Without it, the loop runs infinitely 🧠 Example: Custom Iterator class Repeat: def __init__(self, msg): self.msg = msg def __iter__(self): return self def __next__(self): return self.msg This will print the same message infinitely because StopIteration is never raised. Key Insight A for loop is essentially syntactic sugar over a while loop using the iterator protocol. Understanding this gives you deeper control over debugging and helps you identify the root cause of issues in iteration-heavy code. ✨ Once you understand what's happening behind the scenes, Python feels a lot less “magical” and a lot more predictable. For better understanding and clarity I suggest referring the image attached. Till then Happy Sunday, Happy learning and Happy growing. #Python #Programming #SoftwareDevelopment #Coding #PythonInternals #OOP #Developers #Learning #Tech #CSStudents #Debugging
To view or add a comment, sign in
-
-
You might want to take a look at this, Everybody says NumPy is faster than Python List. But, How fast ?? Well I looked into it !! So, here is the overhead of every value you use in Python. Let's say you use a value 42. Here is the detailed overhead. ob_refcnt - 8 bytes (For garbage collection, if reference count is zero, then python just deletes it from RAM) ob_type - 8 bytes (For storing what datatype that value belongs to, here that's integer) ob_digit - 8 bytes (For the actual value - 42). Therefore, 24 bytes for each value. Let's take it a step further. Say you have a 4 values to store just [1, 2, 3, 4] and Let's compare Python list vs NumPy array. Python List : Stores Pointers not the actual values and Hence, you need a list of pointers first, each pointer in the "pointer list" points to the actual value that is scattered across different locations of RAM. So, in-order to store 4 elements. 4 x 8 = 32 (pointer list) 4 x 24 = 96 (actual values) Therefore, 32 + 96 = 128 Bytes. NumPy arrays : It's contiguous and also homogeneous. Also, we don't have pointers model. Here we store actual values next to each other. Thus, giving us a easy traversal using strides. 4 x 8 = 32 Bytes. NumPy can store raw values directly because it enforces a single dtype. Since every element is the same size, it can locate any element using simple math (base + index × itemsize) instead of pointers. Python lists allow mixed types and that's exactly what forces the pointer model. Note: I am only comparing the storage models here. Both Python lists and NumPy arrays have their own object overhead which I've intentionally left out to keep the comparison clean. Apart from storage models. There is another reason why NumPy is so powerful in numerical computations and that is vectorization Vectorization in NumPy : When you do np.sum(a), NumPy runs optimized C code across the entire array in one shot no Python interpreter involved. A Python loop hits interpreter overhead on every single element. That's the real reason NumPy can be 10-100x faster for numerical operations. There is reason why this guy is named as "Numerical Python" !!
To view or add a comment, sign in
-
Python: 05 🐍 Python Iterables: Diving Deeper 🚀 We'll work on different complex types (range, list etc.) and strings iteration. We've already known the for loops, now let's dive into deeper and know what is range function returns. 🔍 We will use a built in 'type' function to get the type of an object. 🛠️ For example: type(5) .. it will return <class 'int'>; that means number 5 is an integer value 🔢 type(range(5)) .. it will return <class 'range'>; that means we get the value from a range function that means its an object of type range! 🧊 Primitive vs. Complex Types 💡 In python we have primitive types like numbers, strings, Booleans. We also have so many complex types, 'range' is one of those complex types. So interesting concept of range is, it is iterable which means we can iterate over it or use it in a for loop. That is why we can write code like this: for x in range(3): Here x can hold number in the range in each iteration. 🔄 Result: 1 2 3 Strings are also iterable! 🧵 For example: for x in "python": print(x) It will return: ✨ p ✨ y ✨ t ✨ h ✨ o ✨ n Which means x will hold one character from the string in each iteration. 🔡 List Iteration 📋: for x in [1, 2, 3, 4,..,n]: print(x) It will return: 1 2 3 4 ... ... ... nth X will hold one object from the list in each iteration. 🎯 #PythonProgramming #PythonDeveloper #Coding #python #iterator #DataScience #pythondeveloper #programmer
To view or add a comment, sign in
-
-
💡 How Python makes iterables out of indices Objects that implement the dunder method `__getitem__` are automatically iterable, as long as they: - accept integer indices starting at `0`; and - raise an `IndexError` at the end of the sequence. The dunder method `__getitem__` of the class `ArithmeticSequence`, shown in the diagram below, satisfies both constraints. Since it satisfies both constraints, instances of `ArithmeticSequence` are automatically iterable: ```py seq = ArithmeticSequence(5, 3, 6) for value in seq: print(value, end=", ") # 5, 8, 11, 14, 17, 20, ``` Since Python sees the method `__getitem__`, it infers that the looping behaviour must be to go through the container index by index, producing `seq[0]`, `seq[1]`, `seq[2]`, etc. When an `IndexError` is raised, Python stops iterating. Did you know Python could do this?
To view or add a comment, sign in
-
-
Stop using + to join strings in Python! 🐍 When you are first learning Python, it is tempting to use the + operator to build strings. It looks like this: name = "Gemini" status = "coding" print("Hello, " + name + " is currently " + status + ".") The Problem? In Python, strings are immutable. Every time you use +, Python has to create a brand-new string in memory. If you are doing this inside a big loop, your code will slow down significantly. The Pro Way: f-strings (Fast & Clean) Since Python 3.6, f-strings are the gold standard. They are faster, more readable, and handle data types automatically. The 'Pro' way: print(f"Hello, {name} is currently {status}.") Why use f-strings? Speed: They are evaluated at runtime rather than constant concatenation. Readability: No more messy quotes and plus signs. Power: You can even run simple math or functions inside the curly braces: print(f"Next year is {2026 + 1}") Small changes in your syntax lead to big gains in performance. Are you still using + or have you made the switch to f-strings? Let’s talk Python tips in the comments! 👇 #Python #CodingTips #DataEngineering #SoftwareDevelopment #CleanCode #PythonProgramming
To view or add a comment, sign in
-
FastAPI + No-GIL Python might be one of the most important backend shifts this year Most of the conversation in AI has been about models getting faster. But something equally important is happening at the runtime level. With FastAPI 0.136.0, support for Python’s free-threaded (No-GIL) builds is now becoming practical to experiment with. I wanted to understand what this actually means in a real API scenario. So I ran a simple benchmark: - Python 3.12 (with GIL) - Python 3.13 free-threaded build (No-GIL) Same FastAPI app Same endpoints No code changes For CPU-bound workloads, I saw up to ~8x improvement. This isn’t surprising when you think about it. For years, the Global Interpreter Lock has limited Python’s ability to fully use multiple cores in a single process. Threads never really meant parallel execution for CPU-heavy tasks. Most of us worked around it using multiprocessing, task queues, or by adding more infrastructure. No-GIL changes that model. Now threads can actually run in parallel across cores, which means CPU-heavy APIs can scale more naturally without increasing system complexity. Where this becomes especially relevant: - ML inference APIs - Data processing pipelines - Feature engineering workloads - Real-time analytics backends That said, there are some important caveats: - Python 3.13’s free-threaded mode is still experimental - Not all libraries are thread-safe yet - The ecosystem will take time to stabilize So this is not a “move everything to No-GIL today” moment. But it is a strong signal of where Python is heading. For a long time, the trade-off was clear: Python was easy to use, but not ideal for CPU-bound parallelism. That trade-off may not hold for much longer. Curious to hear how others are thinking about this. Are you planning to experiment with No-GIL Python, or waiting for the ecosystem to mature?
To view or add a comment, sign in
-
-
Python functions with fixed signatures break the moment you need to forward arguments across abstraction boundaries. *args and **kwargs solve that — and this python tutorial goes well past the syntax. — How CPython actually handles variadic calls at the C level (PyTupleObject, PyDictObject, and why there's a real allocation cost) — Why a defaulted parameter before *args is effectively unreachable via positional calling — and the idiomatic fix — The difference between *args isolating the mapping vs sharing mutable values inside it — ParamSpec (PEP 612) for preserving decorator signatures through the type system — TypedDict + Unpack (PEP 692, Python 3.12) for per-key precision on **kwargs — inspect.Parameter.kind for reading variadic signatures at runtime — the foundation of FastAPI and pytest's dispatch logic — Lambda variadic syntax, functools.wraps, kwargs.setdefault patterns, and common SyntaxErrors caught at parse time Includes interactive quizzes, spot-the-bug challenges, a design decision review, and a 15-question final exam with a downloadable certificate of completion. Full guide: https://lnkd.in/gHkdvCn5 #Python #PythonProgramming #SoftwareDevelopment
To view or add a comment, sign in
-
Day 32 of my python learning journey Today’s Python topic: Polymorphism🐍 Polymorphism = One name, many forms. Same function/method behaves differently based on object. Types I learned: 1. Duck Typing → If it walks like a duck and quacks like a duck, it’s a duck. Python cares about methods, not type. `def add(a, b): return a + b` works for int, str, list. 2. Method Overriding→ Child class changes parent class method. `class Dog(Animal): def sound(self): return "Bark"` 3. Method Overloading (sort of)→ Python doesn’t support true overloading, but we use default args or `*args` to handle it. 4. Operator Overloading → `+` works for numbers and strings. We can define `*add*` in our class too. Polymorphism makes code flexible and easy to extend. One interface, multiple behaviors. Special thanks to the CEO G.R NARENDRA REDDY Sir for constant guidance and motivation. #Python #OOP #Polymorphism
To view or add a comment, sign in
-
-
Build a RAG pipeline from scratch in Python without LangChain Learn to build a RAG pipeline in Python from scratch — chunk documents, embed with OpenAI, store in ChromaDB, and query with Claude. Read the full post 👇 https://lnkd.in/gBHKATvy #GenerativeAI #AI #WebDevelopment #PHP #Python #Developer #LLM
To view or add a comment, sign in
More from this author
Explore related topics
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development
It depends on use case. Mutable defaults is okay as long as either: 1. We are not making any changes to it: like the below example: def check_item_in_list(item, my_list=[]): return item in my_list #... Not adding, or removing, or modifying anything 2. We really want to make changes to that mutable real-time as and when the function is called, like the first example in this post If we are making changes to the mutable, but want to retain the default behaviour of the mutable (specified during function definition) when we are calling the function without specifying its value, which is the use case you are showing, then we should avoid using mutable defaults.