Skip to content

Latest commit

 

History

History
1709 lines (1387 loc) · 46.3 KB

File metadata and controls

1709 lines (1387 loc) · 46.3 KB

I'm sorry C++ …… I betrayed you.

<List>

  • Overview

    • A comparison of memory usage and execution speed for Python float, decimal.Decimal, NumPy float32, and NumPy float64.
    • The benchmark also measures the overhead of repeatedly converting between Python lists and NumPy arrays.
  • Components

    • floating.py: Creates the datasets, measures memory and execution time, and prints the comparison report.
    • run.py: A helper script that reads dependencies.yaml, installs configured packages, and runs the selected Python script.
    • dependencies.yaml: Registers numpy and pympler as dependencies for floating.py.
  • Measurements

    • Memory usage includes nested objects and container overhead measured with pympler.asizeof.asizeof.
    • Numeric operations multiply every value by 1.05. Python lists use list comprehensions, while NumPy arrays use vectorized multiplication.
    • The conversion benchmark compares direct NumPy operation, Python list operation, list-to-NumPy conversion, NumPy-to-list conversion, and a complete list/NumPy round trip.
    • Conversion costs are included in each timed statement, showing why repeated representation changes can remove the benefit of NumPy.
  • Execution Commands and Results

    $ python3 run.py floating.py
    --- Running 'floating.py' ---
    
    === [Benchmark Report] Data Size: 10,000 elements ===
    
    === [Numeric Type Benchmark] ===                             === [Python/NumPy Conversion Overhead] ===
    Data Type          | Memory (Bytes)  | Execution Time (s)    Operation                    | Execution Time (s)
    ----------------------------------------------------------   --------------------------------------------------
    Python float       |         325,176 |            0.32852    NumPy direct operation       |            0.00264
    Decimal            |       1,125,176 |            3.15240    Python list operation        |            0.28159
    NumPy float32      |          40,128 |            0.00204    List to NumPy each time      |            0.32939
    NumPy float64      |          80,128 |            0.00272    NumPy to list each time      |            0.16725
                                                                 List-NumPy round trip        |            0.58042

    Execution times vary by machine and system load. The important observation is that direct NumPy operations are fast, but repeatedly converting between lists and arrays can make the combined operation slower than staying with a Python list. A practical approach is to convert data once, perform multiple operations while it remains a NumPy array, and convert it back only when necessary.

  • Overview

    • A comparison between Python's two primary testing frameworks: unittest (standard library) and pytest (third-party).
    • unittest: Traditional, class-based approach similar to JUnit; requires setUp() and assertion methods like self.assertTrue().
    • pytest: Modern, function-based approach supporting fixtures; uses simple assert statements.
      • This practice includes parametrize decorator to test multiple scenarios with a single test function.
  • Components

    • tdd_practice.py: Core module containing StockBroker class and should_execute_buy() function for decision logic.
    • tdd_unittest.py: Test suite using unittest framework with MagicMock for mocking.
    • tdd_pytest.py: Test suite using pytest framework with fixtures and monkeypatch for mocking, including parametrized tests.
  • Execution Commands and Results

    unittest
    $ python3 ./tdd_unittest.py
    test_buy_decision_on_low_price (__main__.TestTradingSystem.test_buy_decision_on_low_price)
    Test that the system triggers a buy when the price is below the limit. ... ok
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK
    pytest
    $ pytest -v ./tdd_pytest.py
    ================================================= test session starts ==================================================
    platform linux -- Python 3.12.1, pytest-9.0.2, pluggy-1.6.0 -- /usr/local/python/3.12.1/bin/python3
    cachedir: .pytest_cache
    rootdir: /workspaces/MyPractice/Python
    plugins: anyio-4.11.0
    collected 5 items                                                                                                      
    
    tdd_pytest.py::test_should_buy_when_price_is_under_limit PASSED                                                  [ 20%]
    tdd_pytest.py::test_should_not_buy_when_price_is_over_limit PASSED                                               [ 40%]
    tdd_pytest.py::test_buy_decision_with_parametrize[150.0-160.0-True] PASSED                                       [ 60%]
    tdd_pytest.py::test_buy_decision_with_parametrize[200.0-160.0-False] PASSED                                      [ 80%]
    tdd_pytest.py::test_buy_decision_with_parametrize[160.0-160.0-True] PASSED                                       [100%]
    
    ================================================== 5 passed in 0.06s ===================================================
  • Overview

    • Python does not provide separate syntax for interfaces, but abstract classes can be used as a concept similar to interfaces in other languages.
    • Abstract classes used as interfaces are more about enforcing specific method declarations rather than promoting code reusability.
  • Code and Results

    Code : abc_as_interface.py
    from abc import ABC, abstractmethod
    class MischievousBoy(ABC):
        """Abstract base class defining the interface for mischievous boys."""
        @abstractmethod
        def play_prank(self):
            """Play a prank on someone."""
            # pass  # not necessary
    
        @abstractmethod
        def get_in_trouble(self):
            """Get into trouble for doing something naughty."""
            # pass  # not necessary
    
    class Timmy(MischievousBoy):
        """Concrete class representing Timmy, a mischievous boy."""
        def play_prank(self):
            """Timmy's specific implementation of playing a prank."""
            print("Timmy puts a whoopee cushion on the teacher's chair!")
    
        def get_in_trouble(self):
            """Timmy's specific way of getting into trouble."""
            print("Timmy gets detention for drawing on the walls.")
    
    class Johnny(MischievousBoy):
        """Concrete class representing Johnny, another mischievous boy."""
        def play_prank(self):
            """Johnny's specific implementation of playing a prank."""
            print("Johnny hides all the chalk in the classroom!")
    
        def get_in_trouble(self):
            """Johnny's specific way of getting into trouble."""
            print("Johnny has to clean the blackboard for a week.")
    # Create instances of the mischievous boys
    timmy = Timmy()
    johnny = Johnny()
    
    # Demonstrate Timmy and Johnny in action
    timmy.play_prank()
    timmy.get_in_trouble()
    
    johnny.play_prank()
    johnny.get_in_trouble()
    Results
    Timmy puts a whoopee cushion on the teacher's chair!
    Timmy gets detention for drawing on the walls.
    Johnny hides all the chalk in the classroom!
    Johnny has to clean the blackboard for a week.
  • Overview

    • Original @dataclass is fast but lacks validation features.
    • pydantic.BaseModel provides validation functionality.
    • pydantic.dataclasses allows the use of validation with the same syntax as @dataclass
      • Although it's presumed that the performance is not as good as the original @dataclass.
  • Case 1 : @dataclass without pydantic

    Code : pydantic_dataclass_1.py
    from dataclasses import dataclass
    from typing import List
    @dataclass
    class Superhero:
        name: str
        superpowers: List[str]
        weakness: str
        age: int
    # Create superheroes
    batman = Superhero("Batman", ["Rich", "Smart"], "No superpowers", 35)
    superman = Superhero("Superman", ["Flight", "Super strength"], "Kryptonite", 33)
    
    # Print superhero information
    print(f"{batman.name}'s superpowers: {', '.join(batman.superpowers)}")
    print(f"{superman.name}'s weakness: {superman.weakness}")
    # This case doesn't raise an error but is logically incorrect
    weird_hero = Superhero("Weird Guy", ["Sleeping"], "Wife", -5)
    print(f"Weird hero's age: {weird_hero.age}")  # Negative age is allowed
    Results
    Batman's superpowers: Rich, Smart
    Superman's weakness: Kryptonite
    Weird hero's age: -5
  • Case 2 : pydantic.BaseModel instead of @dataclass

    Code : pydantic_dataclass_2.py
    from typing import List
    from pydantic import BaseModel, Field
    class Superhero(BaseModel):
        name: str
        superpowers: List[str]
        weakness: str
        age: int = Field(..., gt=0, lt=1000)
    # Create superheroes
    batman = Superhero(name="Batman", superpowers=["Rich", "Smart"], weakness="No superpowers", age=35)
    superman = Superhero(name="Superman", superpowers=["Flight", "Super strength"], weakness="Kryptonite", age=33)
    
    # Print superhero information
    print(f"{batman.name}'s superpowers: {', '.join(batman.superpowers)}")
    print(f"{superman.name}'s weakness: {superman.weakness}")
    # Error case
    try:
        weird_hero = Superhero(name="Weird Guy", superpowers=["Sleeping"], weakness="Wife", age=-5)
        print(f"Weird hero's age: {weird_hero.age}")
    except ValueError as e:
        print(f"Error occurred: {e}")
    Results
    Batman's superpowers: Rich, Smart
    Superman's weakness: Kryptonite
    Error occurred: 1 validation error for Superhero
    age
      Input should be greater than 0 [type=greater_than, input_value=-5, input_type=int]
        For further information visit https://errors.pydantic.dev/2.10/v/greater_than
  • Case 3 : @dataclass from pydantic.dataclasses

    Code : pydantic_dataclass_3.py
    from typing import List
    from pydantic.dataclasses import dataclass
    from pydantic import Field
    @dataclass
    class Superhero:
        name: str
        superpowers: List[str]
        weakness: str
        age: int = Field(..., gt=0, lt=1000)
    # Create superheroes
    batman = Superhero("Batman", ["Rich", "Smart"], "No superpowers", 35)
    superman = Superhero("Superman", ["Flight", "Super strength"], "Kryptonite", 33)
    
    # Print superhero information
    print(f"{batman.name}'s superpowers: {', '.join(batman.superpowers)}")
    print(f"{superman.name}'s weakness: {superman.weakness}")
    # Error case
    try:
        weird_hero = Superhero("Weird Guy", ["Sleeping"], "Wife", -5)
        print(f"Weird hero's age: {weird_hero.age}")
    except ValueError as e:
        print(f"Error occurred: {e}")
    Results
    Batman's superpowers: Rich, Smart
    Superman's weakness: Kryptonite
    Error occurred: 1 validation error for Superhero
    3
      Input should be greater than 0 [type=greater_than, input_value=-5, input_type=int]
        For further information visit https://errors.pydantic.dev/2.10/v/greater_than
  • A comparison made between code using Pydantic and code without it

    • Pydantic is an excellent library that contributes to improved code productivity
    • It provides concise representation of data structures and reduces code needed for type conversion, data validation and error handling
    • Therefore, we should use Pydantic. Let's start using it immediately
    • Official Docs ☞ https://docs.pydantic.dev/
  • pydantic_with.py

    Code
    from pydantic import BaseModel
    class User(BaseModel):
        """
        Represents a user in the system.
        """
        id: int
        name: str
        is_active: bool
    # Sample user data with string values
    user_data = {
        'id': '123',        # Will be automatically converted to int
        'name': 'Alice',
        'is_active': 'true' # Will be automatically converted to bool
    }
    
    # Create a User instance from the dictionary
    # Pydantic will automatically validate and convert the data types
    user = User(**user_data)
    
    # Print the user object as a JSON string
    print(user.model_dump_json())
    Results
    {"id":123,"name":"Alice","is_active":true}
  • pydantic_without.py

    Code
    import json
    class UserManual:
        """
        Represents a user in the system, demonstrating manual implementation
        of type validation and JSON serialization.
        """
    
        def __init__(self, user_id, name, is_active):
            """
            Initialize a UserManual instance.
    
            Raises:
                ValueError: If any of the input types are incorrect.
            """
            if not isinstance(user_id, int):
                raise ValueError("id must be an int")
            if not isinstance(name, str):
                raise ValueError("name must be a str")
            if not isinstance(is_active, bool):
                raise ValueError("is_active must be a bool")
    
            self.user_id = user_id
            self.name = name
            self.is_active = is_active
    
        def to_json(self):
            """
            Convert the UserManual instance to a JSON string.
            """
            return json.dumps({
                'id': self.user_id,
                'name': self.name,
                'is_active': self.is_active
            })
    # Sample user data with string values
    user_data_manual = {
        'id': '123',        # Requires explicit conversion to int
        'name': 'Alice',
        'is_active': 'true' # Requires explicit conversion to bool
    }
    
    # Manually convert data types and create UserManual instance
    user_manual = UserManual(
        int(user_data_manual['id']),
        user_data_manual['name'],
        user_data_manual['is_active'].lower() == 'true'
    )
    
    # Serialize to JSON and print
    print(user_manual.to_json())
    Results
    {"id": 123, "name": "Alice", "is_active": true}
  • Review of how to reuse synchronous code within an asynchronous context
    • Using asyncio.loop.run_in_executor()
  • Comparison between code using aiohttp for full asynchronous execution and the re-used synchronous code
    • Results show no significant difference. In cases where a synchronous function is already written and internal computation is less significant compared to network latency, reusing the synchronous function as-is, rather than rewriting it asynchronously, seems to be a more reasonable choice.

    • asyncio_1_handling_sync_funtion.py

      Import modules
      import asyncio
      import time
      import requests
      def fetch_sync()
      def fetch_sync(url):
          """
          Sends a synchronous HTTP GET request to the provided URL and measures the time taken for the request.
      
          Args:
              url (str): The URL to send the request to.
      
          Returns:
              float: The time taken for the HTTP request in seconds.
          """
          start_time = time.time()                # Record the start time
          _ = requests.get(url, timeout=100)       # The results are not needed
          elapsed_time = time.time() - start_time # Calculate elapsed time
          return elapsed_time
      async def fetch_async()
      async def fetch_async(loop, url):
          """
          Asynchronously executes a synchronous HTTP request function using `run_in_executor`.
      
          Args:
              loop (asyncio.AbstractEventLoop): The event loop to run the task in.
              url (str): The URL to send the request to.
      
          Returns:
              float: The time taken for the HTTP request in seconds.
          """
          return await loop.run_in_executor(None, fetch_sync, url)
      async def main
      async def main(base_url, delay_time, n):
          """
          The main asynchronous function that constructs the URLs and sends multiple requests concurrently,
          measuring and printing the time taken for each request and the total time for all requests.
      
          Args:
              base_url (str): The base URL for the HTTP requests.
              delay_time (int): The delay time to append to the base URL (used in URL path).
              n (int): The number of requests to send.
      
          Returns:
              None
          """
          loop = asyncio.get_event_loop()
      
          url = f"{base_url}/{delay_time}"
      
          tasks = [fetch_async(loop, url) for _ in range(n)]
      
          start_time = time.time()
      
          results = await asyncio.gather(*tasks)
      
          print(f"Tasks completed in {time.time() - start_time:.2f} seconds")
      
          for i, elapsed_time in enumerate(results, 1):
              print(f"Response {i} took {elapsed_time:.2f} seconds")
      Run
      if __name__ == "__main__":
          BASE_URL = "https://httpbin.org/delay"
          DELAY_TIME = 3
          N = 10
      
          asyncio.run(main(BASE_URL, DELAY_TIME, N))
    • asyncio_2_entire_async.py

      Import modules
      import asyncio
      import time
      import aiohttp
      async def fetch()
      async def fetch(url):
          """
          Asynchronously performs an HTTP GET request to the provided URL and measures the time taken for the request.
      
          Args:
              url (str): The URL to send the request to.
      
          Returns:
              float: The time taken for the HTTP request in seconds.
          """
          start_time = time.time()  # Record the start time
          async with aiohttp.ClientSession() as session:
              async with session.get(url) as response:
                  await response.text()  # Read the response to ensure completion
          elapsed_time = time.time() - start_time  # Calculate elapsed time
          return elapsed_time
      async def main()
      async def main(base_url, delay_time, n):
          """
          The main asynchronous function that constructs the URLs and sends multiple requests concurrently,
          measuring and printing the time taken for each request and the total time for all requests.
      
          Args:
              base_url (str): The base URL for the HTTP requests.
              delay_time (int): The delay time to append to the base URL (used in URL path).
              n (int): The number of requests to send.
      
          Returns:
              None
          """
          url = f"{base_url}/{delay_time}"
      
          # Create `n` asynchronous tasks, each sending a request to the same URL.
          tasks = [fetch(url) for _ in range(n)]
      
          start_time = time.time()
      
          results = await asyncio.gather(*tasks)
      
          print(f"Tasks completed in {time.time() - start_time:.2f} seconds")
      
          for i, elapsed_time in enumerate(results, 1):
              print(f"Response {i} took {elapsed_time:.2f} seconds")
      Run
      if __name__ == "__main__":
          BASE_URL = "https://httpbin.org/delay"
          DELAY_TIME = 3
          N = 10
      
          asyncio.run(main(BASE_URL, DELAY_TIME, N))
    • Results

      asyncio_1_handling_sync_funtion
      Tasks completed in 5.70 seconds
      Response 1 took 3.62 seconds
      Response 2 took 5.70 seconds
      Response 3 took 4.57 seconds
      Response 4 took 4.02 seconds
      Response 5 took 3.82 seconds
      Response 6 took 4.11 seconds
      Response 7 took 4.83 seconds
      Response 8 took 3.84 seconds
      Response 9 took 3.98 seconds
      Response 10 took 5.30 seconds
      asyncio_2_entire_async
      Tasks completed in 5.65 seconds
      Response 1 took 5.50 seconds
      Response 2 took 3.39 seconds
      Response 3 took 3.73 seconds
      Response 4 took 3.31 seconds
      Response 5 took 3.64 seconds
      Response 6 took 5.16 seconds
      Response 7 took 5.64 seconds
      Response 8 took 4.11 seconds
      Response 9 took 3.72 seconds
      Response 10 took 3.44 seconds
  • A practice to extract 3-bit palette indices for Get Portraits from KAODATA.DAT (Trial 2) (2024.08.05)

  • Code and Results

    Code : Extract3BitPaletteIndices.py
    IS_TEST = True
    def extract_3_bit_palette_indices(data):
        """
        Extracts 3-bit palette indices from the given byte data.
    
        Args:
            data (list of int): The byte data to extract 3-bit palette indices from.
    
        Returns:
            list of int: The extracted 3-bit palette indices.
        """
        bit_list = []
        for index, byte in enumerate(data):
            for bit_position in range(8):
                bit = (byte >> (7 - bit_position)) & 1
                bit_list.append(bit)  # Extract individual bits
            if IS_TEST:
                print(f"data[{index}] : {byte:3d} {bin(byte):10s} {bit_list[-8:]}")
    
        # Extract 3-bit palette indices
        palette_indices = []
        for index in range(0, len(bit_list), 3):
            if index + 2 < len(bit_list):
                palette_index = (bit_list[index] << 2) | (bit_list[index + 1] << 1) | bit_list[index + 2]
                if IS_TEST:
                    print(f"palette_index[{int(index/3)}] : {bit_list[index:index+3]} {bin(palette_index):5s} {palette_index}")
                palette_indices.append(palette_index)
        return palette_indices
    if __name__ == "__main__":
        # Test data
        test_data = [224, 84, 64]
    
        # Extract 3-bit palette indices
        extracted_palette_indices = extract_3_bit_palette_indices(test_data)
        print("Extracted 3-bit palette indices:", extracted_palette_indices)
    Results
    data[0] : 224 0b11100000 [1, 1, 1, 0, 0, 0, 0, 0]
    data[1] :  84 0b1010100  [0, 1, 0, 1, 0, 1, 0, 0]
    data[2] :  64 0b1000000  [0, 1, 0, 0, 0, 0, 0, 0]
    palette_index[0] : [1, 1, 1] 0b111 7
    palette_index[1] : [0, 0, 0] 0b0   0
    palette_index[2] : [0, 0, 0] 0b0   0
    palette_index[3] : [1, 0, 1] 0b101 5
    palette_index[4] : [0, 1, 0] 0b10  2
    palette_index[5] : [0, 0, 1] 0b1   1
    palette_index[6] : [0, 0, 0] 0b0   0
    palette_index[7] : [0, 0, 0] 0b0   0
    Extracted 3-bit palette indices: [7, 0, 0, 5, 2, 1, 0, 0]
  • Just for fun ☞ related meme

  • Code and Result

    Code : HelloWorldPrint.py
    import sys
    def hello_world(func_name):
        """
        Dynamically call the given function using its name.
        The name of the current executing function is passed as an argument.
    
        Caution:
            Using eval() can pose security risks!
    
        Args:
            func_name (str): Name of the function to be called
    
        Returns:
            None
        """
        current_func_name = sys._getframe().f_code.co_name
        func = eval(func_name)
        func(current_func_name)
    if __name__ == "__main__":
        hello_world("print")
    Result
    hello_world
  • I dreamed of making a new open source library to do it for a while, but f-string is too strong …… This devil has broken my dear dream!

  • Reference ☞ https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals

    sample = [
        ['이렇게', '하면'],
        ['줄이', '잘 맞을까'],
        ['모르겠네', '어디'],
        ['한 번', '볼까'],
    ]
    1. Normal Approach
    # 1. Normal Approach
    print("# 1. Normal Approach")
    for el in sample :
        print(el[0], el[1])
    # 1. Normal Approach
    이렇게 하면
    줄이 잘 맞을까
    모르겠네 어디
    한 번 볼까
    
    2. Use f-string
    # 2. Use f-string
    sample[3][0] = '두 번'
    print("\n# 2. Use f-string")
    for el in sample :
        print(f"{el[0]:<10}", f"{el[1]:<10}")                   # Korean letters drive it to insanity
    # 2. Use f-string
    이렇게        하면
    줄이         잘 맞을까
    모르겠네       어디
    두 번        볼까
    
    2.1 Use f-string : Handle Korean letters
    # 2.1 Use f-string : Handle Korean letters
    sample[3][0] = '세 번'
    print("\n# 2.1 Use f-string 2 : Handle Korean letters")
    for r in sample :
        length = [10, 10]
        for c in range(2) :
            for char in r[c] :
                if char >= '가' :
                    length[c] -= 1
        # print(length[0], length[1])                           # test : ok
        # print(f"{r[0]:<length[0]} {r[1]:<length[1]}")         # ValueError: Invalid format specifier; length[] → {length[]}
        print(f"{r[0]:<{length[0]}} {r[1]:<{length[1]}}")
    # 2.1 Use f-string 2 : Handle Korean letters
    이렇게     하면
    줄이       잘 맞을까
    모르겠네   어디
    세 번      볼까
    
    2.2 Use f-string : Change alignment direction
    sample[3][0] = '네 번'
    print("\n2.2 Use f-string : Change alignment direction")
    for r in sample :
        length = [10, 10]
        for c in range(2) :
            for char in r[c] :
                if char >= '가' :
                    length[c] -= 1
        print(f"{r[0]:>{length[0]}} {r[1]:>{length[1]}}")
    2.2 Use f-string : Change alignment direction
        이렇게       하면
          줄이  잘 맞을까
      모르겠네       어디
        네 번       볼까
    
    2.3 Use f-string : Code generalization & individual alignment control
    sample[3][0] = '다섯 번'
    print("\n2.3 Use f-string : Code generalization & individual alignment control")
    for r in sample :
        length = [10] * len(r)
        for c in range(len(r)) :
            for char in r[c] :
                if char >= '가' :
                    length[c] -= 1
            if c == 1 :
                print(f"{r[c]:>{length[c]}}", end = '')
            else :
                print(f"{r[c]:<{length[c]}}", end = '')
        print()
    2.3 Use f-string : Code generalization & individual alignment control
    이렇게          하면
    줄이       잘 맞을까
    모르겠네        어디
    다섯 번         볼까
    
  • A practice to parse arguments from command line to .py script file

  • Reference ☞ https://en.wikipedia.org/wiki/Command-line_argument_parsing

    Codes : ArguementParsing.py
    import sys
    def ArguementParsing() :
        if len(sys.argv) > 1 :                          # not > 0; sys.argv[0] is the script file name
            for arg in sys.argv :
                print(arg)
        else :
            print("No arguments has been received.")
    # test
    def test() :
        for arg in list(sys.argv) :
            print(arg)
    if __name__ == "__main__" :
        ArguementParsing()
        # test()                                        # 0(path) 1 2 3
    Codes : ArguementParsing.bat
    python ArguementParsing.py
    python ArguementParsing.py a b c
    Output
    > python ArguementParsing.py
    No arguments has been received.
    
    > python ArguementParsing.py a b c
    ArguementParsing.py
    a
    b
    c
    
  • A solution for the problem to align text vertically with both of English and Korean letters

    Codes : VerticalAlignment.py
    # Korean letter's length is also measured as 1
    abcd = "abcd"
    ssjj = "삼성전자"
    
    print(len(abcd))
    print(len(ssjj))
    4  
    4
    
    # How to count Korean letter's length as 2
    length = 0
    for char in ssjj :
        if char >= '가' :
            length += 2
    print(length)
    8
    
    # Vertical alignment
    list = ["abcd", "삼성전자"]
    
    # trial 1
    for i in list :
        print(i, '\t', 100)
    abcd     100
    삼성전자         100
    
    # trial 2
    for i in list :
        length = 10
        for char in i :
            if char >= '가' :
                length -= 2
            else :
                length -= 1
        i += length * ' '
        print(i, 100, sep = '')
    abcd      100
    삼성전자  100
    

    Thses are arranged vertically well in the console output. Please believe me ……

  • Originally started from a stupid question : Can a method call other method in the same class?

  • I've just realized it was really obvious (Why does the constructor exist?)

  • This code is a strange station, that two methods call each other with iterator

    Codes : Iterator.py
    turn = 0
    
    class Bros :
    
        def __init__(self) :
            global turn
            turn += 1
            print("<Conversation " + str(turn) + ">")
            self.conversation = iter(["Hey bro", "Wassup"])
            self.n = 0
    
        def bros1(self) :
            print(self.bros1.__name__ + " : " + next(self.conversation))
            if (self.n < 1) :
                self.n += 1
                self.bros2()
            else :
                print()
    
        def bros2(self) :
            print(self.bros2.__name__ + " : " + next(self.conversation))
            if (self.n < 1) :
                self.n += 1
                self.bros1()
            else :
                print()
    if __name__ == "__main__" :
    
        Bros1 = Bros()
        Bros1.bros1()
    
        Bros2 = Bros()
        Bros2.bros2()
    Output

    <Conversation 1>
    bros1 : Hey bro
    bros2 : Wassup

    <Conversation 2>
    bros2 : Hey bro
    bros1 : Wassup

  • A practice of using if and while

  • All the strings and numbers except 0 and False are regarded as True

    Codes : IfWhileTrue.py
    if True :
        print(True)
    
    if False :
        print(False)
    
    if 'abc' :
        print('abc')
    
    a = 1
    if a :
        print(a)
    
    b = 0
    if b :
        print(b)
    
    c = -1
    if c :
        print(c)

    True
    abc
    1
    -1

    while True :
        print(True)
        break
    
    while False :
        print(False)
        break
    
    while '123' :
        print('123')
        break

    True
    123

  • Seperating a string by plural delimiters

  • Using regular expression (re)

    txt = 'one two/three.four'
    
    # 1. string.split()
    print(txt.split())                  # default : ' '
    print(txt.split('/'))
    # print(txt.split(' ').split('/'))    # Error
    
    # 2. Regular Expression
    import re
    print(re.split("[ /.]", txt))       # Enter delimiters directly
    print(re.split("\W", txt))          # \W = a-zA-Z0-9

    ['one', 'two/three.four']
    ['one two', 'three.four']
    ['one', 'two', 'three', 'four']
    ['one', 'two', 'three', 'four']

  • A practice of importing and running module in Python

  • Using __name__ and __main__

    ModuleSample.py

    if __name__ == '__main__' :
        print("Don't call me yet.")
    
    def call() :
        print("Call me now.")

    Don't call me yet.

    ModuleRun.py

    import ModuleSample
    
    ModuleSample.call()

    Call me now.

  • A practice of python module turtle

  • Very easy!

    Turtle Practice

    Codes : Turtle.py
    import turtle
    import time
    
    turtle.setup(width = 300, height = 300)
    turtle.title("My turtle practice")
    
    turtle.hideturtle()         # hide turtle : make the moving speed faster
    
    
    turtle.home()               # set the position (0, 0)
    turtle.position()
    
    turtle.penup()              # penup() = pu() = up() : move without drawing
    turtle.setpos(0, 125)
    
    turtle.pendown()            # pendown() = pd() = down() : move with drawing
    turtle.right(180)
    turtle.circle(125)          # 1st circle
    
    turtle.penup()
    turtle.setpos(0, 100)
    
    turtle.pendown()
    time.sleep(0.3)
    turtle.circle(100)          # 2nd circle
    
    turtle.delay(20)
    
    time.sleep(0.5)
    turtle.circle(100, steps=3) # 1st triangle
    
    turtle.penup()
    turtle.setpos(0, -100)
    turtle.right(180)
    
    turtle.pendown()
    turtle.circle(100, steps=3) # 2nd triangle
    
    turtle.penup()
    turtle.setpos(0, 100)
    turtle.right(180)
    
    turtle.delay(30)
    
    turtle.pendown()
    turtle.circle(100, steps=6) # hexagon
    
    
    turtle.mainloop()           # avoid the screen closing
  • To find how map() runs

    • I guessed the result of running map() would be something to contain hidden elements.
    • But actually it is a generator type object, so has not futural list data before I request by list().
  • References

    Codes : Map.py
    def details(txt) :
        print("elements :", txt)
        print("type :", type(txt))
        try :
            print("elements' type :", type(txt[0]), "\n")
        except :
            print("elements' type : an error occurs.\n")
    
    txt = "1 2 3 4 5"
    details(txt)
    
    txtsplit = txt.split()
    details(txtsplit)
    
    txtmap = map(int, txt.split())
    details(txtmap) # an error occurs
    
    txtlist = list(txtmap)
    details(txtlist)
    Results
    elements : 1 2 3 4 5
    type : <class 'str'>
    elements' type : <class 'str'>
    
    elements : ['1', '2', '3', '4', '5']
    type : <class 'list'>
    elements' type : <class 'str'>
    
    elements : <map object at 0x7fefcdfe8dc0>
    type : <class 'map'>
    elements' type : an error occurs.
    
    elements : [1, 2, 3, 4, 5]
    type : <class 'list'>
    elements' type : <class 'int'>
  • Read a csv file into a dictionary

  • Import csv

  • Seems that dictionary type is not so suitable to generate random paragraphs

    WordMix.py

    0. Check If Words.csv Exists
    import os
    path = "C:\\Users\\……\\Python\\Words.csv"
    # \\ : escape character of \
    os.path.isfile(path)

    True

    1. Read Words.csv simply
    import csv
    with open(path,'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
    
        for c in reader:
            for k, v in c.items():
                print(v, end= ' ')
            print("\n")

    멍청하게 떡볶이 먹고 배탈 나는 똥개
    어리석게 꼭지에서 주식 사는 너구리
    정신 못 차리고 반바지에 긴 양말 신은 코흘리개
    한심하게 노래방 가서 고해 부르는 개미햝기
    아무 생각없이 담뱃불 붙이다 앞머리 불 붙은 이등병

    1-1. Read Words.csv as dictionary type
    with open(path,'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
    
        for row in reader:
            print(row)

    {'\ufeff수식어1': '멍청하게', '수식어2': '떡볶이 먹고 배탈 나는', '명사': '똥개'}
    {'\ufeff수식어1': '어리석게', '수식어2': '꼭지에서 주식 사는', '명사': '너구리'}
    {'\ufeff수식어1': '정신 못 차리고', '수식어2': '반바지에 긴 양말 신은', '명사': '코흘리개'}
    {'\ufeff수식어1': '한심하게', '수식어2': '노래방 가서 고해 부르는', '명사': '개미햝기'}
    {'\ufeff수식어1': '아무 생각없이', '수식어2': '담뱃불 붙이다 앞머리 불 붙은', '명사': '이등병'}

    1-2. Get rid of '\ufeff' from the head of data
    with open(path,'r', encoding='utf-8-sig') as f:
        reader = csv.DictReader(f)
    
        for row in reader:
            print(row)

    {'수식어1': '멍청하게', '수식어2': '떡볶이 먹고 배탈 나는', '명사': '똥개'}
    {'수식어1': '어리석게', '수식어2': '꼭지에서 주식 사는', '명사': '너구리'}
    {'수식어1': '정신 못 차리고', '수식어2': '반바지에 긴 양말 신은', '명사': '코흘리개'}
    {'수식어1': '한심하게', '수식어2': '노래방 가서 고해 부르는', '명사': '개미햝기'}
    {'수식어1': '아무 생각없이', '수식어2': '담뱃불 붙이다 앞머리 불 붙은', '명사': '이등병'}

  • Count words without duplication from .txt file

  • import re for using regular expression

    Codes : CountWords.py
    import os
    import re
    # Check if the target file exists
    path = "C:\\...\\Python\\subtitle - 1.1.txt"
    os.path.isfile(path)

    True

    # Call words' list with duplication
    document_raw = open(path, 'r')
    document_lower = document_raw.read().lower()
    words_duplication = re.findall(r'\b[a-z]{3,15}\b', document_lower)
    # Regular expression to avoid meaningless or wrong words
    # Remove duplication from the list
    words = set(words_duplication)
    print(len(words))

    455

  • Simple practice with print()

    Codes : Print.py
    #1. Print normally
    print("위")
    print("아래")


    아래

    #2. Write on the same line
    print("왼쪽", end='')
    print("에 붙여서 계속")

    왼쪽에 붙여서 계속

    #3. Change lines within one function
    print("줄을\n\n바꿔")

    줄을

    바꿔

  • Simply Generating Fibonacci Series by Python

    FibonacciSeries.py

    a = [1, 1]
    n = 2
    
    while n<10 : # length = 10
        a.append(a[n-2] + a[n-1])
        n += 1
    
    print(a)

    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

  • Generate lists by various ways

    GenerateList.py

    list1 = [[0,0], [0,0], [0,0], [0,0]]
    list2 = [[0,0]] * 4
    list3 = [0,0] * 4
    
    print(list1, "\n", list2, "\n", list3)
    list1 == list2

    [[0, 0], [0, 0], [0, 0], [0, 0]]
    [[0, 0], [0, 0], [0, 0], [0, 0]]
    [0, 0, 0, 0, 0, 0, 0, 0]
    True

  • Read binary file

  • Convert decimal number ↔ hexadecimal number

    Codes : WithOpen.py
    # get current working directory
    import os
    
    os.getcwd()
    print(os.getcwd())
    
    # check if the file exists
    os.path.isfile("path")

    True

    import binascii
    
    # with statement
    with open('path','rb') as f: # rb : read & binary
        string = f.read()
        print(string[0:10])
        print(binascii.b2a_hex(string[0:10]))

    b'1990.02.19'
    b'313939302e30322e3139'

    # with statement X
    f = open('path','rb')
    data = f.read()
    print(data[0:10])
    print(binascii.b2a_hex(data[0:10]))
    f.close()

    b'1990.02.19'
    b'313939302e30322e3139'

    # decimal → hexadecimal
    hex(30000)
    hex(3000000)
    hex(100)

    '0x7530'
    '0x2dc6c0'
    '0x64'

    # hexadecimal → decimal
    int('7530', 16)
    int('2dc6c0', 16)
    int('64', 16)

    30000
    3000000
    100

  • Input the correct passworld within 5 trials or die

  • Practice if~else, break/continue, time.sleep() and so on

    Password.py

    Codes : Password.py
    import time # for using time.sleep()
    
    chance = 0
    pw_original = "mymy" # password. a word that calls a pass. you nahm sayin?
    
    while chance < 5 :
        pw_input = input("Input your password : ")
    
        # right
        if pw_original == pw_input :
            print("You entered the correct password")
            break
        
        # wrong
        else:
            chance += 1
            print("You entered the wrong passwords", chance, "times.")
            if chance == 5 :
                print("You bad guys will be delayed as a penalty.")
                time.sleep(3)
            else :
                continue
    
    # Of course, saving the original password in this file is somewhat stupid.
    # But, yes I am.
  • Simple Python class practice

    Class.py

    class MyFirstClass :
        
        def Family(self, name, role):
            print(name, "is a(an)", role, "in my family")
    
    Do = MyFirstClass()
    
    Do.Family("Kim", "Husband")
    Do.Family("Shin", "Wife")
    Do.Family("Kim", "Future Baby")

    Python_Class_Test

    I found that a simple class in Python doesn't need stuffs like __main__, __init__ and so on.
    What the __hell__?

  • Simple Python practice

    While.py

    death_entropy = 100
    my_entropy = 1
    
    while(my_entropy < death_entropy) :
        print(my_entropy)
        my_entropy += 1
    print('Nirvana')
    1
    2
    3
    ……
    100
    Nirvana