DEV Community

Ashutosh Sarangi
Ashutosh Sarangi

Posted on • Edited on

Python Basic __init__ , __pycache__ & PIP

Basic Python

1. Python Type Checking (Guide)

Python is dynamically typed, but you can use type hints for better readability, tooling, and static analysis.

✅ Type Hinting Example

def greet(name: str, age: int) -> str: return f"Hello {name}, you are {age} years old." 
Enter fullscreen mode Exit fullscreen mode

✅ Type Hinting for Complex Structures

Python uses the typing module to define complex types.

🔹 Imports you'll need:

from typing import Dict, List, Tuple, Any 
Enter fullscreen mode Exit fullscreen mode

🔸 Example 1: Function that returns a list of dictionaries

from typing import Dict, List def transform_data(data: Dict[str, int]) -> List[Dict[str, str]]: """ Converts a dict of {key: int} to a list of dicts with stringified values. Example: {"a": 1, "b": 2} → [{"key": "a", "value": "1"}, {"key": "b", "value": "2"}] """ return [{"key": k, "value": str(v)} for k, v in data.items()] 
Enter fullscreen mode Exit fullscreen mode

✅ Type Breakdown

  • Dict[str, int]: Input is a dictionary with string keys and integer values.
  • List[Dict[str, str]]: Output is a list of dictionaries with string keys and string values.

🔸 Example 2: Function that returns a list of tuples

from typing import Dict, List, Tuple def dict_to_tuples(data: Dict[str, int]) -> List[Tuple[str, int]]: """ Converts a dict to a list of key-value tuples. Example: {"a": 1, "b": 2} → [("a", 1), ("b", 2)] """ return list(data.items()) 
Enter fullscreen mode Exit fullscreen mode

✅ Type Breakdown

  • List[Tuple[str, int]]: Output is a list of tuples, each containing a string and an integer.

🔸 Example 3: Mixed or Unknown Types

If your dictionary or list contains mixed types, use Any:

from typing import Dict, List, Any def process(data: Dict[str, Any]) -> List[Dict[str, Any]]: return [{"key": k, "value": v} for k, v in data.items()] 
Enter fullscreen mode Exit fullscreen mode

🔹 Bonus: Using TypedDict for Structured Dicts

If your dicts have a fixed structure, you can define a TypedDict:

from typing import TypedDict, List class User(TypedDict): name: str age: int def get_users() -> List[User]: return [{"name": "Ashutosh", "age": 30}, {"name": "Assaf", "age": 40}] 
Enter fullscreen mode Exit fullscreen mode

Using TypedDict in Python provides several advantages, especially when you're working with dictionaries that have a fixed structure — like JSON-like data or configuration objects. Let's explore this in detail.


✅ What is TypedDict?

TypedDict is a feature from the typing module that lets you define the expected structure of a dictionary — including the types of its keys and values.

🔹 Example:

from typing import TypedDict class User(TypedDict): name: str age: int is_active: bool def get_user() -> User: return {"name": "Ashutosh", "age": 30, "is_active": True} 
Enter fullscreen mode Exit fullscreen mode

✅ Advantages of Using TypedDict

1. Type Safety

You get static type checking with tools like mypy, pyright, or IDEs (VS Code, PyCharm).

user: User = {"name": "Ashutosh", "age": "thirty", "is_active": True} # ❌ Type error 
Enter fullscreen mode Exit fullscreen mode

2. Better IDE Support

  • Autocompletion for keys
  • Inline type hints
  • Error highlighting

3. Self-Documenting Code

It’s clear what structure the dictionary should have — no need to guess or read through comments.

def create_user(user: User) -> None: ... 
Enter fullscreen mode Exit fullscreen mode

4. Improved Refactoring

If you change the structure of User, type checkers will help you find all affected code.

5. Cleaner JSON Handling

When working with APIs, you often parse JSON into dictionaries. TypedDict helps define the expected shape.

import json def parse_user(json_str: str) -> User: return json.loads(json_str) 
Enter fullscreen mode Exit fullscreen mode

🔸 Optional and Required Keys

You can define optional keys using total=False:

class PartialUser(TypedDict, total=False): name: str age: int 
Enter fullscreen mode Exit fullscreen mode

🔸 Comparison: TypedDict vs Raw Dict[str, Any]

Feature Dict[str, Any] TypedDict
Type safety ❌ No ✅ Yes
IDE support ❌ Limited ✅ Autocompletion, hints
Documentation ❌ Implicit ✅ Explicit structure
Error detection ❌ Runtime only ✅ Static analysis

✅ When Should You Use TypedDict?

  • When working with structured data (e.g., JSON from APIs)
  • When you want type-safe dictionaries
  • When building data models without needing full classes
  • When you want to avoid overengineering with dataclasses or pydantic

Absolutely! Let's dive into how to use TypedDict with required and optional keys in Python, with clear examples and explanations.


✅ What is TypedDict?

TypedDict allows you to define the structure of a dictionary with specific key names and value types. It’s part of the typing module and is especially useful when working with structured data like JSON.


🔹 Required vs Optional Keys

By default, all keys in a TypedDict are required. You can make keys optional by using total=False or by using NotRequired (Python 3.11+).


✅ Example 1: Required Keys Only

from typing import TypedDict class User(TypedDict): name: str age: int def get_user() -> User: return {"name": "Ashutosh", "age": 30} # ✅ All keys are required 
Enter fullscreen mode Exit fullscreen mode

If you omit a key:

return {"name": "Ashutosh"} # ❌ mypy will complain: 'age' is missing 
Enter fullscreen mode Exit fullscreen mode

✅ Example 2: Optional Keys with total=False

from typing import TypedDict class PartialUser(TypedDict, total=False): name: str age: int email: str def get_partial_user() -> PartialUser: return {"name": "Ashutosh"} # ✅ Only 'name' is provided 
Enter fullscreen mode Exit fullscreen mode

Here, all keys are optional — you can include any, all, or none.


✅ Example 3: Mixed Required and Optional (Python 3.11+)

from typing import TypedDict, NotRequired class UserProfile(TypedDict): username: str age: int email: NotRequired[str] phone: NotRequired[str] def get_profile() -> UserProfile: return { "username": "ashu_dev", "age": 30, "email": "ashu@example.com" } # ✅ 'phone' is optional 
Enter fullscreen mode Exit fullscreen mode

This is the most flexible and readable way to define mixed key requirements.


🔸 Summary

Method Python Version Behavior
TypedDict 3.8+ All keys required
TypedDict, total=False 3.8+ All keys optional
NotRequired 3.11+ Selectively optional keys

2. Duck Typing in Python

Duck Typing is a concept where the type of an object is determined by its behavior (methods/attributes), not its actual class.

“If it walks like a duck and quacks like a duck, it’s a duck.”

✅ Example

class Duck: def quack(self): print("Quack!") class Person: def quack(self): print("I'm pretending to be a duck!") def make_it_quack(thing): thing.quack() make_it_quack(Duck()) # Quack! make_it_quack(Person()) # I'm pretending to be a duck! 
Enter fullscreen mode Exit fullscreen mode

🔸 Benefits

  • Flexibility
  • Decoupled code
  • Easier testing and mocking

>>> numbers = [1, 2, 3] >>> person = ("Jane", 25, "Python Dev") >>> letters = "abc" >>> ordinals = {"one": "first", "two": "second", "three": "third"} >>> even_digits = {2, 4, 6, 8} >>> collections = [numbers, person, letters, ordinals, even_digits] >>> for collection in collections: ... for value in collection: ... print(value) ... 1 2 3 Jane 25 Python Dev a b c one two three 8 2 4 6 
Enter fullscreen mode Exit fullscreen mode

✅ General Operations on Built-in Collections

Operation Lists Tuples Strings Ranges Dictionaries Sets
Iteration
Indexing
Slicing
Concatenating
Finding length
Reversing
Sorting ✅* ✅*

* Sorting tuples and strings returns a new sorted list, not a sorted tuple/string.


🔹 Detailed Examples

✅ Iteration

for x in [1, 2, 3]: print(x) for x in (1, 2, 3): print(x) for x in "abc": print(x) for x in range(3): print(x) for k in {"a": 1, "b": 2}: print(k) for x in {1, 2, 3}: print(x) 
Enter fullscreen mode Exit fullscreen mode

✅ Indexing

print([1, 2, 3][0]) # 1 print((1, 2, 3)[1]) # 2 print("hello"[2]) # 'l' print(range(5)[3]) # 3 # Dictionaries and sets do not support indexing 
Enter fullscreen mode Exit fullscreen mode

✅ Slicing

print([1, 2, 3][1:]) # [2, 3] print((1, 2, 3)[1:]) # (2, 3) print("hello"[1:4]) # 'ell' print(range(10)[2:5]) # range(2, 5) 
Enter fullscreen mode Exit fullscreen mode

✅ Concatenating

print([1, 2] + [3, 4]) # [1, 2, 3, 4] print((1, 2) + (3, 4)) # (1, 2, 3, 4) print("ab" + "cd") # 'abcd' # Sets use union, not + 
Enter fullscreen mode Exit fullscreen mode

✅ Finding Length

print(len([1, 2, 3])) print(len((1, 2))) print(len("hello")) print(len(range(10))) print(len({"a": 1, "b": 2})) print(len({1, 2, 3})) 
Enter fullscreen mode Exit fullscreen mode

✅ Reversing

print(list(reversed([1, 2, 3]))) print(tuple(reversed((1, 2, 3)))) print("".join(reversed("abc"))) print(list(reversed(range(5)))) # dict and set are unordered → not reversible directly 
Enter fullscreen mode Exit fullscreen mode

✅ Sorting

print(sorted([3, 1, 2])) # [1, 2, 3] print(sorted((3, 1, 2))) # [1, 2, 3] print(sorted("cba")) # ['a', 'b', 'c'] print(sorted({3, 1, 2})) # [1, 2, 3] # dicts can be sorted by keys or values manually 
Enter fullscreen mode Exit fullscreen mode

🔸 Notes

  • Dictionaries are unordered mappings — you can iterate over keys, values, or items, but not index or slice.
  • Sets are unordered collections — no indexing or slicing, but support union, intersection, etc.
  • Tuples and strings are immutable — operations like sorting or reversing return new objects.

3. Sets in Python

Sets are unordered collections of unique elements.

✅ Basic Usage

a = {1, 2, 3} b = {3, 4, 5} # Union print(a | b) # {1, 2, 3, 4, 5}  # Intersection print(a & b) # {3}  # Difference print(a - b) # {1, 2}  # Symmetric Difference print(a ^ b) # {1, 2, 4, 5} 
Enter fullscreen mode Exit fullscreen mode

🔸 Set Comparison

a == b # Checks if sets are equal a.issubset(b) a.issuperset(b) 
Enter fullscreen mode Exit fullscreen mode

4. Other Data Types

✅ List

fruits = ["apple", "banana", "cherry"] fruits.append("orange") 
Enter fullscreen mode Exit fullscreen mode

✅ Dictionary

person = {"name": "Ashutosh", "age": 30} print(person["name"]) 
Enter fullscreen mode Exit fullscreen mode

✅ Tuple

point = (10, 20) 
Enter fullscreen mode Exit fullscreen mode

✅ String

text = "Hello, World!" 
Enter fullscreen mode Exit fullscreen mode

5. Why Use Dictionary When We Have JSON?

🔹 JSON is a data format (text-based).

🔹 Dictionary is a Python data structure.

You use dictionaries to work with data in Python, and convert them to/from JSON when communicating externally (e.g., APIs, files).

✅ Example

import json data = {"name": "Ashutosh", "age": 30} json_str = json.dumps(data) # Convert dict to JSON string parsed = json.loads(json_str) # Convert JSON string back to dict 
Enter fullscreen mode Exit fullscreen mode

6. sorted() vs .sort()

sorted()

  • Returns a new sorted list
  • Works on any iterable
  • Doesn’t modify the original
nums = [3, 1, 2] new_nums = sorted(nums) 
Enter fullscreen mode Exit fullscreen mode

.sort()

  • Sorts the list in-place
  • Only works on lists
  • Returns None
nums = [3, 1, 2] nums.sort() 
Enter fullscreen mode Exit fullscreen mode

🔸 Why Both?

  • sorted() is functional and flexible.
  • .sort() is efficient for large lists when mutation is acceptable.

✅ Summary

Concept Key Takeaway
Type Checking Improves safety and tooling
Duck Typing Behavior > Type
Sets Unique, unordered, fast ops
Lists, Dicts, Tuples Core data structures
Dict vs JSON Dict = Python, JSON = format
sorted() vs .sort() New list vs in-place sort

Why we need init?

1. Purpose of init.py

  • init.py file in a directory tells Python that the directory should be treated as a package.
  • This allows you to import modules from that directory using package syntax, e.g.:
  • Without init.py, Python (pre-3.3) would not recognize the folder as a package, and imports might fail.
  • The file can be empty, or it can contain initialization code for the package.

Starting with Python 3.3 and above (including Python 3.11), you can technically remove the init.py file from a package directory, and Python will still recognize it as a package due to "implicit namespace packages."

However, you should keep init.py:

  • When you add an init.py file to a package directory, it does not create a global namespace. Instead, it defines a package namespace.

  • All modules and submodules inside that package share the package’s namespace (e.g., tools_package.audio.utils).

  • This keeps your package’s contents organized and separate from the global namespace, preventing naming conflicts.

Module vs Package

  • Module: A single Python file (e.g., utils.py). You import it like import utils or from utils import foo.

  • Package: A directory containing an init.py file and (usually) multiple modules (e.g., audio/ with init.py and utils.py).

2. What is pycache?

  • When you run or import Python code, Python compiles .py files to bytecode for faster execution.

  • The compiled bytecode files are stored in the pycache directory, with names like utils.cpython-311.pyc.

  • cpython-311 means the file was compiled by CPython version 3.11.

  • These .pyc files are used by Python to speed up future imports of the module.

3. PIP (pip installs packages) (package Manager for Python):-

Using pip in a Python Virtual Environment

$ python -m venv venv/ $ source venv/bin/activate (venv) $ pip3 --version pip 24.2 from .../python3.12/site-packages/pip (python 3.12) (venv) $ pip --version pip 24.2 from .../python3.12/site-packages/pip (python 3.12) 
Enter fullscreen mode Exit fullscreen mode
  • Here you initialize a virtual environment named venv by using Python’s built-in venv module.
  • After running the command above, Python creates a directory named venv/ in your current working directory.
  • Then, you activate the virtual environment with the source command. - The parentheses (()) surrounding your venv name indicate that you successfully activated the virtual environment.

  • Finally, you check the version of the pip3 and pip executables inside your activated virtual environment.

  • Both point to the same pip module, so once your virtual environment is activated, you can use either pip or pip3.

Installing Packages With pip

 install a package pip install package_name uninstall a package pip uninstall package_name list installed packages pip list install a specific version of a package pip install package_name==version_number upgrade a package pip install --upgrade package_name show package information pip show package_name search for packages pip search package_name 
Enter fullscreen mode Exit fullscreen mode

Using Requirements Files

 requirement.text package pip install -r requirements.txt make a requirements.txt file from the packages installed pip freeze > requirements.txt 
Enter fullscreen mode Exit fullscreen mode

certifi==x.y.z
charset-normalizer==x.y.z
idna==x.y.z
requests>=x.y.z, <3.0
urllib3==x.y.z

Changing the version specifier for the requests package ensures that any version greater than or equal to 3.0 doesn’t get installed.

very important

We can create 3 files

  • requirements_dev.txt (For Development)
  • requirements_prod.txt (For Production)
  • requirements_lock.txt (After Development complete --> We will freeze it)

Uninstalling Packages With pip

pip show <package Name> 
Enter fullscreen mode Exit fullscreen mode

Name: requests
Version: 2.32.3
Summary: Python HTTP for Humans.
Location: .../python3.12/site-packages
Requires: certifi, idna, charset-normalizer, urllib3
Required-by:

  • Notice the last two fields, Requires and Required-by. The show command tells you that requests requires certifi, idna, charset-normalizer, and urllib3. You probably want to uninstall those too. Notice that requests isn’t required by any other package.
  • So it’s safe to uninstall it.
pip uninstall certifi urllib3 -y 
Enter fullscreen mode Exit fullscreen mode

Here you uninstall urllib3. Using the -y switch, you suppress the confirmation dialog asking you if you want to uninstall this package.

In a single call, you can specify all the packages that you want to uninstall

Top comments (1)

Collapse
 
a-k-0047 profile image
ak0047

Thank you for sharing this article.
I now have a deeper understanding of Python.