# Building Control_Structure in Python - With `switch` and `set` Concept

**Objective**: This script processes a list of user actions (e.g., login, logout, error) using **structural pattern matching** (`match` statement) and sets to track unique users.

It demonstrates:

* control structures,
    
* sets,
    
* functions,
    
* exception handling, and
    
* type hints.
    

---

## New concept

### Structural Pattern Matching (match):

* **What**: Python 3.12’s `match` statement for pattern-based control flow (e.g., matching dictionary structures).
    
* **Why**: Simplifies complex conditionals, making code more readable than nested `if` statements.
    
* **Where**: Handling structured data (e.g., JSON-like actions in apps or logs in DevOps).
    
* **New**: Introduced in Python 3.10, enhanced in 3.12; uses `match`/`case` with patterns like `{'type': 'login', 'user': str(user)}`.
    
* **Exceptions**: Missing keys or wrong types cause errors (handled with `try-except`).
    

---

### Sets:

* **What**: Unordered collections of unique items (e.g., `set[str]` for unique user names).
    
* **Why**: Efficient for tracking unique elements and membership testing.
    
* **Where**: Deduplicating data (e.g., users in logs) or set operations (union, intersection).
    
* **New**: Created with `set()` or `{}`, using `.add()` to insert items.
    
* **Exceptions**: Only hashable types (e.g., strings, not lists) can be added.
    
* **More info**: On Terminal &gt; `pydoc3.10 set`
    

---

### Any Type:

* **What**: Type hint `Any` from `typing` module for flexible dictionary values.
    
* **Why**: Allows type hints for dynamic data like dictionaries with mixed value types.
    
* **Where**: Common when processing JSON-like data or flexible inputs.
    
* **New**: Used in `dict[str, Any]` for action dictionaries.
    
* **Exceptions**: Overuse of `Any` reduces type safety; used sparingly here.
    
* **More info**: On Terminal &gt; `pydoc3.10 typing`
    

---

## Project summary

* Focuses on `match` statement and sets.
    
* Check for more info on them in Terminal
    
    ```python
    pydoc3.10 set
    pydoc3.10 dict
    pydoc3.10 typing
    ```
    

---

## Structure

```bash
core-python
├── basics
│   ├── control_structure
│   │   ├── README.md
│   │   └── main.py
└── tests
    └── test_control_structure.py
```

* `main.py`: Processes user actions using pattern matching (match) and tracks unique users with sets.
    
* `test_control_structure.py`: Pytest tests for `control_structure/main.py`, covering action processing and summarization.
    

---

## How I Built it

1. Build a pseudo flow with pen and paper.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753970202424/a8b26648-a98f-4aec-83c9-3555f224cb62.png align="center")
    
2. Start writing code:
    
    * `main()` - Main entry point of the program.
        
        ```python
        def main() -> None: # No return
        
            # Sample data
            actions: list[dict[str, Any]] = [
                    {"type": "login", "user": "Alice", "time": 1001},
                    {"type": "logout", "user": "Bob"},
                    {"type": "error", "code": 404},
                    {"type": "login", "user": "Alice", "time": 1002},
                    {"type": "invalid"},  # Invalid action
                    {"user": "Charlie"},  # Missing type
                    None,  # Invalid type
                ]
        
            # Provide data to each actions
            for action in actions:
                result = process_action(action)  # `switch` concept
                print(result)
        
            unique_users = get_unique_users(actions)  # `set` concept
            print(f"\nUnique Users: {unique_users}")
        
            summary = summarize_actions(actions)  # `dictionary` concept
            for action_type, count in summary.items():
                print(f"{action_type.capitalize()}: {count}")
        ```
        
        Just same as pseudo flow chart.
        
        ---
        
    * `process_actions()` - Return a message based on action type.
        
        * `match action:` - matching dictionary structures.
            
        * `case pattern:` - match pattern.
            
        * `case _:` - if above case doesn’t match then it raise `ValueError`.
            
        
        ```python
        def process_action(action: dict[str, Any]) -> str:
            try:
                match action:
                    case {"type": "login", "user": str(user), "time": int(time)}:
                        return f"User {user} logged in at timestamp {time}"
                    case {"type": "logout", "user": str(user)}:
                        return f"User {user} logged out"
                    case {"type": "error", "code": int(code)}:
                        return f"Error occurred with code {code}"
                    case {"type": "invalid"}:
                        raise ValueError(f"Invalid action format: {action}")
                    case _:
                        raise TypeError(f"Error processing action: {action}")
            except (KeyError, TypeError) as e:
                return f"{e}"
            except ValueError as e:
                return f"{e}"
        ```
        
        **Logic:** As to why `try-expect` used, is because to handle raise `ValueError` or `TypeError`. If try without `try-execpt` that the end of script with an error.
        
        ---
        
    * `unique_actions()` - Return a set of user names from action data.
        
        * `set()` - tracking unique elements ( no element be repeated ).
            
        * `users.add()` - use for add element in set.
            
        * `isinstance(value data_type)` - Ture if data type of value matches with data\_type. If not then it give `TypeError`.
            
        
        ```python
        def get_unique_users(actions: list[dict[str, Any]]) -> set[str]:
            users: set[str] = set()
            for action in actions:
                try:
                    if "user" in action and isinstance(action["user"], str):
                        users.add(action["user"])
                except TypeError:
                    continue
            return users
        ```
        
        **Logic** - In list there are dictionaries, as condition say `"user" in action` simply means key `user` present in action dictionary or not, and as for second condition `isinstance(action["user"], str)` check data type of `action["user”]` is string or not. Since this `get_unique_users()` return value in `set[str]`.
        
        ---
        
    * `summarize_actions()` - Counts occurrences of each action type.
        
        * `action.get(key)` - a way get value of a key. (eg. {“type”: “login”} type is key and login is value)
            
        
        ```python
        def summarize_actions(actions: list[dict[str, Any]]) -> dict[str, int]:
            summary: dict[str, int] = {"login": 0, "logout": 0, "error": 0, "invalid": 0}
            for action in actions:
                try:
                    match action.get("type"):
                        case "login":
                            summary["login"] += 1
                        case "logout":
                            summary["logout"] += 1
                        case "error":
                            summary["error"] += 1
                        case _:
                            summary["invalid"] += 1
                except (TypeError, AttributeError):
                    summary["invalid"] += 1
            return summary
        ```
        

---

## How to run

Change directory to `core-python`, so that test can also be performed.

```bash
# optional: in python-foundation dir
# source venv/bin/activate    # Windows: venv\Scripts\activate
cd core-python
```

Run [`main.py`](http://main.py).

```bash
python3 basics/control_structure/main.py
```

**Output**:

```bash
 Processing Actions:
 User Alice logged in at timestamp 1001
 User Bob logged out
 Error occurred with code 404
 User Alice logged in at timestamp 1002
 Invalid action format: {'type': 'invalid'}
 Error processing action: {'user': 'Charlie'}
 Error processing action: None

 Unique Users: {'Bob', 'Alice', 'Charlie'}

 Action Summary:
 Login: 2
 Logout: 1
 Error: 1
 Invalid: 3
```

Run `test_control_structure.py`:

```bash
PYTHONPATH=. pytest tests/test_control_structure.py -v
```

**Output**:

```bash
 ========================== test session starts ===========================
 platform linux -- Python 3.12.8, pytest-8.4.1, pluggy-1.6.0 -- /PATH/TO/PYTHON-FOUNDATION/.venv/bin/python3.12
 cachedir: .pytest_cache
 rootdir: /PATH/TO/PYTHON-FOUNDATION/core-python
 collected 6 items

 tests/test_control_structure.py::test_process_action PASSED        [ 16%]
 tests/test_control_structure.py::test_process_action_edge_cases PASSED [ 33%]
 tests/test_control_structure.py::test_get_unique_users PASSED      [ 50%]
 tests/test_control_structure.py::test_get_unique_users_edge_cases PASSED [ 66%]
 tests/test_control_structure.py::test_summarize_actions PASSED     [ 83%]
 tests/test_control_structure.py::test_summarize_actions_edge_cases PASSED [100%]

 =========================== 6 passed in 0.02s ============================
```

---

## Possible Issues

* **Invalid Actions**: Missing keys, wrong types, or `None` (handled with `try-except` and `case _`).
    
* **Empty Inputs**: Empty action lists (handled by returning empty sets or zero counts).
    
* **Match Limitations**: Simple patterns used; complex patterns may require deeper validation.
    

---

## Next

**Variables\_types** *(coming soon)* to explore dictionaries or tuples with type hints.

---

## Links

Github: Repo - Python Foundation/control\_structure

Click here for: [Project list](https://python-foundation.hashnode.dev/python-foundation-projects-learn-by-building#heading-project-list)

---

## 🤝 How to Contribute / Follow Along

* Clone the repo or copy scripts to try on your own machine.
    
* Share your output or improvements in the comments.
    
* DM me on GitHub or Hashnode for feedback!
    

---

## 📢 Let’s Connect

Follow me on Hashnode to get notified when I publish new Python projects 👇

➡️ @[Chetan Tekam](@Chetan3500)

---
