다중 상속(multiple inheritance)에서 다이아몬드 문제란?
같은 클래스를 상속받은 클래스 두 개를 모두 상속받는 클래스가 있을 때 이 자식 클래스가 2개의 부모 클래스 안의 중복되는 메소드에 대해 어떻게 상속을 처리할 것인지 모호해지는 것을 다이아몬드 문제라고 합니다.
이런 문제로 JAVA, 루비 등에서는 다중 상속을 지원하지 않습니다.
파이썬, C++, 스칼라 등에서는 다중 상속을 지원하는데
파이썬에서는 다이아몬드 문제를 해결하기 위해서 MRO 라는 것을 도입했습니다. MRO는 C3선형화 알고리즘을 통해서 상속받는 메소드의 순서를 결정합니다. 클래스의 __mro__를 확인하면 순서를 확인할 수 있습니다.
*파이썬은 교차상속은 지원하지 않아 다중상속을 할 때는 상속받는 클래스의 순서에 유의해야합니다.
파이썬에서 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. 공식문서
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
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가 맞는지도 모르겠디.
🫣 swift에서 copy메소드를 실행할 때
데이터 타입에 따라서 실행되는 복사가 다르다.
ref type
의 객체를 복사하면 얕은 복사가 되고 얕은 복사는 복사로 만들어진 객체가 원본 객체의 메모리를 참조하게 되어 원본 객체가 수정되는 경우 복사된 객체에 영향을 미친다
val type
의 객체를 복사하게되면 깊은 복사를 하게 되고 깊은 복사는 원본으로부터 독립적인 객체를 만들어낸다. 이 객체는 원본 객체의 모든 인스턴스를 복사하므로 새로운 메모리 공간에 인스턴스를 복사하므로 얕은 복사에 비해 느리다
https://velog.io/@ellyheetov/Shallow-Copy-VS-Deep-Copy
튜플 컴프리헨션 없음 → 제너레이터가 됨
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
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
__iter__메소드를 가지며 iterator를 반환하는 객체
x=[1,2,3] #iterable
y=iter(x) #iterator
반복이 가능하다면 iter함수를 이용해서 이터레이터로 만들 수 있다
문자열(str), 튜플(tuple), 리스트(list), 딕셔터리(dictionary), 집합(set)
*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 willcreate 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/
모든 제너레이터는 이터레이터를 만들기때문에 제너레이터 객체는 이터레이터라 할 수 있다. 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 completelyyield는 함수의 결과 값을 하나씩 내보내고 다시 돌아옴
- 필요없는 계산을 하지 않으므로 → 제너레이터의 특징임
- 그래서 실행을 더 빠르게 할 수 있다..❓ 필요없는 부분이 있는 경우 그럴 수도
- 함수형 프로그래밍 언어에서 주로 사용
💥 yield와 lazy evaluation
상관 없는듯 그냥 제너레이터가 lazy evaluation을 하는 거고
yield는 그냥 리턴 대신 사용되면서 상태가 저장되는 그런 메소드인거고
- yield이게 lazy evaluation❓
- lazy eval는❓ 한번에 값을 하나씩만 yield함
suspended
(at yield statement), the state of that function is saved.list comprehensions return full lists vs generator expressions return generators
generators are more memory and CPU efficient
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
>>> 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()
built_in_func(obj)
list[시작:끝:규칙]
list[::-1] → 처음부터 끝까지 뒤집기
list[-2::-1] → 끝에서부터 2번째 값을 시작값으로 해서 뒤집기
맨 끝에 0을 먼저 붙인 다음에 걔는 빼고 뒤집어야해서 이렇게 했당