If Python is a "memory managed" language, but who is managing it? Reference Counter! Reference counter is what decides exactly when an object lives and when it dies in python. As discussed in previous posts, every object in Python carries a hidden counter. This counter tracks exactly how many variables are currently pointing to it. How it works? 1. Assignments: When we do y = x, Python finds the object x is pointing to and increments its counter (+1). 2. Deletions: When we do del x, Python finds the object x is pointing to and decrements its counter (-1). 3. Scope Exit: When a function finishes, all variables inside that function disappear. Python automatically decrements the counter of the objects they pointed to (-1). The moment that counter hits 0, Python immediately deletes the object and frees the memory. While this system is fast, it isn't "thread-safe". If two threads try to update the counter at the exact same time, the tally can get corrupted. That is exactly the reason, Python has Global Interpreter Lock(GIL) in place. Will discuss about it in more detail in next post. I am trying to learn Python Internals in detail and will share my learnings. Do follow along and tell your experiences in comments. #Python #PythonInternals #SoftwareEngineering #BackendDevelopment
Onkar Lapate’s Post
More Relevant Posts
-
More fun with dark corners of Python (yeah, this language is so easy to learn). Consider the following function: >>> def f(x): ... if x == 42: ... return x ... else: ... yield from([x]) When you call it with an argument not equal to 42, this is a generator alright: >>> list(f(1)) [1] Here f yielding from list [x] for x equal to 1, so no big surprise in the answer. But: >>> list(f(42)) [] Where is my number? Why don't I get syntax error? (Try list(42).) The reason is as following: - "yield from" tells Python that "f" is a generator - Python documentation says that "return val" in a generator is equivalent to "raise StopIteration(val)". And indeed: >>> try: ... next(f(42)) ... except StopIteration as ex: ... print(ex.value) ... 42 Here is my 42. #python #gotcha
To view or add a comment, sign in
-
While working with Python, I noticed something curious. When you assign a value to a variable, then change it, the object’s memory address changes. That’s expected. But if you later assign the same value again,Python gives you the exact same address as before. At first glance, this feels like Python is somehow “remembering” the old location. But that’s not what’s happening. What’s really going on? In CPython (the most common Python implementation), there is a mechanism called interning / caching. CPython pre-allocates and reuses certain immutable objects, most notably: Small integers in the range -5 to 256 Some short strings and identifiers So when you write: a = 10 b = 10 Both a and b usually point to the same object in memory. That’s why id(a) == id(b) is often True. Now compare that with larger integers: a = 10000 b = 10000 Here, you’ll often get different memory addresses. These values are not guaranteed to be cached, so Python may allocate new objects. Why does Python do this? This design has very practical benefits: Saves memory by reusing common immutable objects Reduces object allocations Lowers pressure on the garbage collector Improves performance for frequently used values Since integers and strings are immutable, sharing them is completely safe. #python #coding #LearningJourney #DeveloperJourney #Insights
To view or add a comment, sign in
-
-
Some fun with Python iterators. Let's take some list >>> lst = [1, 2, 3, 4] and build an iterator out of it >>> lst_i = iter(lst) Now I have an iterator over lst, so it should produce elements 1, 2, 3, 4. And indeed, the first element is 1. >>> list(zip(lst_i, ['a'])) [(1, 'a')] But let's see what is left... >>> list(zip(lst_i, ['b', 'c', 'd'])) [(3, 'b'), (4, 'c')] Where did 2 go? Well, the explanation is as following. The first zip gets 1 from lst_i and 'a' from ['a']. Then it gets 2 from lst_i and nothing from ['a'], so 2 is **discarded**. What is left for the second zip is 3 and 4. #Python #gotcha
To view or add a comment, sign in
-
🐍 #python tips: (range(len(...))) If you’re looping over indexes just to access values, Python has a better, cleaner option: enumerate(). Why it’s better: ✔️ More readable ✔️ Fewer off-by-one bugs ✔️ Idiomatic Python ✔️ Small changes like this compound into more maintainable code What’s interesting is that modern code generators and AI assistants already prefer patterns like enumerate() because they encode intent, not just mechanics. The clearer your code, the better both humans and tools can reason about it. Clean code isn’t about clever tricks! It’s about making the next reader (or code generator) faster and safer. What do you think? #Python #ProgrammingTips #CleanCode #SoftwareEngineering #DeveloperExperience #CodeQuality
To view or add a comment, sign in
-
-
🚀 Python’s "Hidden Gem": The loop that has an ‘Else’? I’ve been diving deeper into Python lately, and I stumbled upon something that honestly made me do a double-take: The for-else block. In most languages, else belongs strictly with if. But in Python, you can attach an else directly to a for loop. 🤯 🔍 How does it work? It sounds counter-intuitive, but the logic is actually brilliant: The else block runs only if the loop finishes naturally. If the loop hits a break (because you found what you were looking for), the else is skipped entirely. 💡 The "Search" Use Case Before I knew this, I used "flag" variables to check if a search was successful: found = False ... if not found: print("Not found") With for-else, the code is cleaner and more "Pythonic": #Python #Coding #ProgrammingTips #LearningToCode #SoftwareDevelopment #PythonTips #DataAnalysis #DataScience
To view or add a comment, sign in
-
-
Why Python prefers 𝘵𝘳𝘺 / 𝘦𝘹𝘤𝘦𝘱𝘵 over 𝘪𝘧 𝘦𝘭𝘴𝘦 checks? TL;DR: In Python, exceptions are part of normal flow, not rare events! There are two ways to walk through a uncertain code block - 1. Look Before You Leap (LBYL) - - Check conditions before doing the action - The 𝘪𝘧 𝘦𝘭𝘴𝘦 statements. - But here, Python looks at the dictionary twice. Once to check if the key exists, and once to actually fetch it. 2. Easier to Ask Forgiveness than Permission (EAFP) - Assume things will work and wrap the action in a try block. - If the key exists (which is usually the case), execution stays on the fast path. EAFP is the "Pythonic" approach. It is the way Python is built internally too. Python uses exceptions internally for everything. When using a for loop, Python doesn't check the length of the list; it just keeps asking for items until the list raises a StopIteration exception. Takeaway - -> Using try excepts will not add to any extra processing time, if not reduce it in most of the practical cases. -> Use LBYL if the failure is expected to happen often. -> Use EAFP if the failure is unexpected and rare. I’m deep-diving into Python internals and performance. Do follow along and tell your experiences in comments. #Python #PythonInternals #SoftwareEngineering #BackendDevelopment
To view or add a comment, sign in
-
-
#Learning hashtag #Python through Chunks. Lets start journey together (Beginner to Master). Lets code together !! #ABCC - Any Body Can CODE Chunk 2: How Python Actually Runs Code (Interpreter Explained Simply) NOTE: Python is an interpreted language, meaning it runs your code line-by-line. Python sits in the middle and converts readable code into machine-executable steps. 🧩 Python Interpreter in Real Life Terms Think of Python as: 💬 A translator who reads your instructions one line at a time 🎧 Tells the computer what to do 🛠️ Stops if something is unclear and shows you an error message Code: x = 5 print(x * 2) The interpreter does this: 1️⃣ Reads x = 5 → remembers it 2️⃣ Reads print(x * 2) → calculates → prints: Output 10 💡 Key takeaways from this chunk Python runs line-by-line (interpreted). It stops immediately if something doesn’t make sense. It shows error messages to help you fix problems.
To view or add a comment, sign in
-
A Python f-string (formatted string literal) is a way to embed expressions directly inside string constants, introduced in Python 3.6. It makes it easy to insert variable values into strings without needing concatenation or the .format() method. Syntax: name = "Sam" age = 30 print(f"My name is {name} and I am {age} years old.") Output: My name is Sam and I am 30 years old. How it works: The f before the opening quote tells Python to interpret the string as an f-string. Expressions inside {} are evaluated and replaced with their values. Benefits: Clean and readable More concise than using + or .format() You can use any valid Python expression inside the {} (e.g. {age + 5}, {name.upper()}) #Python #f-strings
To view or add a comment, sign in
-
-
If this image made you pause for a second — good. 👀 Same code. Same value. But Python says True here and False there. This is not: ❌ a bug ❌ randomness ❌ Python being inconsistent This is Python memory management at work. Behind the scenes, Python is deciding: Should I reuse memory? Is this object safe to share? Is this value common enough to cache? Can reference counting clean this up? Or should the Garbage Collector step in? Most developers learn Python syntax. Very few learn how Python thinks about memory. That gap is where: interview traps happen `is` vs `==` confusion starts performance bugs hide I explained this clearly, step-by-step (with diagrams) in my Medium article 👇 👉 Python Memory Management Explained (Interning, GC, Reference Counting) https://lnkd.in/grVdVSns Once you read it, this image will make complete sense — and Python will stop feeling “magical”. #Python #PythonInternals #MemoryManagement #BackendDeveloper #SoftwareEngineering #LearnPython
To view or add a comment, sign in
-
-
How does len() function knows how to handle a List, a String, and a Dictionary all the same way in Python? TL;DR: Python Protocols A Protocol is just the set of rules (special methods) an object follows. "Duck Typing" Contract In Python does not care about what the object is, it cares only about what it does. These are represented as dunders (__method__) in Python. 3 Protocols we use everyday in Python: -> Sized (__len__): Tells Python that object has a size. (Powers len()) -> Container (__contains__): Tells Python how to check if something is "inside" the object. (Powers the in keyword) -> Iterable (__iter__): Tells Python that object can be looped over. (Powers for x in obj) Why is this useful? As a developer, we want our code to be intuitive. By following these protocols, we make our custom objects compatible with all of Python’s built-in tools. Protocols are the API of the Python language itself. Using them make custom objects start feeling like native Python parts. I’m deep-diving into the Python protocols this week and will share my learnings. Do follow along and tell your experiences in comments. #Python #PythonInternals #SoftwareEngineering #BackendDevelopment
To view or add a comment, sign in
-
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