파이썬의 숨겨진 기능


1419

파이썬 프로그래밍 언어의 덜 알려졌지만 유용한 기능은 무엇입니까?

  • 파이썬 코어에 대한 답변을 제한하십시오.
  • 답변 당 하나의 기능.
  • 문서에 대한 링크가 아니라 기능에 대한 예와 간단한 설명을 제공하십시오.
  • 제목을 첫 번째 줄로 사용하여 기능에 레이블을 지정하십시오.

답변에 대한 빠른 링크 :

답변:


740

체이닝 비교 연산자 :

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

경우 당신이 그것을하고있어 생각 1 < x으로 나오고있는 True다음과 비교되지 True < 10도이다, True무슨 정말 아니다 그 다음 더, 정말로 번역하는 것 (. 마지막 예제 참조) 1 < x and x < 10, 그리고 x < 10 and 10 < x * 10 and x*10 < 100, 미만 입력하고 각각 용어는 한 번만 평가됩니다.


121
매우 도움이됩니다. 모든 언어에 대해 표준이어야합니다. 슬프게도 그렇지 않습니다.
stalepretzel

8
거짓을 반환하는 몇 가지 예를 추가해야합니다. 예 : >>> 10 <x <20 False
ShoeLace

19
이것은 다른 비교 연산자에도 적용됩니다. 따라서 (5의 [5]가 참) 인 코드가 거짓 인 이유에 사람들이 놀라는 경우가 있습니다 (그러나 처음부터 부울을 명시 적으로 테스트하는 것은 비현실적입니다).
Miles

19
좋지만 'in'과 '='와 같은 동등한 우선 순위를 조심하십시오. 'B의 A == C의 D'는 '(B의 A)와 (B == C)와 (C의 D)'를 뜻하며 예상치 못한 결과 일 수 있습니다.
Charles Merriam

15
Azafe : Lisp의 비교는 자연스럽게 이런 식으로 작동합니다. 해석 할 다른 (합리적인) 방법이 없기 때문에 특별한 경우는 아닙니다 (< 1 x 10). cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/… 와 같은 단일 인수에도 적용 할 수 있습니다 (= 10).
Ken

512

파이썬 정규식 구문 분석 트리를 가져 와서 정규식을 디버깅하십시오.

정규 표현식은 파이썬의 훌륭한 기능이지만, 디버깅은 어려울 수 있으며 정규 표현식을 잘못 사용하는 것은 너무 쉽습니다.

다행히도 파이썬은 문서화되지 않은 실험적인 숨겨진 플래그 re.DEBUG(실제로 128)를 로 전달하여 정규식 구문 분석 트리를 인쇄 할 수 있습니다 re.compile.

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

구문을 이해하면 오류를 발견 할 수 있습니다. 거기서 우리는 내가 탈출하는 것을 잊었다는 것을 알 수 있습니다 [].[/font] .

물론 주석이 달린 정규 표현식과 같이 원하는 플래그와 결합 할 수 있습니다.

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

3
정규 표현식을 사용하여 HTML을 구문 분석하는 것을 제외하고는 느리고 고통 스럽습니다. 내장 'html'파서 모듈조차도 정규 작업을 사용하여 작업을 수행하지 않습니다. html 모듈이 마음에 들지 않으면 휠을 다시 만들지 않고도 작업을 수행하는 XML / HTML 파서 모듈이 많이 있습니다.
BatchyX

출력 구문에 대한 문서 링크가 좋습니다.
Personman

1
이것은 실험적인 것이 아니라 파이썬의 공식적인 부분이어야합니다 ... RegEx는 항상 까다 롭고 일어나고있는 것을 추적 할 수있는 것이 정말 도움이됩니다.
Cahit

460

낱낱이 세다

iterable을 열거 형으로 감싸면 인덱스와 함께 항목이 생성됩니다.

예를 들면 다음과 같습니다.


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

참고 문헌 :


56
파이썬 목록에 대한 자습서에서 일상적으로 다루지 않는 것에 놀랐습니다.
Draemon

45
그리고이 모든 시간 동안 나는이 방법으로 코딩했습니다 : i in range (len (a)) : ... 그리고 a [i]를 사용하여 현재 항목을 가져옵니다.
페르난도 마틴

4
@ 베리 Tsakala : 내 지식으로는, 더 이상 사용되지 않습니다.
JAB

23
이런 쓰레기는 굉장하다. xrange (len (a))에서 i의 경우 : 항상 가장 좋아하는 파이썬 관용구였습니다.
Personman

15
열거는 0이 아닌 임의의 인덱스에서 시작할 수 있습니다. 예 : 'i의 경우, enumerate ( list , start = 1)의 항목 : print i, item'은 0이 아닌 1부터 열거를 시작합니다.
dmitry_romanov

419

생성기 객체 생성

당신이 쓰는 경우

x=(n for n in foo if bar(n))

생성기를 꺼내 x에 할당 할 수 있습니다. 이제는 할 수 있음을 의미합니다

for n in x:

이것의 장점은 중간 저장소가 필요하지 않다는 것입니다.

x = [n for n in foo if bar(n)]

경우에 따라 속도가 크게 향상 될 수 있습니다.

생성기 끝에 많은 if 문을 추가하여 기본적으로 중첩 된 for 루프를 복제 할 수 있습니다.

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

중첩 목록 이해도 사용할 수 있습니다.
shapr

54
특히 주목할 것은 메모리 오버 헤드 절약입니다. 값은 주문형으로 계산되므로 목록 이해의 전체 결과가 메모리에 표시되지 않습니다. 나중에 목록 이해의 일부만 반복하는 경우에 특히 바람직합니다.
2009 년

19
이것은 특히 "숨겨진"imo는 아니지만 생성기 객체를 되 감을 수는 없지만 목록을 여러 번 반복 할 수 있다는 사실에 주목할 가치가 있습니다.
16:26에

13
발전기의 "되감기 없음"기능은 약간의 혼란을 야기 할 수 있습니다. 특히 디버깅을 위해 생성기의 내용을 인쇄 한 다음 나중에이를 사용하여 데이터를 처리하면 작동하지 않습니다. 데이터가 생성되어 print ()에 의해 소비 된 다음 일반 처리에 사용할 수 없습니다. 이것은 이해력이 완전히 메모리에 저장되어 있기 때문에 목록 이해에는 적용되지 않습니다.
johntellsall

4
비슷한 (중복?) 답변 : stackoverflow.com/questions/101268/hidden-features-of-python/… 그러나 여기에 링크 된 답변은 발전기의 힘에 대한 정말 좋은 프레젠테이션을 언급합니다. 당신은 정말로 그것을 확인해야합니다.
Denilson Sá Maia

353

iter ()는 호출 가능한 인수를 취할 수 있습니다

예를 들어 :

def seek_next_line(f):
    for c in iter(lambda: f.read(1),'\n'):
        pass

iter(callable, until_value)함수 는 반환 callable될 때까지 반복적으로 호출 하고 결과를 산출합니다 until_value.


파이썬 초보자에게는 lambda키워드가 왜 필요한지 설명해 주 시겠습니까?
SiegeX

람다가없는 @SiegeX, iter 함수에 전달되기 전에 f.read (1)이 평가 (문자열 반환)됩니다. 대신 람다는 익명 함수를 만들어 iter에게 전달합니다.
jmilloy

339

변경 가능한 기본 인수에주의하십시오

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

대신 "제공되지 않음"을 나타내는 센티넬 값을 사용하고 기본값으로 변경하려는 변수로 대체해야합니다.

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

39
그것은 확실히 더 불쾌한 숨겨진 기능 중 하나입니다. 나는 때때로 그것에 부딪쳤다.
Torsten Marek

77
기본 인수가 함수의 속성 인 튜플에 있다는 것을 알았을 때 이것을 이해하기가 훨씬 쉽다는 것을 알았습니다 foo.func_defaults. 튜플 인 것은 불변입니다.
Robert Rossney 2009

2
@grayger : def 문이 실행될 때 인수는 인터프리터에 의해 평가됩니다. 이것은 코드 객체 (함수 모음)에 이름을 생성 (또는 리 바인드)합니다. 그러나 기본 인수는 정의시 오브젝트로 인스턴스화됩니다. 이것은 기본 객체의 모든 시간에 해당되지만 객체가 변경 가능한 경우에만 (시각적 의미가 드러남) 중요합니다. 함수의 클로저에서 기본 인수 이름을 다시 바인딩하는 방법은 없지만 호출에 대해 재정의되거나 전체 함수를 재정의 할 수는 있습니다).
Jim Dennis

3
@Robert 물론 튜플 인수는 변경할 수 없지만 가리키는 객체는 반드시 불변 일 필요는 없습니다.
poolie

16
x = x 또는 []와 같이 초기화를 조금 더 짧게 만드는 하나의 빠른 해킹. 2 줄 if 문 대신 사용할 수 있습니다.
dave mankoff

317

생성기 함수로 값 보내기 . 예를 들어이 기능이있는 경우 :

def mygen():
    """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None: 
            a = f  #store the new value

당신은 할 수 있습니다 :

>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7

동의했다. 이것을 파이썬의 숨겨진 기능에 대한 불쾌한 예라고 생각하자 :)
Rafał Dowgird

89
다른 언어에서는이 마법 장치를 "가변"이라고합니다.
finnw 2016

5
코 루틴은 코 루틴이어야하고 제너레이터도 혼합되지 않아야합니다. : 여기에 대한 메가 큰 링크 및 이야기와 예 dabeaz.com/coroutines
u0b34a0f6ae

31
@finnw :이 예제는 변수와 비슷한 것을 구현합니다. 그러나이 기능은 변수와 달리 다른 많은 방법으로 사용될 수 있습니다. 비슷한 의미론이 객체 ( 특히 Python의 호출 메소드를 묵시하는 클래스)를 사용하여 구현 될 수 있다는 것도 분명해야합니다 .
Jim Dennis

4
이것은 코 루틴을 본 적이없는 사람들에게는 너무나 사소한 예입니다. 합계 변수 오버플로의 위험없이 실행 평균을 구현하는 예가 좋습니다.
Prashant Kumar

313

공백을 사용하여 범위를 표시하지 않으려면 다음을 실행하여 C 스타일 {}을 사용할 수 있습니다.

from __future__ import braces

122
그것은 악하다. :)
Jason Baker

37
>>> from __future__ import braces File "<stdin>", line 1 SyntaxError : not a chance : P
Benjamin W. Smith

40
신성 모독이야!
Berk D. Demir

335
여기에 구문상의 실수가있을 수 있다고 생각합니다. "from __past__ import braces" 가 아니어야 합니까?
Bill K

47
에서 __cruft__ 수입 중괄호
필립 B 올덤

305

슬라이스 연산자의 단계 인수. 예를 들면 다음과 같습니다.

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

특별한 경우 x[::-1]는 'x reversed'에 대한 유용한 관용구입니다.

>>> a[::-1]
[5,4,3,2,1]

31
내 의견으로는 reversed () 함수가 훨씬 명확합니다. >>> list (reversed (range (4))) [3, 2, 1, 0]
Christian Oudard

3
"this ia string"[::-1]을 더 좋은 방법으로 쓰는 방법? 뒤집어도 도움이되지 않는 것 같습니다
Berry Tsakala 2016 년

24
reversed ()의 문제점은 반복자를 리턴한다는 것입니다. 따라서 반전 된 시퀀스의 유형 (튜플, 문자열, 목록, 유니 코드, 사용자 유형 ...)을 유지하려면 다시 변환하는 추가 단계가 필요합니다. .
Rafał Dowgird 2016 년

6
def reverse_string (string) : return string [::-1]
pi.

4
@pi reverse_string을 정의 할만큼 충분히 알고 있다면 코드에 [::-1]을 남겨두고 그 의미와 느낌에 익숙 할 수 있다고 생각합니다.
physicsmichael

289

데코레이터

데코레이터 사용하면 기능을 추가하고 인수 또는 결과 등을 수정할 수있는 다른 함수로 함수 또는 메소드를 래핑 할 수 있습니다. "at"기호 (@)로 시작하여 데코레이터를 함수 정의보다 한 줄 위에 작성합니다.

예는 print_args데코레이터를 호출하기 전에 데코 레이팅 된 함수의 인수를 인쇄 하는 데코레이터를 보여줍니다 .

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

54
데코레이터를 정의 할 때 @decorator로 데코레이터를 장식하는 것이 좋습니다. 내부 검사를 할 때 함수 서명을 유지하는 데코레이터를 만듭니다. 자세한 정보는 여기 : phyast.pitt.edu/~micheles/python/documentation.html
sirwart

45
이 기능은 어떻게 숨겨져 있습니까?
Vetle

50
글쎄, 그것은 대부분의 간단한 파이썬 튜토리얼에는 없지만 파이썬 사용을 시작한 후 오랜 시간 동안 우연히 발견되었습니다. 이것이 바로 다른 주요 게시물과 거의 같은 숨겨진 기능이라고 부르는 것입니다.
DzinX

16
다시 말해,이 질문들은 "파이썬 프로그래밍 언어의 덜 알려졌지만 유용한 기능"을 요구한다. '알려지지는 않지만 유용한 기능'을 어떻게 측정합니까? 이러한 응답 중 숨겨진 기능은 무엇입니까?
Johnd

4
@vetler 여기서 대부분은 "숨겨지지"않습니다.
Humphrey Bogart

288

for ... else 구문 ( http://docs.python.org/ref/for.html 참조 )

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

"else"블록은 일반적으로 중단이 호출되지 않는 한 for 루프의 끝에서 실행됩니다.

위 코드는 다음과 같이 에뮬레이트 할 수 있습니다.

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")

218
for / else 구문이 어색하다고 생각합니다. 루프의 본문이 실행되지 않으면 else 절이 실행되는 것처럼 느껴집니다.
codeape

14
아 그거 본 적이 없어! 그러나 나는 그것이 약간의 오해라고 말해야합니다. break가 절대로 그렇지 않은 경우에만 else 블록이 실행될 것으로 예상하는 사람은 누구입니까? 나는 codeape에 동의합니다 : 다른 foos에 입력 된 것처럼 보입니다.
Daren Thomas

52
키워드는 다른 키워드가 아닌 마지막에 있어야합니다.
Jiaaro

21
마지막으로 스위트는 항상 해당 스위트가 항상 실행되는 방식으로 사용됩니다.

7
반드시 '그렇지 않아야'합니다. 루프가 실행되지 않았을 때 'then'또는 무언가가 발생하고 'else'일 수 있습니다.
Tor Valamo

258

2.5 이후로 dicts에는 __missing__누락 된 항목에 대해 호출 되는 특수 메소드 가 있습니다.

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

collections호출 된 dict 하위 클래스도 defaultdict거의 동일하지만 기존 항목이 아닌 인수를 사용하지 않고 함수를 호출합니다.

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

이러한 dict을 정규 dict로 변환하여 그러한 서브 클래스를 기대하지 않는 함수로 전달하는 것이 좋습니다. 많은 코드 d[a_key]가 KeyErrors를 사용 하고 포착하여 dict에 새 항목을 추가하는 항목이 있는지 확인합니다.


10
setdefault를 선호합니다. m = {}; m.setdefault ( 'foo', 1)
grayger '03

22
@grayger는 이것을 의미했습니다 m={}; m.setdefault('foo', []).append(1).
Cristian Ciupitu

1
그러나 defaultdict를 전달하는 것이 매우 편리한 경우가 있습니다. 이 함수는 예를 들어 값을 반복 할 수 있으며 기본값은 빈 목록이므로 추가 코드없이 정의되지 않은 키에 작동합니다.
Marian

3
defaultdict는 기본 객체를 생성하지 않기 때문에,을 setDefault보다는 어떤 상황에서는 더 하지 않으면 키가 없습니다. setdefault는 누락 여부에 관계없이 작성합니다. 기본 객체가 생성하는 데 비용이 많이 드는 경우 성능이 저하 될 수 있습니다. 모든 setdefault 호출을 변경하여 하나의 프로그램에서 적절한 속도를 얻었습니다.
Whatang

2
defaultdictsetdefault다른 경우 보다 방법 보다 강력합니다 . 예를 들어, 반대를위한 dd = collections.defaultdict(int) ... dd[k] += 1d.setdefault(k, 0) += 1.
Mike Graham

247

전체 가치 교환

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

과제의 오른쪽은 새로운 튜플을 생성하는 표현식입니다. 과제의 좌측 바로 해당 이름 (참조되지 않은) 튜플을 언팩 a하고b 합니다.

할당 한 후, 새로운 튜플을 참조 해제하고 가비지 컬렉션 대상으로 표시하고 값에 바인딩 ab 교환되었다.

데이터 구조 에 관한 파이썬 튜토리얼 섹션에서 언급했듯이 ,

다중 할당은 실제로 튜플 패킹과 시퀀스 언 패킹의 조합 일뿐입니다.


1
이것이 전통적인 방법보다 더 많은 실제 메모리를 사용합니까? 하나의 스왑 변수 대신 튜플을 만들고 있기 때문에 추측합니다.
Nathan

75
더 많은 메모리를 사용하지 않습니다. 적은 양을 사용합니다. 방금 두 가지 방식으로 작성하고 바이트 코드를 디 컴파일했습니다. 컴파일러는 원하는대로 최적화합니다. dis 결과는 변수를 설정 한 다음 ROT_TWOing을 설정하는 것으로 나타났습니다. ROT_TWO는 '두 개의 최상위 스택 변수 교체'를 의미합니다.
royal

5
또한 실수로 파이썬의 또 다른 멋진 기능을 지적합니다. 즉, 쉼표로 구분하여 항목의 튜플을 암시 적으로 만들 수 있다는 것입니다.
asmeurer

3
Dana the Sane : Python의 대입은 표현식이 아닌 명령문이므로 =가 우선 순위가 높은 경우 표현식이 유효하지 않습니다 (즉, a, (b = b), a로 해석 됨).
hbn

5
이것은 내가 읽은 가장 숨겨진 기능입니다. 멋지지만 모든 Python 자습서에서 명시 적으로 설명했습니다.
Thiago Chaves 2016 년

235

읽을 수있는 정규식

파이썬에서는 정규 표현식을 여러 줄로 나누고 일치하는 이름을 지정하고 주석을 삽입 할 수 있습니다.

자세한 구문 예제 ( Dive에서 Python으로 ) :

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

명명 일치 예 ( Regular Expression HOWTO )

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

re.VERBOSE문자열 리터럴 연결 덕분에 정규 표현식을 자세하게 작성할 수도 있습니다 .

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

7
파이썬 기능을 고려할 것인지 모르겠지만 대부분의 RE 엔진에는 자세한 옵션이 있습니다.
Jeremy Banks

18
예,하지만 grep이나 대부분의 편집자에서는 할 수 없기 때문에 많은 사람들이 그것이 있는지 알지 못합니다. 다른 언어가 동등한 기능을 가지고 있다고해서 파이썬의 유용하고 거의 알려진 기능은 아닙니다.
Mark Baker

7
최적화 된 정규 표현식이 많은 대규모 프로젝트 (읽기 : 기계에는 적합하지만 인간에게는 적합하지 않음)에서 글 머리 기호를 물었고 모든 구문을 자세한 구문으로 변환했습니다. 이제 새로운 개발자를 프로젝트에 소개하는 것이 훨씬 쉽습니다. 이제부터는 모든 프로젝트에 자세한 RE를 적용합니다.
Berk D. Demir

차라리 수백 = "(CM | CD | D? C {0,3})"# 900 (CM), 400 (CD) 등입니다. 언어에는 이미 이름을 지정할 수있는 방법이 있습니다. 주석을 추가하고 문자열을 결합하는 방법. 언어가 이미 완벽하게 잘하는 일에 왜 특수 라이브러리 구문을 사용합니까? 그것은 Perlis의 Epigram 9와 직접 대항하는 것 같습니다.
Ken

3
@Ken : 정규식이 항상 소스에 직접있는 것은 아니며 설정이나 구성 파일에서 읽을 수 있습니다. 주석이나 추가 공백 (가독성을 위해)을 허용하면 큰 도움이 될 수 있습니다.

222

함수 인자 풀기

*and를 사용하여 목록 또는 사전을 함수 인수로 압축 해제 할 수 있습니다 **.

예를 들면 다음과 같습니다.

def draw_point(x, y):
    # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

목록, 튜플 및 dicts가 컨테이너로 널리 사용되므로 매우 유용한 바로 가기입니다.


27
*는 표시 연산자라고도합니다.
Gabriel

3
이 기능이 마음에 들지만 pylint는 슬프게도 아닙니다.
Stephen Paulger

5
pylint의 조언은 법률이 아닙니다. 다른 방법으로 apply (callable, arg_seq, arg_map)는 2.3부터 사용되지 않습니다.
Yann Vernier

1
pylint의 조언은 법이 아닐 수도 있지만 좋은 조언입니다. 이와 같은 것들에 지나치게 탐닉하는 코드를 디버깅하는 것은 순수한 지옥입니다. 원래 포스터에서 언급했듯이 유용한 바로 가기 입니다.
앤드류

2
나는 이것을 코드에서 한 번 사용하는 것을 보았고 그것이 무엇을했는지 궁금해했다. 불행히도 "Python **"을 검색하기는 어렵습니다
Fraser Graham

205

ROT13은 코드 파일 맨 위에서 올바른 코딩 선언을 사용할 때 소스 코드에 유효한 인코딩입니다.

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

10
큰! 시도 : 바이트 문자열은 문자 그대로되지만 유니 코드 문자열을 디코딩하는 방법을 공지 사항cevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
불행히도 그것은 py3k에서 제거되었습니다
mykhal

9
바이러스 백신을 우회하는 데 좋습니다.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
그것은 인코딩과 관련이 없으며 웨일스 어로 작성된 Python입니다. :-P
Olivier Verdier

33
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
Manuel Ferreria

183

완전히 역동적 인 방식으로 새로운 유형 만들기

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

정확히 같은

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

아마도 가장 유용한 것은 아니지만 알아두면 좋을 것입니다.

편집 : 새로운 유형의 고정 이름 NewType은와 정확히 동일해야합니다.class 명령문 합니다.

편집 : 기능을보다 정확하게 설명하기 위해 제목을 조정했습니다.


8
이 유용성, 예를 들어, JIT의으로 ORMs에 대한 많은 잠재력을 가지고
마크시다에게

8
동적 입력을 기반으로 HTML 양식 클래스를 생성하는 데 사용합니다. 아주 좋아요!
pi.

15
참고 : 모든 클래스는 런타임에 작성됩니다. 따라서 조건부 또는 함수 내에서 'class'문을 사용할 수 있습니다 (클로저 역할을하는 클래스 또는 클래스 패밀리를 작성하는 데 매우 유용함). '유형'이 가져 오는 개선점은 동적으로 생성 된 속성 세트 (또는 기준)를 깔끔하게 정의 할 수있는 기능입니다.
spookylukey

1
type ( '', (object,), { 'x': 'blah'})와 같은 빈 문자열을 사용하여 익명 형식을 만들 수도 있습니다.
bluehavana

3
코드 삽입에 매우 유용 할 수 있습니다.
Avihu Turzion

179

컨텍스트 관리자 및 " with"문

에 도입 PEP (343) 하는 컨텍스트 매니저는 문 제품군에 대한 런타임 컨텍스트 역할을하는 객체입니다.

이 기능은 새로운 키워드를 사용하므로 점진적으로 도입됩니다. __future__지시문을 통해 Python 2.5에서 사용할 수 있습니다 . Python 2.6 이상 (Python 3 포함)에는 기본적으로 사용 가능합니다.

내가 사용하고 문 "과" 내가 여기에, 매우 유용한 구조의 빠른 데모입니다 생각하기 때문에 많은 :

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

여기서 뒤에서 일어나는 일은 "with"문 이 파일 객체 의 특수 __enter____exit__메소드를 호출한다는 것입니다. __exit__with 문에서 예외가 발생하면 예외 세부 사항도 전달되어 예외 처리가 가능합니다.

이 특별한 경우에 당신을 위해하는 일은 with정상적으로 발생하는지 또는 예외가 발생했는지 여부에 관계없이 실행이 제품군 범위를 벗어날 때 파일이 닫히도록 보장한다는 것입니다 . 기본적으로 일반적인 예외 처리 코드를 추상화하는 방법입니다.

이것에 대한 다른 일반적인 사용 사례에는 스레드 및 데이터베이스 트랜잭션 잠금이 포함됩니다.


3
나는 미래 에서 무언가를 가져온 코드 검토를 승인하지 않을 입니다. 이 기능은 유용한 것보다 더 귀엽고 일반적으로 파이썬 초보자를 혼란스럽게 만듭니다.
유료 머저리

6
그렇습니다. 중첩 된 스코프 및 생성기와 같은 "귀여운"기능은 자신이하는 일을 아는 사람들에게 더 좋습니다. 그리고 미래 버전의 Python과 호환되기를 원하는 사람. 중첩 된 스코프 및 생성기의 경우 Python의 "미래 버전"은 각각 2.2 및 2.5를 의미합니다. with 문에서 파이썬의 "미래 버전"은 2.6을 의미합니다.
Chris B.

10
말할 필요도 없지만 python v2.6 +에서는 더 이상 미래 에서 가져올 필요가 없습니다 . with는 이제 최고급 키워드입니다.
fitzgeraldsteele

25
2.7에서 당신은 여러 가지를 가질 수 있습니다 withs:) with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson

5
@Austin 나는 그 구문을 2.7에서 작동시킬 수 없었다. 그러나 이것은 효과가 있었다 : with open('filea') as filea, open('fileb') as fileb: ...
wim

168

사전에는 get () 메소드가 있습니다.

사전에는 'get ()'메소드가 있습니다. d [ 'key']를하고 key가 없으면 예외가 발생합니다. d.get ( 'key')를 수행하면 'key'가 없으면 None을 반환합니다. 두 번째 인수를 추가하여 None 대신 해당 항목을 다시 가져올 수 있습니다 (예 : d.get ( 'key', 0)).

숫자 추가와 같은 일에 좋습니다.

sum[value] = sum.get(value, 0) + 1


39
또한 setdefault 메소드를 확인하십시오.
Daren Thomas

27
또한 checks collections.defaultdict 클래스입니다.
jfs

8
Python 2.7 이상 또는 3.1 이상을 사용하는 경우 콜렉션 모듈에서 Counter 클래스를 확인하십시오. docs.python.org/library/collections.html#collections.Counter
Elias

오 사람, 내가 해왔 던 모든 시간 get(key, None). None기본적으로 제공된 아이디어는 없었습니다 .
Jordan Reiter

152

설명자

그것들은 모든 핵심 파이썬 기능의 마술입니다.

점으로 구분 된 액세스를 사용하여 멤버 (예 : xy)를 조회하면 Python은 먼저 인스턴스 사전에서 멤버를 찾습니다. 찾을 수 없으면 클래스 사전에서 찾습니다. 클래스 사전에서 그것을 발견하고 객체가 설명자 프로토콜을 구현하는 대신 반환하지 않고 파이썬이 실행합니다. 디스크립터가 구현하는 모든 클래스 __get__, __set__또는 __delete__방법.

디스크립터를 사용하여 고유 한 (읽기 전용) 버전의 속성을 구현하는 방법은 다음과 같습니다.

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

내장 속성 ()과 같이 사용합니다.

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

설명자는 Python에서 속성, 바인딩 된 메서드, 정적 메서드, 클래스 메서드 및 슬롯 등을 구현하는 데 사용됩니다. 그것들을 이해하면 이전에 파이썬 '질투'처럼 보이는 많은 것들이 왜 그런지 쉽게 알 수 있습니다.

Raymond Hettinger는 저보다 더 잘 설명 하는 훌륭한 자습서를 제공 합니다.


이것은 데코레이터의 복제품입니다. ( stackoverflow.com/questions/101268/… )
gecco

2
아니요, 데코레이터와 설명자는 완전히 다릅니다. 예제 코드에서는 설명자 데코레이터를 만들고 있습니다. :)
Nick Johnson

1
이를 수행하는 다른 방법은 람다를 사용하는 것입니다.foo = property(lambda self: self.__foo)
Pete Peterson

1
@PetePeterson 예, 그러나 property그 자체는 설명 자로 구현되어 있습니다.
닉 존슨

142

조건부 할당

x = 3 if (y == 1) else 2

"y가 1이면 3을 x에 할당하고, 그렇지 않으면 2를 x에 할당"과 같은 소리를냅니다. 파렌은 필요하지 않지만 가독성을 좋아합니다. 더 복잡한 것이 있으면 체인을 연결할 수도 있습니다.

x = 3 if (y == 1) else 2 if (y == -1) else 1

특정 시점에 있지만 너무 멀리갑니다.

if ... else를 어떤 식으로도 사용할 수 있습니다. 예를 들면 다음과 같습니다.

(func1 if y == 1 else func2)(arg1, arg2) 

여기서 y가 1이면 func1이 호출되고 그렇지 않으면 func2가 호출됩니다. 두 경우 모두 해당 함수는 인수 arg1 및 arg2와 함께 호출됩니다.

마찬가지로 다음 사항도 유효합니다.

x = (class1 if y == 1 else class2)(arg1, arg2)

여기서 class1과 class2는 두 개의 클래스입니다.


29
과제는 특별한 부분이 아닙니다. 다음과 같이 쉽게 할 수 있습니다 : else 3 if (y == 1) else 2
Brian

25
그 대체 방법은 내가 난독 화 된 파이썬을 처음 본 것입니다.
Craig McQueen

3
Kylebrooks :이 경우 부울 연산자는 단락되지 않습니다. bool (3) == False 인 경우에만 2를 평가합니다.
RoadieRich

15
이 역전 스타일의 코딩은 나를 혼란스럽게합니다. 같은 x = ((y == 1) ? 3 : 2)날 수 있습니다 더 의미
mpen

13
나는 C 스타일의 삼항 연산자가 항상 나를 혼란스럽게 생각하는 @Mark의 반대라고 생각합니다. 오른쪽 또는 중간은 잘못된 조건에서 평가되는 것입니까? 나는 파이썬의 삼항 구문을 선호합니다.
Jeffrey Harris

141

Doctest : 문서화와 단위 테스트를 동시에 수행합니다.

파이썬 문서에서 추출한 예 :

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

6
독신 테스트는 확실히 멋지지만, 예외를 제기해야하는 것을 테스트하기 위해 입력해야하는 모든 균열을 정말로 싫어합니다
TM.

60
Doctest는 과대 평가되어 문서를 오염시킵니다. setUp ()없이 독립형 함수를 얼마나 자주 테스트합니까?
유료 괴상한

2
누가 doctest에서 설정할 수 없다고 말합니까? 컨텍스트를 생성하고 locals()doctest에서 다음을 반환하는 함수를 작성 하십시오. do locals().update(setUp())= D
Jiaaro

12
독립형 함수에 설정이 필요한 경우 관련이없는 항목에서 분리하거나 클래스에 넣을 가능성이 높습니다. 그러면 클래스 doctest 네임 스페이스는 클래스 메소드 doctests에서 재사용 될 수 있으므로 setUp과 비슷하며 DRY와 읽기만 가능합니다.
Andy Mikhaylenko

4
"독립형 함수를 얼마나 자주 테스트합니까?"-많음. 외관을 결정할 때 doctest가 종종 디자인 프로세스에서 자연스럽게 나타납니다.
Gregg Lind

138

명명 된 서식

%-포맷팅은 사전을 취합니다 (% i / % s 등의 유효성 검사도 적용됨).

>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.

>>> foo, bar = 'question', 123

>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.

그리고 locals () 또한 사전이기 때문에이를 dict로 전달하고 지역 변수에서 % -substitions를 가질 수 있습니다. 나는 이것이 눈살을 찌푸리게 생각하지만 일을 단순화합니다 ..

새로운 스타일 형식

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

60
단계적으로 중단되고 결국 문자열의 format () 메소드로 대체됩니다.
Constantin

3
그들은 단지 컨텍스트에 대한 변수 이름없이 형식 문자열을 참조하는 경향이 명명 된 서식은 번역자에 매우 유용합니다
pixelbeat

2
python 3.0.1에서 작동하는 것으로 보입니다 (인쇄 호출 주위에 괄호를 추가해야 함).
Pasi Savolainen

9
해시 , 응? 어디에서 왔는지 봅니다
shylent

11
% s 형식화가 단계적으로 종료되지 않습니다. str.format ()은 확실히 더 파이썬 적이지만, 간단한 문자열 교체에 대해서는 실제로 10 배 느립니다. 내 생각에 % s 형식은 여전히 ​​모범 사례입니다.
Kenneth Reitz

132

더 많은 파이썬 모듈 (특히 타사 모듈)을 추가하기 위해 대부분의 사람들은 PYTHONPATH 환경 변수를 사용하거나 사이트 패키지 디렉토리에 심볼릭 링크 또는 디렉토리를 추가합니다. 다른 방법은 * .pth 파일을 사용하는 것입니다. 공식 파이썬 문서의 설명은 다음과 같습니다.

"python의 검색 경로를 수정하는 가장 편리한 방법은 경로 구성 파일을 이미 Python 경로에있는 디렉토리, 일반적으로 ... / site-packages / 디렉토리에 추가하는 것입니다. 경로 구성 파일의 확장자는 .pth입니다. , 각 행에는 sys.path에 추가 될 단일 경로가 포함되어야합니다. (새 경로는 sys.path에 추가되므로 추가 된 디렉토리의 모듈은 표준 모듈을 무시하지 않습니다. 따라서이 메커니즘을 사용할 수 없습니다. 표준 모듈의 고정 버전을 설치하는 데 사용됩니다.) "


1
setuptools의 site-packages 디렉토리에있는 .pth 파일 과이 아이디어를 연결하지 않았습니다. 대박.
dave paola

122

예외 다른 절 :

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

try ... except 문으로 보호되는 코드에 의해 발생하지 않은 예외를 실수로 포착하지 않기 때문에 else 절을 ​​사용하는 것이 try 절에 추가 코드를 추가하는 것보다 낫습니다.

http://docs.python.org/tut/node10.html을 참조 하십시오


8
+1 대단합니다. try 블록이 예외 블록을 입력하지 않고 실행되면 else 블록이 입력됩니다. 그리고 물론 finally 블록이 실행됩니다
inspectorG4dget

나는 왜 '다른'것이 있는지 알게됩니다! 감사.
taynaron

계속 사용하는 것이 더 합리적이지만, 이미 찍은 것 같습니다.)
Paweł Prażak

이전 버전의 Python2에서는 다른 시도와 같은 시도를 동시에 할 수 없습니다. block
Kevin Horn

1
@ Paweł Prażak은 Kevin Horn이 언급했듯이이 구문은 Python의 최초 릴리스 이후에 도입되었으며 기존 언어에 새로운 예약 키워드를 추가하는 것은 항상 문제가됩니다. 이것이 기존 키워드가 일반적으로 재사용되는 이유입니다 (최근 C ++ 표준에서 "auto"참조).
Constantin

114

재발급 예외 :

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

오류 처리기 내에 인수가없는 'raise'문은 Python에 원래의 역 추적 intact로 예외를 다시 발생 시키도록 지시 합니다. "

원래 트레이스 백으로 인쇄, 저장 또는 피들 링하려면 sys.exc_info ()로 가져 와서 파이썬처럼 인쇄하는 것은 'traceback'모듈로 수행됩니다.


죄송합니다. 이것은 거의 모든 언어에서 잘 알려진 일반적인 기능입니다.
Lucas S.

6
기울임 꼴 텍스트를 참고하십시오. raise e대신 어떤 사람들은 원래 역 추적을 보존하지 않습니다.
habnabit

12
아마도 더 마술 exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]
적일

3
@Lucas S. 글쎄, 나는 그것을 몰랐고, 여기에 쓰여서 기쁘다.
전자 Satis

나는 여기에 내 젊음을 보여줄지 모르지만, 나는 파이썬 2.7에서 파이썬 3 문법을 아무 문제없이 사용했습니다.
wim

106

주요 메시지 :)

import this
# btw look at this module's source :)

암호 해독 :

Tim Peters의 Python Zen

못생긴 것보다 아름답습니다.
암시적인 것보다 명시적인 것이 좋습니다.
단순보다 복잡합니다.
복잡한 것이 복잡한 것보다 낫습니다.
평평한 것이 중첩보다 낫습니다.
스파 스가 밀도보다 낫습니다.
가독성이 중요합니다.
특별한 경우는 규칙을 어길만큼 특별하지 않습니다.
실용성은 순도를 능가하지만.
오류가 자동으로 전달되지 않아야합니다.
명시 적으로 침묵하지 않는 한.
모호함에 직면하여 추측하려는 유혹을 거부하십시오. 그것을하는 명백한 방법이 있어야합니다.
네덜란드 인이 아니라면 처음에는 그 방법이 명확하지 않을 수 있습니다.
지금보다 결코 낫습니다.
결코 결코 낫지 않지만바로 지금
구현이 설명하기 어렵다면 나쁜 생각입니다.
구현이 설명하기 쉬운 경우 좋은 생각 일 수 있습니다.
네임 스페이스는 훌륭한 아이디어 중 하나입니다. 더 많은 것을 해보자!


1
왜 소스가 그런 식으로 암호화되었는지 아십니까? 그것은 단지 재미를위한 것이 었습니까, 아니면 다른 이유가 있었습니까?
MiniQuark

42
소스가 쓰여지는 방식은 선에 반합니다!
hasen jan


2
/usr/lib/python2.6/this.py를 업데이트하여 이전 코드를 이것으로 바꾸면 print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))훨씬 좋아 보입니다! :-D
fortran

2
@MiniQuark : 빠른 히스토리 레슨 : wefearchange.org/2010/06/import-this-and-zen-of-python.html

105

대화식 통역사 탭 완성

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

PYTHONSTARTUP 환경 변수도 설정해야합니다.


2
이것은 매우 유용한 기능입니다. 그래서 나는 그것을 가능하게하는 간단한 스크립트 (그리고 몇 가지 다른 내성 향상) : pixelbeat.org/scripts/inpy
pixelbeat

43
IPython는 당신에게 다른 깔끔한 물건이 플러스 톤을 제공합니다
akaihola

이것은 IPython이 그 목적을 수행하기 때문에 일반 파이썬 프롬프트보다 pdb 프롬프트에서 더 유용했을 것입니다. 그러나 이것은 pdb 프롬프트에서 작동하지 않는 것 같습니다 .pdb는 탭에 대해 자체 바인딩을 수행하기 때문에 유용하지 않습니다. pdb 프롬프트에서 parse_and_bind () 호출을 시도했지만 여전히 작동하지 않습니다. IPython으로 pdb 프롬프트를 얻는 대안은 더 많은 작업이므로 사용하지 않는 경향이 있습니다.
haridsv

2
@haridsv-- easy_install ipdb그러면 사용 가능import ipdb; ipdb.set_trace()
Doug Harris

1
osx (그리고 libedit를 사용하는 다른 시스템)에서해야 할 일readline.parse_and_bind ("bind ^I rl_complete")
Foo Bah

91

중첩 된 목록 이해 및 생성기 표현식 :

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

이것들은 큰 덩어리의 중첩 루프 코드를 대체 할 수 있습니다.


"범위 (i)의 j의 경우"-오타입니까? 일반적으로 i와 j에 대해 고정 범위를 원할 것입니다. 2D 배열에 액세스하는 경우 요소의 절반을 놓칠 수 있습니다.
피터 깁슨

이 예제에서는 배열에 액세스하지 않습니다. 이 코드의 유일한 목적은 내부 범위의 표현식이 외부 범위의 표현식에 액세스 할 수 있음을 보여주기위한 것입니다. 부산물은 4> x> y> 0가되도록 쌍 (x, y)의 목록입니다.
Rafał Dowgird

2
미적분학에서의 이중 적분 또는 이중 합산과 같습니다.
Yoo

22
여기에서 기억해야 할 핵심 사항은 깨닫기까지 오랜 시간이 걸렸다는 것입니다. for진술의 순서는 외부에서 안쪽으로 표준 for-loop로 작성 될 것으로 예상되는 순서대로 작성되어야합니다.
sykora

2
sykora의 의견에 덧붙여서 : 내부 에 fors와 ifs의 스택으로 시작한다고 상상해보십시오 yield x. 이것을 제너레이터 표현식으로 변환하려면 x먼저 이동하고 모든 콜론 (및 yield)을 삭제 하고 괄호로 전체를 둘러 쌉니다. 대신 목록을 이해하려면 바깥 쪽 부분을 대괄호로 바꿉니다.
Ken Arnold

91

set내장에 대한 연산자 과부하 :

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

표준 라이브러리 참조에서 자세한 내용 : 유형 설정


튜토리얼에서 부분적으로 docs.python.org/tutorial/datastructures.html#sets
XTL
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.