반응형

참고주소 : https://stackoverflow.com/questions/6473679/transpose-list-of-lists

리스트의 리스트를 transpose(전치행렬)

다음과 같은 행렬이 있습니다.

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

제가 찾고 있는 결과는 다음과 같습니다.

r = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

다음 결과는 아닙니다.

r = [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

매우 감사합니다.

13개 답변 중 1개

Python 3 :

# 테이블(행렬)이 들쭉날쭉한 경우 가장 짧은 내부 리스트 개수만큼 단락:
list(map(list, zip(*l)))

# 들쭉날쭉한 경우 데이터를 버리지 않고 내부 리스트를 None으로 채웁니다
list(map(list, itertools.zip_longest(*l, fillvalue=None)))

Python 2 :

map(list, zip(*l))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

설명:

진행 상황을 이해하기 위해 알아야 할 두 가지 사항이 있습니다.

  1. zip의 시그너쳐: zip(*iterables) 이것은 zip이 각각 반복 가능한 임의의 개수의 인수를 예상한다는 것을 의미합니다. 예를 들어 zip([1, 2], [3, 4], [5, 6]).
  2. unpack 된 인수 목록: 인수 args의 시퀀스가 주어지면 f(*args)args의 각 요소가 f의 개별 위치 인수가 되도록 f를 호출합니다.
  3. itertools.zip_longest는 내부 리스트의 요소 수가 동일하지 않은 경우(동종) 데이터를 버리지 않고 대신 더 짧은 중첩 목록을 채운 다음 zip 처리를 합니다.

질문 l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]의 입력으로 돌아가면 zip(*l)zip([1, 2, 3], [4, 5, 6], [7, 8, 9])와 같습니다. 나머지는 결과가 튜플의 리스트 대신 리스트의 리스트인지 확인하는 것입니다.

반응형
반응형

출처 : https://stackoverflow.com/questions/39993238/vlookup-between-2-pandas-dataframes

2개의 Pandas 데이터프레임 간에 vlookup

다음처럼 2개의 Pandas 데이터 프레임이 있습니다.

DF1:

Security     ISIN
ABC           I1 
DEF           I2
JHK           I3
LMN           I4
OPQ           I5

DF2:

ISIN      Value
 I2        100
 I3        200
 I5        300

저는 다음처럼 보이는 결국 세번째 데이터프레임을 얻고 싶습니다.

DF3:

Security   Value
 DEF       100
 JHK       200
 OPQ       300

2개의 답변 중 1개

당신은 기본으로 inner join에 의해 merge를 사용할 수 있습니다. how=inner는 제외되고 두 DataFrames에서 공통 열만 있다면, 당신은 파라미터 on=ISIN을 제외할 수 있습니다.

df3 = pd.merge(df1, df2)
#ISIN 열 제거
df3.drop('ISIN', axis=1, inplace=True)
print (df3)
  Security  Value
0      DEF    100
1      JHK    200
2      OPQ    300

또는 df1로부터 Series에 의한 ISIN 열을 map을 호출할 수 있습니다.

print (df1.set_index('ISIN')['Security'])
ISIN
I1    ABC
I2    DEF
I3    JHK
I4    LMN
I5    OPQ
Name: Security, dtype: object

#df2를 복사하여 새로운 df를 생성
df3 = df2.copy()
df3['Security'] = df3.ISIN.map(df1.set_index('ISIN')['Security'])
#ISIN열을 없앰
df3.drop('ISIN', axis=1, inplace=True)
#열의 순서를 변경
df3 = df3[['Security','Value']]
print (df3)
  Security  Value
0      DEF    100
1      JHK    200
2      OPQ    30
반응형
반응형

출처 : https://stackoverflow.com/questions/26835477/pickle-load-variable-if-exists-or-create-and-save-it

피클(Pickle) - 만약 존재하면 불러오고 그렇지 않으면 생성하여 저장하기

이미 존재하면 불러오고 그렇지 않으면 생성하여 덤프하여 pickle로 변수를 불어오는 더 좋은 방법이 있을까요?

if os.path.isfile("var.pickle"):
    foo = pickle.load( open( "var.pickle", "rb" ) )
else:
    foo = 3
    pickle.dump( foo, open( "var.pickle", "wb" ) )

2개 중 1개의 답변

당신은 용서를 구하면서 EAFP 원리를 따를 수 있습니다.

import pickle

try:
    foo = pickle.load(open("var.pickle", "rb"))
except (OSError, IOError) as e:
    foo = 3
    pickle.dump(foo, open("var.pickle", "wb"))
반응형
반응형

출처 : https://stackoverflow.com/questions/2921847/what-does-the-star-and-doublestar-operator-mean-in-a-function-call

함수 호출에서 별(*)과 쌍별(**) 연산자의 의미는 무엇입니까?

다음 코드 같은 zip(*x) 또는 f(**k)처럼 파이썬에서 * 연산자의 의미는 무엇입니까?

  1. 그것은 인터프리터로 내부적으로 어떻게 다루어집니까?
  2. 그것은 성능에 영향을 줍니까? 빠릅니까 또는 느립니까?
  3. 언제 유용하며 언제 그렇지 않습니까?
  4. 그것은 함수 선언에서 사용되어야 합니까? 호출할 때 사용되어야 합니까?

5개 중 1개의 답변

하나의 별 *은 시퀀스/컬렉션을 위치 인자로 unpack합니다. 다음처럼 사용할 수 있습니다.

def sum(a, b):
    return a + b

values = (1, 2)

s = sum(*values)

이는 튜플을 unpack하여 실제로 다음처럼 실행할 것입니다.

s = sum(1, 2)

쌍별 **은 같지만 dictionary와 이름있는 인자를 사용합니다.

values = { 'a': 1, 'b': 2 }
s = sum(**values)

다음처럼 결합하여 사용도 가능합니다.

def sum(a, b, c, d):
    return a + b + c + d

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)

이는 다음처럼 실행할 것입니다.

s = sum(1, 2, c=10, d=15)

또한, 파이썬 문서에서 4.7.4 인자 목록 언 패킹 섹션도 확인하세요.


또한 *x**y 인수를 사용하도록 함수를 정의할 수 있습니다. 이렇게 하면 함수가 선언에 구체적으로 이름이 지정되지 않아도 위치 및/또는 명명된 인수를 원하는 만큼 허용할 수 있습니다.

예시:

def sum(*values):
    s = 0
    for v in values:
        s = s + v
    return s

s = sum(1, 2, 3, 4, 5)

** 예시입니다.

def get_a(**values):
    return values['a']

s = get_a(a=1, b=2)      # 1을 리턴

이는 그들을 선언할 필요 없이 많은 수의 인자를 지정할 수 있도록 합니다.

def sum(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s

s = sum(1, 2, 3, 4, 5)            # 15를 리턴
s = sum(1, 2, 3, 4, 5, neg=True)  # -15를 리턴
s = sum(1, 2, 3, 4, 5, neg=False) # 15를 리턴
반응형
반응형

출처 : https://note.nkmk.me/en/python-for-enumerate-zip/

Python에서 enumerate()와 zip() 함께 사용하기

Python에서 enumerate()zip()for 루프에서 iterable(list, tuple 등)의 요소들을 iterate하는 데 유용합니다.

당신은 enumerate()로 인덱스를 얻을 수 있으며, zip()으로 여러개의 요소들을 얻을 수 있습니다.

이 글은 enumerate()zip()을 함께 사용할 때 참고 사항을 설명합니다.

enumerate()와 zip() 함께 사용할 때 참고 사항

여러개의 리스트와 인덱스의 요소를 얻고 싶을 때 enumerate()zip()를 함께 사용할 수 있습니다.

이 경우, for i, (a, b, ...) in enumerate(zip( ... ))처럼 괄호로 zip()의 요소들을 둘러쌓을 필요가 있습니다.

names = ['Alice', 'Bob', 'Charlie']
ages = [24, 50, 18]

for i, (name, age) in enumerate(zip(names, ages)):
    print(i, name, age)
# 0 Alice 24
# 1 Bob 50
# 2 Charlie 18

튜플로 zip()의 요소들을 받을 수도 있습니다.

for i, t in enumerate(zip(names, ages)):
    print(i, t)
# 0 ('Alice', 24)
# 1 ('Bob', 50)
# 2 ('Charlie', 18)
for i, t in enumerate(zip(names, ages)):
    print(i, t[0], t[1])
# 0 Alice 24
# 1 Bob 50
# 2 Charlie 18

표준 라이브러리의 itertools 모듈의 count()zip() 함수는 (i, a, b) 처럼 nested되지 않은 형태를 생성하는 데 사용될 수 있습니다.

반응형
반응형

출처 : https://stackoverflow.com/questions/893657/how-do-i-calculate-r-squared-using-python-and-numpy

Python과 Numpy를 사용하여 r-제곱을 계산하는 방법?

Python과 Numpy를 사용하여 임의의 차수에 가장 적합한 다항식을 계산합니다. x값, y값 및 내가 맞추려는 다항식의 차수(선형, 2차 등) 목록을 전달합니다.

이것은 많은 효과가 있지만 r(상관 계수)과 r-제곱(결정 계수)도 계산하고 싶습니다. Excel의 최적 추세선 기능 및 제가 계산하는 r-제곱 값 결과와 비교하고 있습니다. 이것을 사용하여 선형 최적 맞춤(차수는 1과 같음)에 대해 r-제곱을 올바르게 계산하고 있다는 것을 알고 있습니다. 그러나 내 함수는 차수가 1보다 큰 다항식에서는 작동하지 않습니다.

엑셀로 이를 할 수 있습니다. Numpy를 사용하여 고차 다항식에 대한 r-제곱을 어떻게 계산합니까?

제가 만든 함수는 다음과 같습니다.

import numpy

# 다항 회귀
def polyfit(x, y, degree):
    results = {}

    coeffs = numpy.polyfit(x, y, degree)
     # 다항 상관 계수 
    results['polynomial'] = coeffs.tolist()

    correlation = numpy.corrcoef(x, y)[0,1]

     # r
    results['correlation'] = correlation
     # r-제곱
    results['determination'] = correlation**2

    return results

12개 중 2개의 답변

numpy.polyfit 문서로부터 이는 선형 회귀에 적합(fit) 합니다. 특히, 차수가 'd'인 numpy.polyfit은 평균 함수를 사용하여 선형 회귀에 맞춥니다.

E(y|x) = p_d * x ** d + p_{d-1} * x ** (d-1) + ... + p_1 * x + p_0

따라서 해당 회귀에 적합(fit)하도록 R-제곱을 계산하기만 하면 됩니다. 선형 회귀에 대한 wikipedia 페이지는 자세한 내용을 제공합니다. 당신은 몇 가지 방법으로 계산할 수 있는 R^2에 관심이 있습니다. 가장 쉬운 것은 아마도

SST = Sum(i=1..n) (y_i - y_bar)^2
SSReg = Sum(i=1..n) (y_ihat - y_bar)^2
Rsquared = SSReg/SST

여기서 y의 평균으로 'y_bar'를 사용하고 각 점에 대한 맞춤(fit) 값으로 'y_ihat'을 사용합니다.

저는 numpy에 익숙하지 않습니다(저는 일반적으로 R에서 작업합니다). 따라서 R-제곱을 계산하는 더 깔끔한 방법이 있을 수 있지만 다음 방법은 정확할 것입니다.

import numpy

# 다항 회귀
def polyfit(x, y, degree):
    results = {}

    coeffs = numpy.polyfit(x, y, degree)

     # 다항 상관 계수 
    results['polynomial'] = coeffs.tolist()

    # r-제곱
    p = numpy.poly1d(coeffs)
    # 적합(fit) 값들과 평균 
    yhat = p(x)                         # or [p(z) for z in x]
    ybar = numpy.sum(y)/len(y)          # or sum(y)/len(y)
    ssreg = numpy.sum((yhat-ybar)**2)   # or sum([ (yihat - ybar)**2 for yihat in yhat])
    sstot = numpy.sum((y - ybar)**2)    # or sum([ (yi - ybar)**2 for yi in y])
    results['determination'] = ssreg / sstot

    return results

매우 늦은 답변이지만, 이를 위해 준비된 함수가 누군가는 필요할 것입니다.

scipy.stats.linregress

예시

slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(x, y)
반응형
반응형

출처 : https://stackoverflow.com/questions/1060279/iterating-through-a-range-of-dates-in-python

Python에서 날짜 범위를 반복하기

이를 하기 위해 다음 코드가 있지만, 어떻게 하면 더 좋게 할 수 있을까요? 지금은 중첩 루프보다 낫다고 생각하지만 list comprehension에 generator로 한 줄씩 날짜를 얻기 시작합니다.

day_count = (end_date - start_date).days + 1
for single_date in [d for d in (start_date + timedelta(n) for n in range(day_count)) if d <= end_date]:
    print strftime("%Y-%m-%d", single_date.timetuple())

Notes

  • 나는 실제로 이것을 출력하는 데 사용하지 않습니다. 그냥 이는 데모 용입니다.
  • start_dateend_date 변수는 타임 스탬프가 필요하지 않기 때문에 datetime.date 개체입니다. (보고서를 생성하는 데 사용됩니다).

샘플 출력

시작날짜 2009-05-30에서 끝날짜 2009-06-09 동안 출력합니다.

2009-05-30
2009-05-31
2009-06-01
2009-06-02
2009-06-03
2009-06-04
2009-06-05
2009-06-06
2009-06-07
2009-06-08
2009-06-09

24 개의 답변 중 1 개의 답변만 추려냄.

왜 이중 for문을 반복하시나요? 저는 하나의 반복문으로 데이터의 같은 list를 생산합니다.

for single_date in (start_date + timedelta(n) for n in range(day_count)):
    print ...

그리고 list가 저장되지 않고 하나의 generator에서만 반복됩니다. 또한 generator의 "if"는 불필요한 것 같습니다.

결국 선형 시퀀스에는 두 개가 아닌 하나의 반복자만 필요합니다.

John Machin과 토론 후 갱신

아마도 가장 우아한 해결책은 generator 함수를 사용하여 날짜 범위에 대한 반복을 완전히 숨기거나 줄이는 것입니다.

from datetime import date, timedelta

def daterange(start_date, end_date):
    for n in range(int((end_date - start_date).days)):
        yield start_date + timedelta(n)

start_date = date(2013, 1, 1)
end_date = date(2015, 6, 2)
for single_date in daterange(start_date, end_date):
    print(single_date.strftime("%Y-%m-%d"))

주의: 내장 range() 함수와의 일관성을 위해 이 반복은 end_date에 도달하기 전에 중지됩니다. 따라서 포괄적인 반복을 위해서는 range()에서와 같이 다음 날을 사용하십시오.

    for n in range(int ((end_date - start_date).days+1)):
반응형
반응형

출처 : https://stackoverflow.com/questions/19231871/convert-unix-time-to-readable-date-in-pandas-dataframe

Unix 시간을 pandas dataframe에서 읽을 수 있는 날짜로 변환하기

저는 Unix 시간으로 가격이 포함된 dataframe이 있습니다. 사람이 읽을 수 있는 날짜로 표시되도록 index 열을 변환하고 싶습니다.

예를 들어 index 열에서 date1349633705가 있지만 그것이 10/07/2012(또는 적어도 10/07/2012 18:15)로 보여지길 원합니다.

다음 구문에서 내가 작업 중인 코드와 이미 시도한 코드는 다음과 같습니다.

import json
import urllib2
from datetime import datetime
response = urllib2.urlopen('http://blockchain.info/charts/market-price?&format=json')
data = json.load(response)   
df = DataFrame(data['values'])
df.columns = ["date","price"]
#convert dates 
df.date = df.date.apply(lambda d: datetime.strptime(d, "%Y-%m-%d"))
df.index = df.date

보시다시피 df.date = df.date.apply(lambda d: datetime.strptime (d, "%Y-%m-%d")) 여기에서 문자열이 아닌 정수로 작동하지 않습니다. 나는 datetime.date.fromtimestamp를 사용해야 한다고 생각하지만 이것을 df.date 전체에 적용하는 방법을 잘 모르겠습니다.

감사합니다.


4 개의 답변 중 1 개의 답변만 추려냄.

다음은 epoch 이후 초단위로 보일 것입니다.

In [20]: df = DataFrame(data['values'])

In [21]: df.columns = ["date","price"]

In [22]: df
Out[22]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 358 entries, 0 to 357
Data columns (total 2 columns):
date     358  non-null values
price    358  non-null values
dtypes: float64(1), int64(1)

In [23]: df.head()
Out[23]: 
         date  price
0  1349720105  12.08
1  1349806505  12.35
2  1349892905  12.15
3  1349979305  12.19
4  1350065705  12.15
In [25]: df['date'] = pd.to_datetime(df['date'],unit='s')

In [26]: df.head()
Out[26]: 
                 date  price
0 2012-10-08 18:15:05  12.08
1 2012-10-09 18:15:05  12.35
2 2012-10-10 18:15:05  12.15
3 2012-10-11 18:15:05  12.19
4 2012-10-12 18:15:05  12.15

In [27]: df.dtypes
Out[27]: 
date     datetime64[ns]
price           float64
dtype: object
반응형
반응형

참고주소 : https://stackoverflow.com/questions/49643225/whats-the-difference-between-reshape-and-view-in-pytorch

pytorch에서 reshape와 view 간에 차이점은 무엇입니까?

numpy에서 배열을 reshape 하기 위해 ndarray.reshape()를 사용합니다.

저는 pytorch에서 사람들이 torch.view(...)를 같은 목적으로 사용한다는 것을 알았지만 동시에 torch.reshape(...)도 존재한다는 점입니다.

그리하여 저는 이들의 차이점이 무엇인지와 이들 중 하나를 언제 사용해야 되는지 궁금합니다.


5개 답변 중 1개

torch.viewtorch.reshape가 모두 텐서의 모양을 변경하는 데 사용되지만 여기에 두 가지 차이점이 있습니다.

  1. 이름에서 알 수 있듯이 torch.view는 원래 텐서의 를 생성 할뿐입니다. 새 텐서는 항상 데이터를 원래 텐서와 공유합니다. 즉, 원래 텐서를 변경하면 재구성 된 텐서가 변경되고 그 반대도 마찬가지입니다.
>>> z = torch.zeros(3, 2)
>>> x = z.view(2, 3)
>>> z.fill_(1)
>>> x
tensor([[1., 1., 1.],
        [1., 1., 1.]])
  1. 새 텐서가 항상 원본과 데이터를 공유하도록 하기 위해torch.view는 두 텐서의 모양에 몇 가지 연속성 제약 조건을 적용합니다 docs. 종종 이것은 문제가 되지 않지만 때때로 torch.view는 두 텐서의 모양이 호환되는 경우에도 오류를 발생시킵니다. 여기에 유명한 반례가 있습니다.
>>> z = torch.zeros(3, 2)
>>> y = z.t()
>>> y.size()
torch.Size([2, 3])
>>> y.view(6)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: invalid argument 2: view size is not compatible with input tensor's
size and stride (at least one dimension spans across two contiguous subspaces).
Call .contiguous() before .view().
  1. torch.reshape는 연속성 제약을 부과하지 않지만 데이터 공유를 보장 하지도 않습니다. 새로운 텐서는 원래 텐서의 view 일 수도 있고, 완전히 새로운 텐서일 수도 있습니다.
>>> z = torch.zeros(3, 2)
>>> y = z.reshape(6)
>>> x = z.t().reshape(6)
>>> z.fill_(1)
tensor([[1., 1.],
        [1., 1.],
        [1., 1.]])
>>> y
tensor([1., 1., 1., 1., 1., 1.])
>>> x
tensor([0., 0., 0., 0., 0., 0.])

너무 길면 안 읽어도 됩니다 (TL;DR:)

텐서의 모양을 변경하려면 torch.reshape를 사용하십시오. 메모리 사용량도 염려하고 두 텐서가 동일한 데이터를 공유하도록 하려면 torch.view를 사용하세요.

반응형
반응형

출처 : https://stackabuse.com/unpacking-in-python-beyond-parallel-assignment/

파이썬으로 unpacking : 병렬 대입을 넘어서

소개

파이썬에서 unpacking은 하나의 대입 구문에서 변수들의 튜플(tuple) (또는 리스트(list))로 iterable한 할당을 포함하는 연산입니다. 반대로 packing 이라는 용어는 iterable unpacking 연산자 * 를 사용하여 단일 변수에서 여러 값을 수집할 때 사용할 수 있습니다.

역사적으로, 파이썬 개발자는 튜플(tuple) unpacking 같은 연산 종류를 일반적으로 참조해 왔습니다. 하지만, 파이썬 기능은 매우 유용하고 인기있는 것으로 밝여졌기 때문에 모든 종류의 iterable 들로 일반화되었습니다. 요즘에는 더 현대적이고 정확한 용어는 iterable unpacking 입니다.

이 튜토리얼에서 우리는 iterable unpacking이 무엇이고 우리의 코드를 가독성 있고 유지보수에 좋고 pythonic 하도록 하는 파이썬 특징에 어떻게 이득을 주는지 학습 하겠습니다.

추가적으로, 우리는 대입 연산, for 루프, 함수 정의와 함수 호출에서 iterable unpacking 특징을 사용하는 방법에 대한 몇 가지 실용적인 예시를 다룰 것입니다.

파이썬에서 packing과 unpacking

파이썬은 변수들의 튜플(tuple) ( 또는 리스트(list) ) 대입 연산 왼쪽에 나오는 것을 허용합니다. 튜플(tuple)의 각 변수는 오른쪽 부분에 iterable로부터 하나의 값 ( 또는 만약 * 연산자를 사용할 경우 그 이상)을 받을 수 있습니다.

역사적인 이유로 파이썬 개발자는 이를 tuple unpacking 이라 부르고는 했습니다. 하지만 이 특징은 모든 종류의 iterable로 일반화되고 부터 더 정확한 용어는 _iterable unpacking_이 되었고 이 튜토리얼에서 그렇게 부르는 것입니다.

Unpacking 연산은 우리의 코드를 더 가독성있고 우아하게 해주기 때문에 파이썬 개발자 사이에서 아주 유명해졌습니다. 파이썬에서 unpacking에 대해 더 살펴보고 이 특징이 우리의 코드를 어떻게 증진시키는지 살펴봅시다.

Unpacking Tuples

파이썬에서 우리는 대입 연산 왼쪽에 변수들의 튜플(tuple) 을 놓고 오른쪽 부분에 값들의 튜플(tuple) 을 놓습니다. 오른쪽의 값은 자동적으로 튜플(tuple)에서 그 위치에 따라서 왼쪽의 변수로 대입됩니다. 이는 파이썬에서 _tuple unpacking_으로 널리 알려져 있습니다. 다음 예제를 확인하세요.

>>> (a, b, c) = (1, 2, 3)
>>> a
1
>>> b
2
>>> c
3

우리가 대입 연산자 양쪽에 튜플을 놓았을 때, 튜플 unpacking 연산이 발생합니다. 오른쪽의 값은 각 튜플(tuple)에 상대적인 위치에 따라 왼쪽에 변수로 대입됩니다. 위에 예제에서 볼 수 있듯이, a1, b2, c는 3이 될 것입니다.

튜플(tuple) 객체를 생성하기 위해 우리는 괄호 () 의 쌍을 구분자로 사용할 필요가 없습니다. 이는 또한 튜플 unpacking으로 작동하며 다음 문법들은 똑같습니다.

>>> (a, b, c) = 1, 2, 3
>>> a, b, c = (1, 2, 3)
>>> a, b, c = 1, 2, 3

모든 변이는 파이썬 문법에서 유효하기 때문에 우리는 위에 것 중 상황에 맞춰 아무거나 사용할 수 있습니다. 논쟁의 여지가 있지만 마지막 문법은 파이썬에서 unpacking할 때 더 일반적으로 사용됩니다.

튜플 unpacking을 사용하여 변수로 값을 unpacking할 때, 튜플(tuple) 왼쪽에 변수의 수는 오른쪽 튜플(tuple)의 값의 수와 같아야 합니다. 그렇지 않으면 ValueError가 나오게 됩니다.

예를 들어 다음 코드에서 우리는 왼쪽에 2개 변수와 오른쪽에 3개의 값을 사용합니다. 이는 ValueError 예외를 발생하는데 우리에게 너무 많은 값을 unpacking 한다고 우리에게 이야기 합니다.

>>> a, b = 1, 2, 3
Traceback (most recent call last):
  ...
ValueError: too many values to unpack (expected 2)

참고 : 이에 대한 유일한 예외는 나중에 살펴 보겠지만 * 연산자를 사용하여 하나의 변수에 여러 값을 pack 하는 경우입니다.

반면에 값보다 더 많은 변수를 사용하면 ValueError가 발생하지만 이번에는 압축을 풀 값이 충분하지 않다는 메시지가 표시됩니다.

>>> a, b, c = 1, 2
Traceback (most recent call last):
  ...
ValueError: not enough values to unpack (expected 3, got 2)

튜플 unpacking 연산에서 다른 수의 변수와 값을 사용하면 ValueError가 발생합니다. 파이썬은 어떤 값이 어떤 변수에 들어가는 지 모호하지 않게 알아야 하기 때문에 그에 따라 할당을 수행할 수 있습니다.

Unpacking Iterables

튜플 unpacking 특징은 매우 인기가 많아서 iterable 객체와 함께 작동하도록 구문이 확장되었습니다. 유일한 요구 사항은 iterable이 수신 튜플 (또는 목록)의 변수당 정확히 하나의 item을 생성한다는 것입니다.

Python에서 iterable unpacking 작동 방식에 대한 다음 예제를 확인하십시오.

>>> # Unpacking strings
>>> a, b, c = '123'
>>> a
'1'
>>> b
'2'
>>> c
'3'
>>> # Unpacking lists
>>> a, b, c = [1, 2, 3]
>>> a
1
>>> b
2
>>> c
3
>>> # Unpacking generators
>>> gen = (i ** 2 for i in range(3))
>>> a, b, c = gen
>>> a
0
>>> b
1
>>> c
4
>>> # Unpacking dictionaries (keys, values, and items)
>>> my_dict = {'one': 1, 'two':2, 'three': 3}
>>> a, b, c = my_dict  # Unpack keys
>>> a
'one'
>>> b
'two'
>>> c
'three'
>>> a, b, c = my_dict.values()  # Unpack values
>>> a
1
>>> b
2
>>> c
3
>>> a, b, c = my_dict.items()  # Unpacking key-value pairs
>>> a
('one', 1)
>>> b
('two', 2)
>>> c
('three', 3)

파이썬에서 unpacking할 때 할당 연산자의 오른쪽에 모든 iterable을 사용할 수 있습니다. 왼쪽은 튜플(tuple)이나 변수 리스트(list)으로 채울 수 있습니다. 대입문의 오른쪽에 튜플(tuple)을 사용하는 다음 예제를 확인하십시오.

>>> [a, b, c] = 1, 2, 3
>>> a
1
>>> b
2
>>> c
3

range() iterator를 사용한다면 같은 방법으로 작동합니다.

>>> x, y, z = range(3)
>>> x
0
>>> y
1
>>> z
2

유효한 파이썬 구문일지라도 실제 코드에서는 일반적으로 사용되지 않으며 초보 파이썬 개발자에게는 약간 혼란스러울 수 있습니다.

마지막으로, unpacking 작업에서 set 객체를 사용할 수도 있습니다. 그러나 set는 순서가 지정되지 않은 컬렉션이므로 할당 순서가 일관성이 없고 미묘한 버그가 발생할 수 있습니다. 다음 예를 확인하십시오.

>>> a, b, c = {'a', 'b', 'c'}
>>> a
'c'
>>> b
'b'
>>> c
'a'

set을 unpacking 연산에서 사용한다면 대입문의 마지막 순서는 우리가 원하거나 기대했던 거와는 많이 다릅니다. 따라서 할당 순서가 중요하지 않은 경우가 아니면 unpacking 작업에서 set을 사용하지 않는 것이 가장 좋습니다.

* 연산자로 packing 하기

여기에서 * 연산자는 튜플 (또는 iterable) unpacking 연산으로 알려져 있습니다. 이 연산자는 단일 변수로 여러 값을 수집하거나 packing 할 수 있도록 unpacking 기능을 확장합니다. 다음 예제에서는 * 연산자를 사용하여 값의 튜플(tuple) 을 단일 변수로 pack 합니다.

>>> *a, = 1, 2
>>> a
[1, 2]

이 코드가 작동하려면 대입문에 왼쪽은 튜플(tuple) 또는 리스트(list)가 되어야 합니다. 그래서 마지막에 쉼표(콤마)를 사용하는 이유입니다. 이 튜플(tuple)은 우리가 필요한 만큼 많은 변수들을 담습니다. 하지만, 이는 하나의 별로 표시된 표현식만 포함할 수 있습니다.

위 코드의 *a 와 같이 유효한 파이썬 식별자와 함께 unpacking 연산자 *를 사용하여 별표 표현식을 만들 수 있습니다. 왼쪽 튜플(tuple)의 나머지 변수는 구체적인 값으로 채워야하기 때문에 필수 변수라고 합니다. 그렇지 않으면 오류가 발생합니다. 이것이 실제로 작동하는 방법은 다음과 같습니다.

마지막의 값들로 b를 packing 합니다.

>>> a, *b = 1, 2, 3
>>> a
1
>>> b
[2, 3]

시작 값들로 a를 packing 합니다.

>>> *a, b = 1, 2, 3
>>> a
[1, 2]
>>> b
3

bc가 필수 변수이기 때문에 하나의 값 a를 packing 합니다.

>>> *a, b, c = 1, 2, 3
>>> a
[1]
>>> b
2
>>> c
3
```python

`b`와`c`,`d`가 필수 변수이기 때문에 빈 값 `a`(`a`는 `[]`가 기본값)를 packing 합니다.

```python
>>> *a, b, c, d = 1, 2, 3
>>> a
[]
>>> b
1
>>> c
2
>>> d
3

필수 변수 (e)로 공급할 값이 없기 때문에, 오류가 발생합니다.

>>> *a, b, c, d, e = 1, 2, 3
 ...
ValueError: not enough values to unpack (expected at least 4, got 3)

* 연산자를 사용하여 변수에 값을 packing하면 list() 함수를 사용하지 않고 단일 변수에서 generator의 요소를 수집해야 할 때 편리합니다. 다음 예제에서는 * 연산자를 사용하여 generator 표현식의 요소와 range 객체를 개별 변수로 압축합니다.

>>> gen = (2 ** x for x in range(10))
>>> gen
<generator object <genexpr> at 0x7f44613ebcf0>
>>> *g, = gen
>>> g
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
>>> ran = range(10)
>>> *r, = ran
>>> r
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

이 예에서 * 연산자는 gen에 요소를 packing 하고 각각 gr을 만났습니다. 그 구문을 사용하면 range 객체, generator 표현식 또는 generator 함수에서 값 목록(list)을 만들기 위해 list()를 호출 할 필요가 없습니다.

할당의 왼쪽에 있는 변수 마지막에 쉼표를 추가하지 않고는 unpacking 연산자 *를 사용하여 여러 값을 하나의 변수로 packing 할 수 없습니다. 따라서 다음 코드는 작동하지 않습니다.

>>> *r = range(10)
  File "<input>", line 1
SyntaxError: starred assignment target must be in a list or tuple

* 연산자를 사용하여 여러 값을 단일 변수로 packing 경우 단일 튜플(tuple) 구문을 사용해야 합니다. 예를 들어, 위의 예제가 작동하도록 하려면 *r, = range(10) 에서와 같이 변수 r 뒤에 쉼표를 추가하면 됩니다.

실제로 Packing 과 Unpacking 사용하기

실제로 Packing 과 Unpacking 연산은 매우 유용합니다. 이는 코드를 깔끔하고 가독성있고 pythonic하게 만듧니다. 파이썬에서 packing과 unpacking의 몇가지 공통 사용 예시를 살펴봅시다.

병렬로 대입

파이썬에서 unpacking의 가장 일반적인 사용 사례 중 하나는 병렬 할당 입니다. 병렬 할당을 사용하면 반복 가능한 값을 하나의 우아한 문장으로 변수의 튜플(tuple) (또는 목록(list))에 할당 할 수 있습니다.

예를 들어 회사의 직원에 대한 데이터베이스가 있고 목록의 각 항목을 변수에 할당해야 한다고 가정해 보겠습니다. 파이썬에서 반복 가능한 unpacking이 작동하는 방식을 무시하면 다음과 같은 코드를 직접 작성할 수 있습니다.

>>> employee = ["John Doe", "40", "Software Engineer"]
>>> name = employee[0]
>>> age = employee[1]
>>> job = employee[2]
>>> name
'John Doe'
>>> age
'40'
>>> job
'Software Engineer'

이 코드는 작동하지만 index 처리는 서투르고 입력하기 어렵고 혼란스러울 수 있습니다. 더 깨끗하고 읽기 쉽고 pythonic한 해결책은 다음과 같이 코딩할 수 있습니다.

>>> name, age, job = ["John Doe", "40", "Software Engineer"]
>>> name
'John Doe'
>>> age
40
>>> job
'Software Engineer'

Python에서 unpacking를 사용하면 하나의 간단하고 우아한 문장으로 이전 예제의 문제를 해결할 수 있습니다. 이 작은 변경으로 인해 신규 개발자가 코드를 더 쉽게 읽고 이해할 수 있습니다.

변수간 값 교환

파이썬에서 unpacking의 또 다른 우아한 응용 프로그램은 임시 또는 보조 변수를 사용하지 않고 변수간에 값을 교환하는 것입니다. 예를 들어 두 변수 a와 b의 값을 바꿔야한다고 가정 해 보겠습니다. 이를 위해 기존 솔루션을 고수하고 임시 변수를 사용하여 다음과 같이 교환할 값을 저장할 수 있습니다.

>>> a = 100
>>> b = 200
>>> temp = a
>>> a = b
>>> b = temp
>>> a
200
>>> b
100

이 절차에는 세 단계와 새 임시 변수가 필요합니다. 파이썬에서 unpacking을 사용하면, 한 번의 간결한 단계로 동일한 결과를 얻을 수 있습니다.

>>> a = 100
>>> b = 200
>>> a, b = b, a
>>> a
200
>>> b
100

a, b = b, a에서 우리는 한 줄의 코드에서 ab에, ba에 재할당합니다. 이것은 훨씬 더 읽기 쉽고 간단합니다. 또한 이 기술을 사용하면 새 임시 변수가 필요하지 않습니다.

*로 여러개의 값 모으기

일부 알고리즘으로 작업할 때 추가 처리를 위해 반복 가능한 값 또는 시퀀스 값을 값 청크로 분할해야 하는 상황이 있을 수 있습니다. 다음 예는 이를 위해 리스트(list)slicing 연산을 사용하는 방법을 보여줍니다.

>>> seq = [1, 2, 3, 4]
>>> first, body, last = seq[0], seq[1:3], seq[-1]
>>> first, body, last
(1, [2, 3], 4)
>>> first
1
>>> body
[2, 3]
>>> last
4

이 코드는 우리가 예상 한대로 작동 하지만, index와 slice를 다루는 것은 초보자에게 약간 귀찮고 읽기 어렵고 혼란 스러울 수 있습니다. 또한 코드를 엄격하고 유지 관리하기 어렵게 만드는 단점도 있습니다. 이 상황에서 반복 가능한 unpacking 연산자 * 및 단일 변수에 여러 값을 pack하는 기능은 훌륭한 도구가 될 수 있습니다. 위 코드의 리팩토링한 내용을 확인하세요.

>>> seq = [1, 2, 3, 4]
>>> first, *body, last = seq
>>> first, body, last
(1, [2, 3], 4)
>>> first
1
>>> body
[2, 3]
>>> last
4

첫 번째 라인, *body, last = seq는 여기서 마법을 만듭니다. 반복 가능한 unpacking 연산자 *bodyseq 중간에 있는 요소들을 수집합니다. 이것은 우리의 코드를 더 읽기 쉽고, 유지 관리하고, 유연하게 만듭니다. 왜 더 유연할까요? 음, seq가 리스트의 길이를 변경하였고 여전히 body의 중간 요소를 수집해야 한다고 가정합니다. 이 경우 Python에서 unpacking을 사용하므로 코드가 작동하기 위해 변경할 필요가 없습니다. 이 예를 확인하십시오.

>>> seq = [1, 2, 3, 4, 5, 6]
>>> first, *body, last = seq
>>> first, body, last
(1, [2, 3, 4, 5], 6)

만약 파이썬에서 iterable unpacking 대신에 시퀀스 slicing을 사용 한다면, 우리는 새로운 값에 대한 정확하게 slice할 인덱스를 갱신해야 합니다.

하나의 변수에서 몇개의 값을 pack하는 * 연산의 사용은 파이썬이 각 값을 어떤 요소들에 모호하지 않게 할당하기 위해 다양하게 값을 설정하는데 적용될 수 있습니다. 다음 예를 살펴봅시다.

>>> *head, a, b = range(5)
>>> head, a, b
([0, 1, 2], 3, 4)
>>> a, *body, b = range(5)
>>> a, body, b
(0, [1, 2, 3], 4)
>>> a, b, *tail = range(5)
>>> a, b, tail
(0, 1, [2, 3, 4])

우리는 필요에 따라서 값을 모으기 위해 변수들의 tuple(튜플) (또는 list(리스트) )에서 * 위치를 이동할 수 있습니다. 유일한 조건은 파이썬이 각 값들을 어느 변수에 할당할 지 결정할 수 있다는 것입니다.

우리는 대입문에서 별 표기법을 하나를 초과하여 사용할 수 없다는 것이 중요합니다. 별 표기법을 하나를 초과할 경우 다음처럼 SyntaxError가 나오게 됩니다.

>>> *a, *b = range(5)
  File "<input>", line 1
SyntaxError: two starred expressions in assignment

할당 표현식에서 *를 두 개 이상 사용하면 별표 두 개가 있는 표현식이 발견되었음을 알려주는 SyntaxError가 발생합니다. 이것은 파이썬이 각 변수에 할당할 값 (또는 값)을 명확하게 결정할 수 없기 때문입니다.

*로 필요 없는 값 버리기

* 연산자의 또 다른 일반적인 사용 사례는 쓸모 없거나 불필요한 값을 삭제하기 위해 더미 변수 이름과 함께 사용하는 것입니다. 다음 예를 확인하십시오.

>>> a, b, *_ = 1, 2, 0, 0, 0, 0
>>> a
1
>>> b
2
>>> _
[0, 0, 0, 0]

이 사용 사례에 대한 보다 통찰력 있는 예를 들면 사용중인 파이썬 버전을 확인하는 데 필요한 스크립트를 개발하고 있다고 가정합니다. 이를 위해 sys.version_info 속성을 사용할 수 있습니다. 이 속성은 버전 번호의 5개 구성 요소인 major, minor, micro, releaselevelserial 을 포함하는 튜플을 반환 합니다. 그러나 스크립트가 작동하려면 major, minormicro 만 필요하므로 나머지는 삭제할 수 있습니다. 예를 들면 다음과 같습니다.

>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=8, micro=1, releaselevel='final', serial=0)
>>> mayor, minor, micro, *_ = sys.version_info
>>> mayor, minor, micro
(3, 8, 1)

이제 필요한 정보가 포함 된 세 가지 새로운 변수가 있습니다. 나머지 정보는 프로그램에서 무시할 수있는 더미 변수 _에 저장됩니다. 이것은 우리가 _에 저장된 정보를 사용하고 싶지 않거나 사용할 필요가 없다는 것을 신규 개발자에게 분명하게 할 수 있습니다. 이 문자는 명백한 의미가 없기 때문입니다.

참고: 기본적으로 밑줄 문자 _는 파이썬 인터프리터에서 대화형 세션에서 실행하는 명령문의 결과 값을 저장하는 데 사용됩니다. 따라서 이 컨텍스트에서 더미 변수를 식별하기 위해 이 문자를 사용하는 것은 모호할 수 있습니다.

함수로 튜플 리턴하기

Python 함수는 쉼표로 구분된 여러 값을 리턴할 수 있습니다. 괄호를 사용하지 않고 tuple(튜플) 객체를 정의할 수 있기 때문에 이런 종류의 연산은 tuple(튜플) 값을 리턴하는 것으로 해석될 수 있습니다. 여러 값을 반환하는 함수를 코딩하면 리턴된 값을 사용하여 iterable packing 및 unpacking 작업을 수행할 수 있습니다.

주어진 숫자의 정사각형과 정육면체를 계산하는 함수를 정의하는 다음 예제를 확인하십시오.

>>> def powers(number):
...     return number, number ** 2, number ** 3
...
>>> # Packing returned values in a tuple
>>> result = powers(2)
>>> result
(2, 4, 8)
>>> # Unpacking returned values to multiple variables
>>> number, square, cube = powers(2)
>>> number
2
>>> square
4
>>> cube
8
>>> *_, cube = powers(2)
>>> cube
8

쉼표로 구분된 값을 리턴하는 함수를 정의하면 이러한 값에 대해 packing 또는 unpacking 작업을 수행할 수 있습니다.

* 연산자로 iterable 병합

unpacking 연산자 *의 또 다른 흥미로운 사용 사례는 iterable을 최종 시퀀스로 병합하는 기능입니다. 이 기능은 list, 튜플 및 set에 대해 작동합니다. 다음 예를 살펴보십시오.

>>> my_tuple = (1, 2, 3)
>>> (0, *my_tuple, 4)
(0, 1, 2, 3, 4)
>>> my_list = [1, 2, 3]
>>> [0, *my_list, 4]
[0, 1, 2, 3, 4]
>>> my_set = {1, 2, 3}
>>> {0, *my_set, 4}
{0, 1, 2, 3, 4}
>>> [*my_set, *my_list, *my_tuple, *range(1, 4)]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> my_str = "123"
>>> [*my_set, *my_list, *my_tuple, *range(1, 4), *my_str]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, '1', '2', '3']

시퀀스를 정의할 때 iterable unpacking 연산자 *를 사용하여 하위 시퀀스 (또는 반복 가능)의 요소를 최종 시퀀스로 unpacking할 수 있습니다. 이렇게하면 append(), insert() 등과 같은 메서드를 호출하지 않고도 다른 기존 시퀀스에서 즉시 시퀀스를 만들 수 있습니다.

마지막 두 가지 예는 이것이 iterable을 연결하는 더 읽기 쉽고 효율적인 방법임을 보여줍니다. list (my_set) + my_list + list (my_tuple) + list (range (1, 4)) + list (my_str) 을 쓰는 대신 [* my_set, * my_list, * my_tuple, * range (1, 4), * my_str]로 작성할 수 있습니다.

** 연산자로 딕셔너리(dictionary) unpacking

파이썬에서 unpacking할 때, **dictionary unpacking 연산자라 부릅니다. 이 연산자의 사용은 PEP 448에 의해 확장되었습니다. 이제 함수 호출, comprehesion, generator 표현식, dictionary display에서 그것을 사용할 수 있습니다.

dictionary unpacking 연산자의 기본적인 사용 예시는 단일 표현식으로 여러 dictionary를 하나의 최종 dictionary로 병합 합니다. 이것이 어떻게 작동하는지 봅시다.

>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> letters = {"a": "A", "b": "B", "c": "C"}
>>> combination = {**numbers, **letters}
>>> combination
{'one': 1, 'two': 2, 'three': 3, 'a': 'A', 'b': 'B', 'c': 'C'}

dictionary display 내에서 dictionary unpacking 연산자를 사용하면 위의 코드에서 했던 것처럼 dictionary의 unpack하고 결합하여 원래 dictionary의 키-값 쌍을 포함하는 최종 dictionary를 만들 수 있습니다.

유의해야 할 중요한 점은 병합하려는 dictionary에 반복되거나 공통된 키가 있는 경우 맨 오른쪽 dictionary의 값이 맨 왼쪽 dictionary의 값을 재정의 한다는 것입니다. 예를 들면 다음과 같습니다.

>>> letters = {"a": "A", "b": "B", "c": "C"}
>>> vowels = {"a": "a", "e": "e", "i": "i", "o": "o", "u": "u"}
>>> {**letters, **vowels}
{'a': 'a', 'b': 'B', 'c': 'C', 'e': 'e', 'i': 'i', 'o': 'o', 'u': 'u'}

키가 두 dictionary 모두에 있기 때문에 가장 오른쪽에 있는 모음에서 값이 나옵니다. 이것은 파이썬이 왼쪽에서 오른쪽으로 키-값 쌍을 추가하기 시작하기 때문에 발생합니다. 프로세스에서 파이썬이 이미 종료된 키를 찾으면 인터프리터는 해당 키를 새 값으로 업데이트 합니다. 이것 이 위의 예에서 키 값이 소문자로 된 이유입니다.

For 루프에서 unpacking

우리는 for 루프에서 iterable unpacking을 사용할 수 있습니다. 우리가 for 루프를 실행할 때 루프는 각 iteration 에서 iterable의 하나의 아이템을 타겟 변수로 대입합니다. 대입할 아이템이 iterable이면 우리는 타겟 변수의 튜플을 사용할 수 있습니다. 루프는 타겟 변수의 튜플로 iterable을 unpack할 것입니다.

예를 들어, 다음과 같은 회사 판매 데이터가 포함된 파일이 있다고 가정해 보겠습니다.

Product Price Sold Units
Pencil 0.25 1500
Notebook 1.30 550
Eraser 0.75 1000
... ... ...

이 테이블에서 두 요소 튜플 리스트(list)를 작성할 수 있습니다. 각 튜플(tuple)에는 제품 이름, 가격 및 판매된 단위가 포함됩니다. 이 정보를 사용하여 각 제품의 수입을 계산하려고 합니다. 이를 위해 다음과 같은 for 루프를 사용할 수 있습니다.

>>> sales = [("Pencil", 0.22, 1500), ("Notebook", 1.30, 550), ("Eraser", 0.75, 1000)]
>>> for item in sales:
...     print(f"Income for {item[0]} is: {item[1] * item[2]}")
...
Income for Pencil is: 330.0
Income for Notebook is: 715.0
Income for Eraser is: 750.0

이 코드는 예상대로 작동합니다. 그러나 각 튜플(tuple)의 개별 요소에 액세스하기 위해 인덱스를 사용하고 있습니다. 이것은 초보 개발자가 읽고 이해하기 어려울 수 있습니다.

파이썬에서 unpacking를 사용하는 대체 가능한 구현을 살펴 보겠습니다.

>>> for product, price, sold_units in sales:
...     print(f"Income for {product} is: {price * sold_units}")
...
Income for Pencil is: 330.0
Income for Notebook is: 715.0
Income for Eraser is: 750.0

이제 for 루프에서 반복 가능한 unpacking을 사용하고 있습니다. 이것은 각 튜플(tuple)의 요소를 식별하기 위해 설명을 잘 하는 이름을 사용하기 때문에 코드를 더 읽기 쉽고 유지 관리하기 쉽게 만듭니다. 이 작은 변화를 통해 초보 개발자는 코드의 논리를 빠르게 이해할 수 있습니다.

for 루프에서 * 연산자를 사용하여 단일 대상 변수에 여러 항목을 packing할 수도 있습니다.

>>> for first, *rest in [(1, 2, 3), (4, 5, 6, 7)]:
...     print("First:", first)
...     print("Rest:", rest)
...
First: 1
Rest: [2, 3]
First: 4
Rest: [5, 6, 7]

for 루프에서 우리는 먼저 각 시퀀스의 첫번째 요소를 잡습니다. 그런 다음 * 연산자는 대상 변수 나머지에서 값의 리스트(list)를 포착합니다.

마지막으로 타겟 변수의 구조는 iterable의 구조와 일치해야합니다. 그렇지 않으면 오류가 발생합니다. 다음 예를 살펴보십시오.

>>> data = [((1, 2), 2), ((2, 3), 3)]
>>> for (a, b), c in data:
...     print(a, b, c)
...
1 2 2
2 3 3
>>> for a, b, c in data:
...     print(a, b, c)
...
Traceback (most recent call last):
  ...
ValueError: not enough values to unpack (expected 3, got 2)

첫 번째 루프에서 타겟 변수 (a, b), c의 구조는 반복 가능한 항목의 구조 ((1, 2), 2)와 일치합니다. 이 경우 루프가 예상대로 작동합니다. 반대로 두 번째 루프는 반복 가능한 항목의 구조와 일치하지 않는 대상 변수의 구조를 사용하므로 루프가 실패하고 ValueError가 발생합니다.

함수에서 Packing 과 Unpacking

우리는 함수를 정의하고 호출할 때 파이썬의 packing과 unpacking을 사용할 수 있습니다. 이는 매우 유용하며 파이썬에서 packing 과 unpacking의 유명한 사용 사례입니다.

이 섹션에서 우리는 함수 정의 또는 함수 호출에서 파이썬 함수에서 packing과 unpacking을 사용하는 방법의 기초에 대해 알아볼 것입니다.

Note: For a more insightful and detailed material on these topics, check out Variable-Length Arguments in Python with _args and *_kwargs.

참고: 이 주제에 대한보다 통찰력 있고 자세한 자료는 *args**kwargs를 사용하는 Python의 가변 길이 인수를 확인하십시오.

***로 함수 정의하기

파이썬 함수의 서명에 대해 *** 연산자를 사용할 수 있습니다. 이렇게하면 가변 개수의 위치 인수 (*) 또는 가변 개수의 키워드 인수 또는 둘 다를 사용하여 함수를 호출 할 수 있습니다. 다음 함수를 고려해 봅시다.

>>> def func(required, *args, **kwargs):
...     print(required)
...     print(args)
...     print(kwargs)
...
>>> func("Welcome to...", 1, 2, 3, site='StackAbuse.com')
Welcome to...
(1, 2, 3)
{'site': 'StackAbuse.com'}

위의 함수에는 required 라는 인수가 하나 이상 필요합니다. 가변 개수의 위치 및 키워드 인수도 허용할 수 있습니다. 이 경우 * 연산자는 args라는 튜플에서 추가 위치 인수를 수집하거나 pack하고 ** 연산자는 kwargs라는 dictionary에서 추가 키워드 인수를 수집하거나 pack합니다. argskwargs는 모두 선택 사항이며 기본값은 각각 (){}입니다.

argskwargs라는 이름은 파이썬 커뮤니티에서 널리 사용되지만 이러한 기술이 작동하는 데 필요한 것은 아닙니다. 구문에는 * 또는 ** 뒤에 유효한 식별자가 필요합니다. 따라서 이러한 인수에 의미있는 이름을 부여할 수 있다면 그렇게 하십시오. 그것은 확실히 코드의 가독성을 향상시킬 것입니다.

***로 함수 호출하기

함수를 호출할 때 *** 연산자를 사용하여 인수 모음을 각각 별도의 위치 또는 키워드 인수로 unpack할 수 있습니다. 이것은 함수의 시그니처에서 ***를 사용하는 것과 반대입니다. 서명에서 연산자는 하나의 식별자에 가변 개수의 인수를 수집하거나 pack하는 것을 의미합니다. 호출에서 iterable을 여러 인수로 unpack하는 것을 의미합니다.

이것이 작동하는 기본적인 예시입니다.

>>> def func(welcome, to, site):
...     print(welcome, to, site)
...
>>> func(*["Welcome", "to"], **{"site": 'StackAbuse.com'})
Welcome to StackAbuse.com

여기서 * 연산자는 ["Welcome", "to"]와 같은 시퀀스를 위치 인수로 unpack합니다. 마찬가지로 ** 연산자는 사전을 unpack된 dictionary의 키와 이름이 일치하는 인수로 unpack 합니다.

이 기술과 이전 섹션에서 다룬 기술을 결합하여 매우 유연한 함수를 작성할 수도 있습니다. 예를 들면 다음과 같습니다.

>>> def func(required, *args, **kwargs):
...     print(required)
...     print(args)
...     print(kwargs)
...
>>> func("Welcome to...", *(1, 2, 3), **{"site": 'StackAbuse.com'})
Welcome to...
(1, 2, 3)
{'site': 'StackAbuse.com'}

파이썬 함수를 정의하고 호출 할 때 *** 연산자를 사용하면 추가 기능을 제공하고 더 유연하고 강력하게 만들 수 있습니다.

결론

iterable unpacking는 파이썬에서 매우 유용하고 인기있는 기능으로 밝혀졌습니다. 이 기능을 사용하면 iterable을 여러 변수로 unpack할 수 있습니다. 반면에 packing은 unpacking 연산자 *를 사용하여 여러 값을 하나의 변수로 포착하는 것으로 구성됩니다.

이 튜토리얼에서 우리는 파이썬에서 반복 가능한 unpacking을 사용하여 더 읽기 쉽고, 유지 보수가 가능하며, 파이썬 코드를 작성하는 방법을 배웠습니다.

이 지식을 바탕으로 이제 파이썬에서 iterabble unpacking을 사용하여 병렬 할당 및 변수 간 값 교환과 같은 일반적인 문제를 해결할 수 있습니다. 또한 for 루프, 함수 호출, 함수 정의와 같은 다른 구조에서도 이 파이썬 기능을 사용할 수 있습니다.

반응형

+ Recent posts