{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Variables are just memory references\n",
    "\n",
    "In Python, variables are not containers holding data directly but act as references to memory locations where the actual data is stored. This means that:\n",
    "\n",
    "- Variables point to objects in memory.\n",
    "- The same variable can point to different objects over time due to Python's dynamic nature.\n",
    "- When you assign one variable to another, you are copying the reference, not the actual object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "name = \"John\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### What happens internally?\n",
    "\n",
    "1. **Object Creation**: Python creates an object \"John\" if it does not already exist in memory. For small strings python uses string interning to reuse same object.\n",
    "2. **Variable Binding**: The variable a is created and points to the memory address of the string \"b\".\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3. **Reference Count**: The string object's reference count increases because a now refers to it.\n",
    "```{note}\n",
    " <i>getrefcount creates an extra reference count </i>\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sys\n",
    "sys.getrefcount(id(name))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "4. **Symbol Table Update**: The variable a is added to the current scope's symbol table, linking it to the \"b\" object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "John\n"
     ]
    }
   ],
   "source": [
    "print(globals()['name'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br>\n",
    "\n",
    "---\n",
    "\n",
    "<br>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Python is a Dynamically Typed Language  \n",
    "\n",
    "In Python, variables do not have fixed types. The type of the object a variable points to is determined at runtime, allowing flexibility in assigning different types of objects to the same variable.\n",
    "\n",
    "#### Key Characteristics:\n",
    "- **No Type Declaration**: You don’t need to specify the type of a variable when declaring it.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 10       # Integer\n",
    "a = \"Hello\"  # Now a string"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **Runtime Type Checking**: The type of an object is checked when operations are performed, not at compile time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "unsupported operand type(s) for +: 'int' and 'str'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[42], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m a \u001b[38;5;241m=\u001b[39m \u001b[38;5;241;43m5\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m5\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m  \u001b[38;5;66;03m# Raises a TypeError\u001b[39;00m\n",
      "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'"
     ]
    }
   ],
   "source": [
    "a = 5 + \"5\"  # Raises a TypeError"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **Dynamic Reassignment**: Variables can change their type by simply assigning a new value.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
