DanKim0213 / Today-I-Learned

Today I Learned
1 stars 0 forks source link

Python #13

Open DanKim0213 opened 1 year ago

DanKim0213 commented 1 year ago

Python

What is Python?

Python syntax

Class

Python tools

AndreaBoffaAW commented 1 year ago

Python is a high-level, interpreted programming language that is widely used for various purposes such as web development, data analysis, artificial intelligence, and more. Its syntax is simple and easy to learn, and it supports object-oriented programming with features such as classes. There are also many tools available for Python development, such as IDEs, text editors, and libraries/modules for specific functionalities.

DanKim0213 commented 1 year ago

Item "None" of "Optional[List[int]]" has no attribute "append" [union-attr]

test: dict[int, list[int]] = {}
# error occurred: test.get(1).append(2)
_list = test.get(1)
if _list is not None: 
    _list.append(2)
DanKim0213 commented 1 year ago

Python Variable Scope

A variable scope specifies the region where we can access a variable. Based on the scope, variables in Python could be one of these types: global, local, or nonlocal variable.

To explain the variable scopes, I comply with an order.

  1. Declare a variable
  2. Call an inner function
  3. Print the current variable I declared at the first step

Let's give a quick glance at the following code:

def outer_func():
    def inner_func():
        message = "local2 :)"
        print("call from inner function: ", message)

    message = "local1 :)"
    inner_func()
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

# Output:
# call from inner function:  local2 :)
# call from outer function:  local1 :)
# call from global:  global :) 

Read Global, Local, or Nonlocal variable

We can read variables of the three types by complying with the default order in Python. However, sometimes we need to directly read variables using global or nonlocal keyword.

Call the global variable

def outer_func():
    def inner_func():
        # message = "local2 :)"
        print("call from inner function: ", message)

    # message = "local1 :)"
    inner_func()
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

# Output:
# call from inner function:  global :)
# call from outer function:  global :)
# call from global:  global :) 

Call the global variable with local1 variable

def outer_func():
    def inner_func():
        global message
        # message = "local2 :)"
        print("call from inner function: ", message)

    message = "local1 :)"
    inner_func()
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

# Output:
# call from inner function:  **global :)**
# call from outer function:  local1 :)
# call from global:  global :) 

Call the local1 within the inner function

def outer_func():
    def inner_func():
        nonlocal message
        # message = "local2 :)"
        print("call from inner function: ", message)

    message = "local1 :)"
    inner_func()
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

# Output:
# call from inner function:  **local1 :)**
# call from outer function:  local1 :)
# call from global:  global :) 

SyntaxError: no binding for nonlocal 'message' found

def outer_func():
    nonlocal message # use global instead 
    message = "local1 :)"
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

Update global or nonlocal variable

We've seen the usage of global and local keywords to read variables. What if we'd like to update the variables?

global keyword

def outer_func():
    global message
    message = "local1 :)"
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

# Output:
# call from outer function:  local1 :)
# call from global:  local1 :) 

nonlocal keyword

def outer_func():
    def inner_func():
        nonlocal message
        message = "local2 :)"
        print("call from inner function: ", message)

    message = "local1 :)"
    inner_func()
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

# Output:
# call from inner function:  local2 :)
# call from outer function:  local2 :)
# call from global:  global :) 

UnboundLocalError: local variable 'message' referenced before assignment

def outer_func():
    # To resolve, **global message** required
    message = message + "local1 :)" 
    inner_func()
    print("call from outer function: ", message)

message = "global :)"
outer_func()
print("call from global: ", message)

Thoughts

Variable Shadowing is not a good practice for coding like we did above. However, we sometimes need to use global or nonlocal keyword to update variables we already declared.

I think the rule of thumb could be put '_' before the variable name, such as '_message', for global variables. By doing so, I could figure out whether to use a global or local variable.

(Also, declaring variables as capitalized for final static variables is a good practice, too. For example, 'N', 'K', 'NUM_OF_PEOPLE')

References

DanKim0213 commented 1 year ago

Enumerate

https://realpython.com/python-enumerate/

DanKim0213 commented 1 year ago

Sorting

# Example: 아기상어 
# sort 1. Distance 2. min x 3. min y
candidates = [(x, y, dist)]
candidates.sort(key=lambda x: (x[2], x[0], x[1])

What if I'd like to sort x[0] in a reverse order?

Furthermore

DanKim0213 commented 1 year ago

Generators

# Example: dfs와 bfs 
print(' '.join(str(node) for node in numbers\_list)) 
# output: 1 2 3 4 

Furthermore

DanKim0213 commented 1 year ago

Priority Queue

https://realpython.com/queue-in-python/#priority-queue-sorted-from-high-to-low

DanKim0213 commented 1 year ago

Built-in Functions

Python docs

DanKim0213 commented 1 year ago

Logical Operators

Use () to set priority.

print(False or True and False) # False
print(True or False and False) # True

Where it comes from

I tried to solve SWEA 1767

    grid = []
    positions = []
    edges = 0  # to check the grid is surrounded by cores
    for i in range(N):
        row = list(map(int, input().split()))
        grid.append(row)
        for j in range(N):
            if (i == 0 or i == N - 1 or j == 0 or j == N - 1) and row[j] == 1:
                edges += 1
            if 0 < i < N - 1 and 0 < j < N - 1 and row[j] == 1:
                positions.append((i, j))

The upper code could be better:

    grid = []
    positions = []
    edges = 0  # to check the grid is surrounded by cores
    for i in range(N):
        row = list(map(int, input().split()))
        grid.append(row)
        for j in range(N):
            if row[j] != 1:
                continue
            elif 0 < i < N - 1 and 0 < j < N - 1:
                positions.append((i, j))
            else:
                edges += 1
DanKim0213 commented 1 year ago

Type Hint

link

Item "None" of "Optional[List[int]]" has no attribute "append" [union-attr]

test: dict[int, list[int]] = {}
# error occurred: test.get(1).append(2)
_list = test.get(1)
if _list is not None: 
    _list.append(2)
DanKim0213 commented 1 year ago

Assert statement to debug

DanKim0213 commented 1 year ago

Mutable vs Immutable types in python

While solving Baekjoon problem, I met this code:

# To check `visited`
def board_to_string(board):
    return "".join(str(num) for row in board for num in row)

I think it would cost a lot since string is an immutable type. And then, suddenly I would like to know Mutable vs Immutable types in python.

DanKim0213 commented 1 year ago

How List works?

lst = [0, 0, 1, 0, 1, 0]  # Q. which one between 00010 or 00100 would be printed?
lst.remove(1)
print(lst)  # 00010

Aha, remove() works from the beginning of the list while pop() works from the end.

What happens if removing first element from a list in python and what is the time complexity?

In Python, if you remove the first element from a list using the pop() method with an index of 0 or by using slicing (del lst[0]), the first element will be removed from the list, and all other elements will be shifted one position to the left. The size of the list will be reduced by one, and the index of each remaining element will be decreased by 1.

For example, consider the following list:

lst = [10, 20, 30, 40, 50]

If you remove the first element using pop(0) or del lst[0], the list will become:

lst = [20, 30, 40, 50]

Keep in mind that removing elements from the beginning of a list can be less efficient than removing elements from the end since it requires shifting all subsequent elements.

Regarding time complexity, the time complexity for removing the first element from a list in Python is O(n), where "n" is the number of elements in the list. This is because removing an element from the beginning of a list requires shifting all the remaining elements to the left, which takes linear time proportional to the number of elements in the list.

If you need to frequently remove elements from the beginning of a collection and the order of elements is important, you might consider using a data structure like a deque from the collections module, which provides more efficient operations for appending and popping elements from both ends with a time complexity of O(1).

How to remove an element while iterating?

"Never remove elements from the list you're iterating over. Create a new list."

What happens when comparing list?

import time

def sum_list(numbers):
    total = 0
    for number in numbers:
        total += number
    return total

for n in [10, 100, 1000, 10000, 100000, 1000000]:
    numbers = list(range(n))
    start_time = time.time()
    result = sum_list(numbers)  # O(N)
    end_time = time.time()
    print(f"Input size: {n}, Time: {end_time - start_time} seconds")

    start_time = time.time()
    result = numbers == list(range(n // 10))  # depends on the shorter one
    end_time = time.time()
    print(f"compare Input size: {n}, Time: {end_time - start_time} seconds")

'''
output:

Input size: 10, Time: 1.9073486328125e-06 seconds
compare Input size: 10, Time: 1.1920928955078125e-06 seconds
Input size: 100, Time: 5.0067901611328125e-06 seconds
compare Input size: 100, Time: 1.1920928955078125e-06 seconds
Input size: 1000, Time: 3.790855407714844e-05 seconds
compare Input size: 1000, Time: 2.1457672119140625e-06 seconds
Input size: 10000, Time: 0.00037789344787597656 seconds
compare Input size: 10000, Time: 1.3828277587890625e-05 seconds
Input size: 100000, Time: 0.003981113433837891 seconds
compare Input size: 100000, Time: 0.00015306472778320312 seconds
Input size: 1000000, Time: 0.02839970588684082 seconds
compare Input size: 1000000, Time: 0.001276254653930664 seconds
'''

The time complexity of comparing two lists depends on the shorter list:

# Let's pair them based on the approximately same time complexity

Input size: 100, Time: 5.0067e-06 seconds
compare Input size: 1000, Time: 2.1457e-06 seconds

Input size: 1000, Time: 3.7908e-05 seconds
compare Input size: 10000, Time: 1.3828e-05 seconds

Input size: 10000, Time: 0.0003 seconds
compare Input size: 100000, Time: 0.0001 seconds

Input size: 100000, Time: 0.0039 seconds
compare Input size: 1000000, Time: 0.0012 seconds
DanKim0213 commented 1 year ago

Iterator vs Iterable

range() is also iterable.

for i in range(4):
    print(i)

Combinatoric iterators in Itertools

Examples Results
product(range(2), repeat=2) 00 01 10 11
product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2) AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD
DanKim0213 commented 1 year ago

How do I use multiple keys in heapq?

DanKim0213 commented 1 year ago

pip vs python -m pip

The -m flag makes sure that you are using the pip that's tied to the active Python executable.

It's good practice to always use -m, even if you have just one global version of Python installed from which you create virtual environments.

DanKim0213 commented 9 months ago

Floor Division

// is Floor Division

연산자 끼워넣기

Floor Division

print(1//3) # 0
print(-1//3) # -1
print(int(-1/3)) # 0
DanKim0213 commented 8 months ago

How to copy leftover values

연산자 끼워넣기 Destructuring in Python

val = (1, 2, 3)
val2 = (*val, 4)
print(val2) # (1, 2, 3, 4)