파이썬

다이아몬드 문제

  1. 다중 상속(multiple inheritance)에서 다이아몬드 문제란?
    같은 클래스를 상속받은 클래스 두 개를 모두 상속받는 클래스가 있을 때 이 자식 클래스가 2개의 부모 클래스 안의 중복되는 메소드에 대해 어떻게 상속을 처리할 것인지 모호해지는 것을 다이아몬드 문제라고 합니다.
    이런 문제로 JAVA, 루비 등에서는 다중 상속을 지원하지 않습니다.

    파이썬, C++, 스칼라 등에서는 다중 상속을 지원하는데
    파이썬에서는 다이아몬드 문제를 해결하기 위해서 MRO 라는 것을 도입했습니다. MRO는 C3선형화 알고리즘을 통해서 상속받는 메소드의 순서를 결정합니다. 클래스의 __mro__를 확인하면 순서를 확인할 수 있습니다.

    *파이썬은 교차상속은 지원하지 않아 다중상속을 할 때는 상속받는 클래스의 순서에 유의해야합니다.

    https://xo.dev/python-method-resolution-order/

복사

  1. 얕은 복사(shallow copy)와 깊은 복사(deep copy)의 차이는 무엇인가?
    어떤 객체를 얕은 복사를 하게 되면 새로운 단일/복합 객체가 생성되고 이 새로운 객체는 원본 객체를 참조하게 됩니다. 원본 객체가 수정되는 경우 복사된 객체에도 같은 수정 사항이 반영됩니다. (call by ref와 유사한 개념)
    깊은복사는 원본 객체로부터 독립적인 객체로 모든 인스턴스를 다 복사하기 때문에 얕은 복사에 비해서 느립니다.

파이썬은 기본적으로 call by ref라서 얕은 복사를 수행함

파이썬에서 copy()는 얕은 복사를 의미하고 deepcopy()를 하면 깊은 복사를 할 수 있습니다.
얕은 복사와 깊은 복사의 차이점은 복합 객체에서만 유효합니다.

  • 얕은 복사는 새로운 복합 객체를 만들고 원본 객체를 가리키는 레퍼런스를 새로운 복합 객체에 삽입
  • 깊은 복사는 새로운 복합 객체를 만들고 재귀적으로 원본 객체의 사본을 새로운 복합 객체에 삽입
    • 복합 객체: 리스트/ 클래스 인스턴스처럼 다른 객체를 포함하는 객체

https://docs.python.org/ko/3/library/copy.html?highlight=copy#module-copy
https://stackoverflow.com/questions/6158907/what-does-python-treat-as-reference-types

Assignment statements in Python do not copy objects, they create bindings between a target and an object. 공식문서

Python의 정체성 💥

Everything in Python is an object

All values in Python are references.

There are names and objects in Python and together they appear like variables

  • Assignment binds a name to an object.
  • Passing an argument into a function also binds a name (the parameter name of the function) to an object.

It doesn't help in Python to think in terms of references or values. Neither is correct.

Basically, the CPython compiler will often optimize immutable constant expressions to the same object. How and when it happens depends on a lot of things, and again, is an implementation detail
또 인터프리터에 따라서 다르고 버전에 따라서도 다르다

only mutable can be mutated

Everything in Python is passed and assigned by value.
Every value in Python is a reference (pointer) to an object.
Objects cannot be values.
Assignment always copies the value (which is a pointer)

파이썬이 인자를 함수에 전달하는 과정을 다양하게 부른다
(위에 스택오버플로우 참조)
pass-by-assignment
pass-by-reference value
pass-by-object reference

call-by-object

이건 내 생각 🫣

x=10에서
x라는 스트링은 10이라는 오브젝트를 가리키는 pointer와 매핑된다
생각해보니까 10이라는 오브젝트는 하나밖에 없으니까
포인터랑 매핑될 수 밖에 없네
name, label, ref, value - object가 뭐든지 다 이 개념을 표현하기 위한 것 같다.

결국 어느 이름이 맞는지는 모르겠다. 보통 다른 언어에서 부르는 value랑 ref의 의미가 파이썬에는 하나에 함축되어있는 거나 마찬가지니까 새로운 이름이 필요한가? 어쨌든 value가 ref의 역할을 하는거니까 일반적으로 얘기하자면 ref가 맞는지도 모르겠디.

  • object는 생성과 삭제가 되고 ref가 될 뿐 변하지 않는다 절대!
  • name 과 pointer가 dictionary처럼 mapping되는 게 맞는 것 같다 단지 pointer는 눈에 보이지 않을 뿐

🫣 swift에서 copy메소드를 실행할 때

데이터 타입에 따라서 실행되는 복사가 다르다.
ref type의 객체를 복사하면 얕은 복사가 되고 얕은 복사는 복사로 만들어진 객체가 원본 객체의 메모리를 참조하게 되어 원본 객체가 수정되는 경우 복사된 객체에 영향을 미친다
val type의 객체를 복사하게되면 깊은 복사를 하게 되고 깊은 복사는 원본으로부터 독립적인 객체를 만들어낸다. 이 객체는 원본 객체의 모든 인스턴스를 복사하므로 새로운 메모리 공간에 인스턴스를 복사하므로 얕은 복사에 비해 느리다
https://velog.io/@ellyheetov/Shallow-Copy-VS-Deep-Copy

축약식

  1. 리스트, 딕셔너리, 튜플 컴프리헨션은 무엇인가?
    컴프리헨션은 축약식으로 리스트, 딕셔너리, set과 같은 컨테이너 타입의 데이터를 간결한 방식으로 만들어낼 수 있는 문법이다. 각각 대괄호, 중괄호 안에 for문과 if문을 사용한 generator expression을 이용해 만들 수 있다.
    *튜플 컴프리헨션은 따로 존재하지 않으며 이 형태는 제너레이터 오브젝트가 된다.

튜플 컴프리헨션 없음 → 제너레이터가 됨
set 컴프리헨션 있음

[thing for thing in things] constructs a list much faster than list(thing for thing in things)

https://stackoverflow.com/questions/16940293/why-is-there-no-tuple-comprehension-in-python

이터레이터

  1. 이터레이터란 무엇인가?
    여러개의 요소를 가지는 데이터 (iterable)안에서 각 요소를 하나씩 꺼내서 사용할 수 있도록 합니다. 주어진 대상에 iter()함수를 호출해서 이터레이터 객체를 구하고 내부의 요소를 하나씩 가져오기 위해서 next()를 호출하며 더이상 가져올 요소가 없으면(더 반환할 값이 없다면) stopiteration예외를 발생시킵니다.

iterator

iterator is like a lazy factory that is idle until you ask it for a value
internal state를 hold하는 stateful helper object
== The state inside this iterator is fully kept inside the prev and curr instance variable → so they can use next()

All of the itertools functions return iterators
Any object that has a \__next__() method is an iterator

iterable

__iter__메소드를 가지며 iterator를 반환하는 객체
x=[1,2,3] #iterable
y=iter(x) #iterator

반복이 가능하다면 iter함수를 이용해서 이터레이터로 만들 수 있다

Container 자료형

문자열(str), 튜플(tuple), 리스트(list), 딕셔터리(dictionary), 집합(set)

  • container type을 상속받음
    • issubclass(X, Y): X 가 Y의 속성을 상속했는지 확인
  • __contains__ 메소드를 가진 데이터타입
  • 'in'을 사용할 수 있음

*Literal 자료형: 정수, 실수, 복소수 등은 타입이 고정되어 있는 단일 종류

container vs iterables

an important point of difference between containers and general iterables is that when iterated over, containers will return existing objects that they hold a reference to,
while generators and e.g. file objects will create a new object each time. This has implications for garbage collection and deep object traversal (e.g. deepcopy and serialisation)

https://nvie.com/posts/iterators-vs-generators/

제너레이터

  1. 제너레이터란 무엇인가?
    iter, next 메소드를 사용하지 않고 yield를 통해 iterator를 만들어낸다. 이때 제너레이터 함수를 이용할 수도 있고 제너레이터 표현식을 사용할 수도 있다.

모든 제너레이터는 이터레이터를 만들기때문에 제너레이터 객체는 이터레이터라 할 수 있다. not vice versa!
→ 제너레이터 또한 stateful하다

A generator function is any function in which the keyword yield appears in its body.
A generator will be garbage collected after its use.

Generators work the same whether they’re built from a function or an expression. Using an expression just allows you to define simple generators in a single line, with an assumed yield at the end of each inner iteration.

generating an infinite sequence will need a generator since your computer memory is finite
using yield can capture the initial state

💥 yield

yield indicates where a value is sent back to the caller, but unlike return, you don’t exit the function afterward.

yield returns the yielded value to the caller.
return stops function execution completely

yield는 함수의 결과 값을 하나씩 내보내고 다시 돌아옴

  • 필요없는 계산을 하지 않으므로 → 제너레이터의 특징임
  • 그래서 실행을 더 빠르게 할 수 있다..❓ 필요없는 부분이 있는 경우 그럴 수도
  • 함수형 프로그래밍 언어에서 주로 사용

💥 yield와 lazy evaluation

상관 없는듯 그냥 제너레이터가 lazy evaluation을 하는 거고
yield는 그냥 리턴 대신 사용되면서 상태가 저장되는 그런 메소드인거고
- yield이게 lazy evaluation❓
- lazy eval는❓ 한번에 값을 하나씩만 yield함

lazy evaluation

  • as the same as the iterator, generator has latency issues
  • When a function is suspended(at yield statement), the state of that function is saved.

list comprehension vs generator

list comprehensions return full lists vs generator expressions return generators

generators are more memory and CPU efficient

  • 요청시에만 값을 리턴하여 대용량의 iterable객체에서 유용하게 사용할 수 있습니다
    • 대용량이더라도 제너레이터는 하나씩 리턴하는 격이므로 메모리 상태를 봐가면서 할당할 수 있음???
    • 리턴은 전체 함수의 실행 결과를 한번에 쫜-! 하면서 함수가 종료됨
      한번에 쫜-!해서 담을 메모리가 없을 수도 있음

If the list is smaller than the running machine’s available memory, then list comprehensions can be faster to evaluate than the equivalent generator expression.

https://realpython.com/introduction-to-python-generators/#example-1-reading-large-files

cycle( ) 내장함수

>>> from itertools import islice
>>> colors = cycle(['red', 'white', 'blue'])  # infinite
>>> limited = islice(colors, 0, 4)            # finite
>>> for x in limited:                         # so safe to use for-loop on
...     print(x)
red
white
blue
red

프로그래머스 문제풀기

➡️ 푸드 파이트 대회

 food.pop(0)
 for f in range(len(food)):
         if food[f]//2!=0:
             food[f]=(food[f]//2)*str(f+1)
     food=[x for x in food if x!=1]

첨에 물을 그냥 뺐는데
물도 어차피 항상 1이고 리스트에서 1인 값은 결국 못쓰게 되어있어서 4번째 줄에서 빠지게 되어있어서 빼도 상관없고,
인덱스 값 가용하는 3번째 줄만 f+1 → f 바꿔주면 된다.

그리고 리스트 축약식을 쓰면 for문을 만드는 데서부터 쓸데없는 값이 다 빠지게 돼서 아래 x가 1이 아닌 값만 들어간 리스트 축약식을 없애도 된다

그래서 한 줄이 된다 짜잔..

food=[(x//2)*str(i) for i,x in enumerate(food) if x != 1]

이후에 0을 중심으로 리스트를 뒤집어서 이어붙여야하는데 처음에 reversed를 이용했는데 슬라이싱을 사용해서 뒤집을 수도 있다.

food.append('0')
food.extend(food[-2::-1])
return ''.join(food)

근데 이렇게 한방에 할수도 있을듯

return ''.join(food)+'0'+''.join(food[::-1])

무튼 난 최대한 리스트를 이용하려고 한거라 만족한다 끗

리스트 관련 문법

리스트 뒤집기

  • 리스트 메서드
    list.method()
    list.reverse() → list에 저장됨
    list.append()처럼 이 구문 자체를 어디에 사용하면 에러남 list가 변했기때문에 list로 사용해줘야함
  • 파이썬 내장함수
    built_in_func(obj)
    reversed(list) → 이 구문 자체를 사용할 수 있음

리스트 슬라이싱

list[시작:끝:규칙]
list[::-1] → 처음부터 끝까지 뒤집기
list[-2::-1] → 끝에서부터 2번째 값을 시작값으로 해서 뒤집기
맨 끝에 0을 먼저 붙인 다음에 걔는 빼고 뒤집어야해서 이렇게 했당

profile
looooggi

0개의 댓글