반응형

출처

https://stackoverflow.com/questions/24718697/pyspark-drop-rows

PySpark에서 행 버리기

PySpark에서 RDD로부터 행을 어떻게 버릴 수 있을까요? 특별히 첫 번째 행에 제 데이터 셋에 컬럼명이 포함되어 있기 때문입니다. API를 자세히 살펴보면 이 작업을 쉽게 하는 방법을 찾을 수 없는 거 같습니다. 당연히 저는 Bash / HDFS를 통해 이를 할 수 있지만 PySpark로만 이를 할 수 있는 방법을 알고 싶습니다.


6개 답변 중 1개만 추려냄

제가 아는 한 이를 하는 '쉬운' 방법은 없습니다.

그래서 트릭을 수행해야 합니다.

val header = data.first
val rows = data.filter(line => line != header)
반응형
반응형

출처

https://www.baeldung.com/linux/redirect-output-of-running-process

이미 실행중인 프로세스의 출력을 redirecting 하기

1. 소개

Linux에서 작업할 때 redirections을 사용하는 것은 매우 일반적입니다. 예를 들어, 프로그램을 실행할 수 있고 실행시 생성되는 출력을 침묵시킬 수 있습니다. 그러나 bash는 프로세스가 실행되면 출력을 redirection 하는 직접적인 방법을 제공하지 않습니다. 따라서 이 글에서는 실행중인 프로세스의 출력을 리디렉션하거나 복사하는 다양한 방법에 대해 알아 봅니다. 예를 들어 프로그램을 실행할 때 출력을 리디렉션하는 것을 잊은 경우 유용 할 수 있습니다.

이를 위해 첫 번째는 gdb를 사용하고 다른 하나는 strace를 사용하며 마지막으로 세 번째는 screen을 사용하는 세 가지 방법을 살펴 보겠습니다. 세 번째 접근 방식은 약간 다릅니다.

2. 출력을 redirect하기 위해 gdb 사용하기

gdb_는 리눅스에서 코드 디버깅을 위한 강력한 도구입니다. 그리고 우리는 실행 중인 프로세스에서 코드를 실행하기 위해 그것을 사용할 수 있습니다. 이 경우, *_우리는 실행 중인 프로세스로 _gdb_에 접근(attach)하여 출력을 redirect하기 위해 *gdb 사용할 것이며 작업을 마쳤을 때 실행중인 프로세서로부터 분리(detach)할 것입니다.**

출력을 redirect하기 위해 우리가 할 수 있는 방법은 현재 파일 descriptor를 닫고 그것을 새로운 출력을 가리키도록 다시 여는 것입니다. 우리는 opendup2 함수를 사용하여 이를 할 것입니다.

유닉스 시스템에는 2개의 기본 출력이 있는데, 표준출력*과 *표준에러 입니다. _표준출력_은 파일 descriptor 1과 관련되어 있고 _표준에러_는 파일 descriptor 2와 관련되어 있습니다. 예를 들어, 표준 출력을 redirect하기 원하면 우리는 파일 descriptor 1에서 활동할 필요가 있습니다.

우리는 PID 14560인 프로세스의 출력을 redirect하기 원한다고 가정합시다. 우리는 그 PID로 _gdb_를 접근함으로써 시작해야 합니다.

$ gdb -p 14560

프로세스로 접근했을 때 우리는 파일 descriptor 1을 /tmp/process_stdout로 redirect할 수 있습니다.

(gdb) p dup2(open("/tmp/process_stdout", 1089, 0777), 1)

우리는 숫자 1089를 사용했는데 이는 _O_WRONY | O_CREAT | O_APPEND_를 표현하기 때문이라는 것을 참고하세요.

우리는 표준 출력도 같은 방법으로 파일 descriptor 2를 사용함으로써 정확하게 redirect할 수 있습니다.

(gdb) p dup2(open("/tmp/process_stderr", 1089, 0777), 2)

이 시점에서 출력이 redirect 되었습니다. 그러나 프로세스가 중지되고 _gdb_가 그 프로세스에 접근(attach)합니다.

더 이상 gdb가 필요하지 않으므로 프로세스에서 분리하고 _gdb_를 종료할 수 있습니다. 이렇게하면 프로세스가 계속 실행됩니다.

(gdb) q

또는 /dev/null로 redirect 하여 출력을 침묵시킬 수 있습니다.

(gdb) p dup2(open("/dev/null"), 1)

우리는 모든 gdb 명령을 "명령 파일"로 작성할 수 있고 파라미터 -x 를 사용하여 그것을 실행할 수 있습니다.
gdb_redirect 라 불리는 파일을 생성합시다.

p dup2(open("/tmp/process_stdout", 1089, 0777), 1)
p dup2(open("/tmp/process_stderr", 1089, 0777), 2)
q

다음 우리의 파일 _gdb_redirect_를 사용하여 _gdb_를 실행하면 됩니다.

$ gdb -p 14560 -x gdb_redirect

3. 모든 쓰기 호출을 검사하는 strace 사용하기

우리는 시스템 콜(호출)을 검사하는 strace를 사용할 수도 있습니다. 이 방법은 원래 출력을 중단하지 않습니다. 대신 다른 위치로 복사합니다.
PID 14560의 표준 오류로 쓰는 모든 쓰기를 검사합시다.

$ strace -etrace=write -s 100000 -p 14560 2>&1 | grep --line-buffered '^write(2,'
write(2, "\r", 1)                       = 1
write(2, "17243001856 bytes (17 GB, 16 GiB) copied, 1185 s, 14.6 MB/s", 59) = 59
write(2, "\r", 1)                       = 1
write(2, "17249965568 bytes (17 GB, 16 GiB) copied, 1186 s, 14.5 MB/s", 59) = 59

이 파라미터로 strace*는 *쓰기 호출과 최대 문자열 크기를 10만으로 설정하여 PID 14560에 접근합니다. 그리고 우리는 파일 descriptor 2로 쓰는 것만 출력하기 위해 grep 으로 사용합니다.
우리는 /tmp/process_stderr라 불리는 파일로 이를 redirect할 수 있습니다.

$ strace -etrace=write -s 100000 -p 14560 2>&1 | grep --line-buffered '^write(2,' > /tmp/process_stderr

만약 strace 출력 포멧을 좋아하지 않는다면 문자열만 출력하기 위해 sed를 사용할 수 있습니다.

$ strace -etrace=write -s 100000 -p 14560 2>&1 | sed -n -r 's/^write\(2,\s*"(.+)",\s*[[:digit:]]+\)\s*=\s*[[:digit:]]+$/\1/p'
\r
25754656256 bytes (26 GB, 24 GiB) copied, 1710 s, 15.1 MB/s
\r
25761747456 bytes (26 GB, 24 GiB) copied, 1711 s, 15.1 MB/s

또한 ** strace는 16진수와 파일 descriptor로 쓰여진 아스키코드로 출력할 수 있습니다.** 우리는 이를 -ewrite=fd 옵션을 사용하여 할 수 있습니다.

$ strace -ewrite=2 -etrace=write -p 14560 2>&1 | grep  --line-buffered '^ |'
 | 00000  0d                                                .                |
 | 00000  33 33 30 31 32 30 32 37  39 30 34 20 62 79 74 65  33012027904 byte |
 | 00010  73 20 28 33 33 20 47 42  2c 20 33 31 20 47 69 42  s (33 GB, 31 GiB |
 | 00020  29 20 63 6f 70 69 65 64  2c 20 32 31 36 32 20 73  ) copied, 2162 s |
 | 00030  2c 20 31 35 2e 33 20 4d  42 2f 73                 , 15.3 MB/s      |
 | 00000  0d                                                .                |
 | 00000  33 33 30 31 39 36 32 31  38 38 38 20 62 79 74 65  33019621888 byte |
 | 00010  73 20 28 33 33 20 47 42  2c 20 33 31 20 47 69 42  s (33 GB, 31 GiB |
 | 00020  29 20 63 6f 70 69 65 64  2c 20 32 31 36 33 20 73  ) copied, 2163 s |
 | 00030  2c 20 31 35 2e 33 20 4d  42 2f 73                 , 15.3 MB/s      |

4. screen을 사용하여 파일에 출력 쓰기

프로세스가 스크린 세션 내에서 실행 중인 경우 현재 창을 파일에 기록할 수 있습니다. strace와 마찬가지로 출력을 대체하지 않고 대신 복사합니다. 그러나 임의의 파일 descriptor를 복사 할 수 없습니다. 화면 창에 기록 중인 내용만 복사할 수 있습니다.

이를 위해 screen 명령 로그 또는 핫키 C-a H를 사용합니다. 그러면 화면 창 번호가 n 인 screenlog.n이라는 파일에 로깅이 활성화됩니다. 그런 다음 화면에서 분리하여 프로세스를 실행하면 screenlog.n에서 출력을 볼 수 있습니다. log 명령이나 핫키를 다시 사용하여 언제든지 로그인을 중지 할 수 있습니다.

또한 logfile 명령을 사용하여 출력을 작성할 위치를 지정할 수 있습니다.

:logfile process_output

그런 다음 log를 실행하면 출력이 screenlog.n 대신 process_output에 표시됩니다.

동영상 링크

5. 결론

이 글에서는 이미 실행중인 프로세스의 출력을 redirect 하는 세 가지 방법을 살펴 보았습니다.

먼저 gdb를 사용하여 현재 출력을 새 출력으로 대체했습니다. 그런 다음 *strace로 *쓰기 위한 모든 호출을 가로 채서 원하는 출력을 다른 위치에 복사했습니다. 마지막으로 창을 파일에 기록하는 screen을 활용했습니다.

반응형
반응형

출처

https://stackoverflow.com/questions/32029647/warning-feof-expects-parameter-1-to-be-resource-boolean-given-in-volume1-we

경고 : feof()는 첫 번째 매개 변수가 리소스가 될 것으로 예상합니다. 하지만은 /volume1/web/comment.php 62행에 boolean 타입입니다.

저는 youtube와 다른 사이트의 도움으로 코드를 학습하기 시작했습니다만, 문제에 직면하였습니다. 여기에 제 코드입니다.

<form action="" method="post" id="c">
  <label> Name: <br><input type="text" name="name" size="36"></label><br></br>
  <label> Message: <br><textarea cols="35" rows="5" name="mes"></textarea></label><br></br>
  <input type="submit" name="submit" value="Submit" class="texty" >
</form>

<?php
$post = $_POST["post"];
$name = $_POST["name"];
$text = $_POST["mes"];

if ($post) {

    #WRITE DOWN COMMENTS#

    $write = fopen("c.txt", "a+");
    fwrite($write, "<u><b> $name</b></u><br>$text<br></br>");
    fclose($write);

    #DISPLAY COMMENTS#

    $read = fopen("c.txt", "r+t");
    echo "All comments:<br>";

    while (!feof($read)) {   #this line does the error#
        echo fread($read, 1024);
    }
    fclose($read);
}
else{
    #DISPLAY COMMENTS#

    $read = fopen("c.txt", "r+t");
    echo "All comments:<br>";

    while (!feof($read)) {
        echo fread($read, 1024);
    }
    fclose($read);
}
?>

그래서 2개의 파일이 있는데, 하나는 당신이 코멘트를 입력하고 그것을 게시하는 곳이고, 다른 하나는 당신이 입력한 것을 붙여 넣은 다음 페이지에 다시 출력되는 .txt 파일입니다. 파일 권한에 문제가 있는 것 같습니다. "r"에만 입력하면 오류가 발생하지 않지만 게시하려는 내용이 저장되지 않기 때문입니다. 감사합니다. 읽고 답장해 주셔서 감사합니다.


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

fopen은 파일을 열 수 없는 경우 부울(FALSE) 타입을 반환합니다. feof에 전달하기 전에 $read가 false가 아닌지 확인해야 합니다. 그리고 왜 파일을 읽을 수 없는지 알아 내십시오.

if ($read) {
    ...

권한으로 인해 또는 파일 자체를 찾을 수 없는 경우 파일을 읽을 수 없습니다. c.txt를 참조하고 있지만 PHP가 있는 동일한 디렉토리에 있습니까? getcwd를 사용하여 PHP가 어떤 디렉토리에 있는지 확인할 수 있습니다.

echo getcwd ()

또한 form 핸들러는 $_POST[ 'post']에 값이 있지만 해당 이름이 form에서 사용되지 않는 경우에만 쓰기 분기문에 들어갑니다 (적어도 표시된 예제에서는 사용되지 않았습니다).

반응형
반응형

참고주소 : 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://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work

어떻게 자바의 'for each' 루프가 작동하나요?

다음을 고려할 때

List<String> someList = new ArrayList<String>();
// "monkey", "donkey", "skeleton key"를 someList에 추가
for (String item : someList) {
    System.out.println(item);
}

for each 문법을 사용하지 않고 for 루프처럼 똑같이 하려면 어떻게 해야할까요?


28개 답변 중 1개

for (Iterator<String> i = someIterable.iterator(); i.hasNext();) {
    String item = i.next();
    System.out.println(item);
}

루프에서 i.remove();를 사용할 필요가 있거나, 다른 방법으로 실제 iterator를 접근(수정)한다면 구문을 실제 iterator만 추론(읽기) 때문에 for ( : )를 사용할 수 없습니다.

Denis Bueno가 언급했듯이 이 코드는 Iterable 인터페이스를 구현하는 모든 개체에서 작동합니다.

또한 for (:) 관용구의 오른쪽이 Iterable 객체가 아닌 array(배열)인 경우 내부 코드는 int 인덱스 카운터를 사용하고 대신 array.length를 확인합니다. Java 언어 스펙을 참조하십시오.

반응형
반응형

출처 : 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 루프, 함수 호출, 함수 정의와 같은 다른 구조에서도 이 파이썬 기능을 사용할 수 있습니다.

반응형
반응형

출처 : https://stackoverflow.com/questions/2500436/how-does-cat-eof-work-in-bash

bash에서 어떻게 "cat << EOF"가 작동합니까?

저는 프로그램(psql)에 여러줄의 입력을 넣기(enter) 위해 스크립트를 작성할 필요가 있습니다.

구글링을 좀 한 결과 다음 문법이 작동함을 발견하였습니다.

cat << EOF | psql ---params
BEGIN;

`pg_dump ----something`

update table .... statement ...;

END;
EOF

이는 (BEGIN;부터 END;까지) 여러줄 문자열을 생성하고 psql의 입력으로 pipe 전달을 합니다.

하지만 저는 어떻게/왜 작동하는지 모르겠습니다. 아무나 설명해주실 수 있을까요?

저는 주로 cat << EOF를 참조하고 있습니다. 저는 >는 파일로 출력하기, >> 파일로 추가(append)하기, <는 파일로부터 읽기라는 것을 알고 있습니다.

<<는 정확히 무엇을 합니까?

그리고 이에 대한 man page가 있나요?


9 Answers

이는 표준입력으로 문자열을 제공하는 heredoc 포멧으로 불립니다. 더 자세한 내용은 https://en.wikipedia.org/wiki/Here_document#Unix_shells 를 보시면 됩니다.


man bash에서

Here Documents

이러한 유형의 redirection은 특정 단어만 포함된 행(뒤에 공백 없음)이 표시될 때까지 쉘이 현재 소스에서 입력을 읽도록 지시합니다.

그 지점까지 읽은 모든 행은 명령의 표준 입력으로 사용됩니다.

여기 문서의 형식은 다음과 같습니다.

          <<[-]word
                  here-document
         delimiter

매개 변수 확장, 명령 대체, 산술 확장 또는 경로 이름 확장은 단어(word)에서 수행되지 않습니다. 단어(word)의 문자가 인용된 경우 구분(delimeter) 기호는 단어에서 따옴표 부호를 제거한 결과이며 here-document의 행은 확장되지 않습니다. 단어(word)가 따옴표가 없을 경우 here-document의 모든 행은 매개 변수 확장, 명령 대체 및 산술 확장의 대상이 됩니다. 후자의 경우 문자 시퀀스 \ 은 무시되며 인용하는 데 \, $ 및 ` 문자를 사용해야 합니다.

redirection 연산자가 <<- 이면 모든 탭이 먼저오는 문자가 입력 줄과 구분(delimiter) 기호를 포함하는 줄에서 제거됩니다. 이를 통해 쉘 스크립트 내의 here-document를 자연스럽게 들여 쓰기 할 수 있습니다.

반응형
반응형

참고주소 : https://stackoverflow.com/questions/2235276/how-to-run-junit-test-cases-from-the-command-line

명령어 라인에서 JUnit test case를 실행하는 방법

저는 명령어 라인에서 JUnit test case를 실행하고 싶습니다. 어떻게 이를 할 수 있을까요?


10개 답변 중 1개만 추려냄

JUnit 5.X에서는

java -jar junit-platform-console-standalone-<version>.jar <Options>

https://stackoverflow.com/a/52373592/1431016 에서 간단한 요약을 찾을 수 있고 https://junit.org/junit5/docs/current/user-guide/#running-tests-console-launcher 에서 전체 세부사항을 볼 수 있습니다.

JUnit 4.X에서는

java -cp .:/usr/share/java/junit.jar org.junit.runner.JUnitCore [test class name]

JUnit 3.X를 사용하신다면 클래스 이름이 다릅니다.

java -cp .:/usr/share/java/junit.jar junit.textui.TestRunner [test class name]

윈도우즈에서는 세미콜론으로 유닉스/리눅스에서는 콜론으로 classpath로 클래스 파일을 디렉터리나 JAR를 더 추가하고 싶을 수 있습니다. 환경에 따라 다릅니다.

편집: 저는 예제로 현재 디렉터리를 추가하였습니다. 환경과 당신이 응용프로그램을 어떻게 빌드하느냐(bin/ 또는 build/ 또는 my_application.jar 등)에 의존적입니다. Java 6+는 classpath에 glob을 지원합니다. 다음처럼 할 수 있습니다.

java -cp lib/*.jar:/usr/share/java/junit.jar ...

도음이 되길 바랍니다. 테스트를 작성하세요! :-)

반응형
반응형

참고주소 : https://stackoverflow.com/questions/33907835/docker-error-cannot-delete-docker-container-conflict-unable-to-remove-reposito

Docker 오류 docker container를 삭제할 수 없음, 충돌 : 저장소 참조를 제거할 수 없음

저는 Docker에서 container를 삭제하고 싶지만, 지우기를 원할 때 오류가 발생합니다.

container를 삭제하기 전에 다음 단계에서 존재하는 container의 목록을 확인하세요.

sts@Yudi:~/docker$ sudo docker ps -as

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES                  SIZE
78479ffeba5c        ubuntu              "/bin/bash"         42 hours ago        Exited (0) 42 hours ago                       sharp_wescoff          81 B (virtual 187.7 MB)
0bd2b54678c7        training/webapp     "python app.py"     5 days ago          Exited (0) 5 days ago                         backstabbing_ritchie   0 B (virtual 323.7 MB)
0adbc74a3803        training/webapp     "python app.py"     5 days ago          Exited (143) 5 days ago                       drunk_feynman          0 B (virtual 323.7 MB)

저는 이 목록 중 하나 "training / webapp" 을 지우고 싶지만 다음 오류가 발생합니다.

sts@Yudi:~/docker$ sudo docker rmi training/webapp
Error response from daemon: conflict: unable to remove repository reference "training/webapp" (must force) - container 0bd2b54678c7 is using its referenced image 54bb4e8718e8
Error: failed to remove images: [training/webapp]

이미지에 container가 실행 중인건가요?

도와주세요.


9개 답변 중 1개만 추려냄

docker image와 docker container에는 차이가 있습니다. 이 질문을 확인하세요.

즉, container는 이미지의 실행 가능한 인스턴스입니다. 이미지로부터 실행중인 컨테이너가 있다면 지울 수 없는 이유가 됩니다. 당신은 먼저 container를 지워야 합니다.

docker ps -a                # container 목록 (과 그들이 어떤 이미지로 만들어 졌는지 확인)

docker images               # image 목록 

docker rm <container_id>    # 멈춰진 container를 삭제

docker rm -f <container_id> # 실행 중인 container를 (SIGKILL을 사용하여) 강제로 삭제

docker rmi <image_id>       # image 삭제
                            # 이미지의 인스턴스가 실행중이면 실패. 예. container

docker rmi -f <image_id>    # 여러 저장소에서 참조될 지라도 image를 강제로 삭제.
                            # 예. 여러개의 names/tags인 같은 image id
                            # image를 참조하는 docker container가 있으면 여전히 실패.

Docker 1.13+ 업데이트 (2017년 1월 부터)

Docker 1.13에서는 모든 명령이 상호 작용하는 논리적 객체 아래에 위치하도록 다시 그룹화했습니다.

기본적으로, 위의 명령은 다음처럼 다시 작성될 수 있습니다.

docker container ls -a
docker image ls
docker container rm <container_id>
docker image rm <image_id>

만약 모두 삭제하고 싶으면 다음을 사용할 수 있습니다.

docker system prune -a

주의! 이는 다음을 삭제합니다.

  • 모든 멈춘 container
  • 하나 이상의 사용되지 않는 모든 네트워크
  • 모든 사용되지 않는 image
  • 모든 build 된 캐시
반응형

'Docker' 카테고리의 다른 글

CentOS6 Docker설치  (0) 2019.04.14
반응형

참고주소 : https://stackoverflow.com/questions/8318236/regex-pattern-for-hhmmss-time-string

HH:MM:SS 시간 문자열에 대한 정규식 패턴

저는 hh:mm:ss 문자열을 파싱하고 싶습니다. 간단한 방법은 2:3:24 또는 02:03:24 문자열이 기대되는 ([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)입니다.

저는 더 단계를 진행하고 싶고 다음과 같은 경우에 유효성을 통과하는지 알고 싶습니다.

  1. 56만 입력할 경우, 통과해야하며, 56은 56초 [SS]로 고려될 수 있습니다.
  2. 2:3 또는 02:03 또는 02:3 또는 2:03을 입력해도 통과해야 합니다. 2분 3초 [MM:SS]의 의미입니다.
  3. 20:30:12를 입력하면 20시 30분 12초 [HH:MM:SS]라는 의미로 통과합니다.
  4. 78:12를 입력하면 78분은 틀렸기 때문에 통과할 수 없습니다.

기본적으로 ":"이 발견되면, ":" 앞에 숫자는 MM으로, ":" 뒤의 숫자는 SS로 간주합니다. 두 개의 ":"이 발견되면 HH:MM:SS로 갅주합니다.

전 이 패턴을 생각해 냈습니다.

(^([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)$)|(^([0-5]?\d):([0-5]?\d)$)|(^[0-5]?\d$)

잘 작동하는 것 같습니다. 저는 이 작업을 할 수 있는 다른 더 간단한 정규식을 알고 싶습니다.


2개 답변 중 1개

^(?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)?([0-5]?\d)$

설명:

^                   # 문자열의 시작
(?:                 # 맞는가 시도...
 (?:                #  맞는가 시도...
  ([01]?\d|2[0-3]): #   HH:
 )?                 #  (옵션으로).
 ([0-5]?\d):        #  MM: (필수)
)?                  # (그룹 전체가 옵션, 그래서 HH:MM: 또는 MM: 또는 없음의 의미)
([0-5]?\d)          # SS (필수)
$                   # 문자열의 끝
반응형

+ Recent posts