출처 : http://pypix.com/tools-and-tips/python-functions/
가변 갯수 인자로 함수 쓰기
우선 다음의 단순한 선택 인자 예제를 보자.
1
2
3
4
5
6
7
8
9
10
11 | def function(arg1="",arg2=""):
print "arg1: {0}".format(arg1)
print "arg2: {0}".format(arg2)
function("Hello", "World")
# prints arg1: Hello
# prints arg2: World
function()
# prints arg1:
# prints arg2:
|
함수 인자에 =를 이용하여 default 값을 지정해 놓으면 해당 인자를 명시하지 않을 경우 default 값이 사용된다.
하지만 이보다는 좀 더 유연한 방법도 있다. Tuple을 이용한 인자 받기 방식이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | def foo(*args): # "*" 를 사용하면 나머지 인자를 모두 tuple로 받는다.
numargs = len(args)
print "Number of arguments: {0}".format(numargs)
for i, x in enumerate(args):
print "Argument {0} is: {1}".format(i,x)
foo()
# Number of arguments: 0
foo("hello")
# Number of arguments: 1
# Argument 0 is: hello
foo("hello","World","Again")
# Number of arguments: 3
# Argument 0 is: hello
# Argument 1 is: World
# Argument 2 is: Again
|
glob()으로 파일 찾기
glob()을 써본 적이 없다면 이름에서 뭘 하는 함수인지 유추해내기는 쉽지 않을 것이다. 일종의 listdir()의 다른 버전이라고 생각하면 될 듯.
이 함수는 이름 패턴을 써서 파일들을 찾는 데에 사용된다.
1
2
3
4
5
6
7
8 | import glob
# get all py files
files = glob.glob('*.py')
print files
# Output
# ['arg.py', 'g.py', 'shut.py', 'test.py']
|
다음과 같은 방식으로 다양한 파일 타입을 동시에 찾을 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | import itertools as it, glob
def multiple_file_types(*patterns):
return it.chain.from_iterable(glob.glob(pattern) for pattern in patterns)
for filename in multiple_file_types("*.txt", "*.py"): # add as many filetype arguements
print filename
# output
#=========#
# test.txt
# arg.py
# g.py
# shut.py
# test.py
|
찾은 파일들에 대해 full path를 알고 싶다면 리턴값에 대해 realpath()를 사용하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | import itertools as it, glob, os
def multiple_file_types(*patterns):
return it.chain.from_iterable(glob.glob(pattern) for pattern in patterns)
for filename in multiple_file_types("*.txt", "*.py"): # add as many filetype arguements
realpath = os.path.realpath(filename)
print realpath
# output
#=========#
# C:\xxx\pyfunc\test.txt
# C:\xxx\pyfunc\arg.py
# C:\xxx\pyfunc\g.py
# C:\xxx\pyfunc\shut.py
# C:\xxx\pyfunc\test.py
|
디버깅
(물론 pdb로 디버깅하는 방법도 있지만) 아래 예제들은 inspect 모듈을 사용한 것이다. 이 모듈은 디버깅 목적으로 매우 유용하며 많은 것을 얻어낼 수 있다. 아래에 간단한 예제를 명시한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | import logging, inspect
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)-8s %(filename)s:%(lineno)-4d: %(message)s',
datefmt='%m-%d %H:%M',
)
logging.debug('A debug message')
logging.info('Some information')
logging.warning('A shot across the bow')
def test():
frame,filename,line_number,function_name,lines,index=\
inspect.getouterframes(inspect.currentframe())[1]
print(frame,filename,line_number,function_name,lines,index)
test()
# Should print the following (with current date/time of course)
#10-19 19:57 INFO test.py:9 : Some information
#10-19 19:57 WARNING test.py:10 : A shot across the bow
#(<frame object at 0x01E8A390>, 'C:/xxx/pyfunc/magic.py', 16, '<module>', ['test()\n'], 0)
|
단일 ID 생성
뭔가 ID 역할을 할 문자열을 생성해야 할 상황에 부딪치는 경우가 많을 것이다. 많은 사람들이 그런 경우에 md5()를 쓰는 것을 보았는데 정확한 해결책이라고는 할 수 없다.
그런 목적을 위해서는 파이썬에서 지원하는 uuid()가 더 적합하다.
1
2
3
4
5
6
7
8 | import uuid
result = uuid.uuid1()
print result
# output => various attempts
# 9e177ec0-65b6-11e3-b2d0-e4d53dfcf61b
# be57b880-65b6-11e3-a04d-e4d53dfcf61b
# c3b2b90f-65b6-11e3-8c86-e4d53dfcf61b
|
생성된 문자열들이 각각 다르기는 해도 뒷부분은 동일하다는 것을 눈치챘는지? 이는 uuid가 네트웍 주소에 기반하기 때문이다.
중복여지를 더 줄이기 위해서는 다음과 같은 방식도 쓸 수 있다.
1
2
3
4
5
6
7
8
9
10
11 | import hmac,hashlib
key='1'
data='a'
print hmac.new(key, data, hashlib.sha256).hexdigest()
m = hashlib.sha1()
m.update("The quick brown fox jumps over the lazy dog")
print m.hexdigest()
# c6e693d0b35805080632bc2469e1154a8d1072a86557778c27a01329630f8917
# 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
|
직렬화
DB나 텍스트 파일에 복잡한 변수를(객체 변수) 저장해야 되었던 적이 있었는지? 그런 경우에 굳이 특정 포맷의 문자열을 생성한다든가 할 필요는 없다. 파이썬은 이미 그런 목적을 위한 함수들을 갖고 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | import pickle
variable = ['hello', 42, [1,'two'],'apple']
# serialize content
file = open('serial.txt','w')
serialized_obj = pickle.dumps(variable)
file.write(serialized_obj)
file.close()
# unserialize to produce original content
target = open('serial.txt','r')
myObj = pickle.load(target)
print serialized_obj
print myObj
#output
# (lp0
# S'hello'
# p1
# aI42
# a(lp2
# I1
# aS'two'
# p3
# aaS'apple'
# p4
# a.
# ['hello', 42, [1, 'two'], 'apple']
|
이는 파이썬 고유의 직렬화 방법이다(즉 파이썬에서만 읽을 수 있음). 하지만 최근에는 JSON 포맷이 인기를 끌다 보니 그에 대한 것도 지원하게 되었다.
이제 JSON으로 인코딩/디코딩하는 예제를 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | import json
variable = ['hello', 42, [1,'two'],'apple']
print "Original {0} - {1}".format(variable,type(variable))
# encoding
encode = json.dumps(variable)
print "Encoded {0} - {1}".format(encode,type(encode))
#deccoding
decoded = json.loads(encode)
print "Decoded {0} - {1}".format(decoded,type(decoded))
# output
# Original ['hello', 42, [1, 'two'], 'apple'] - <type 'list'>
# Encoded ["hello", 42, [1, "two"], "apple"] - <type 'str'>
# Decoded [u'hello', 42, [1, u'two'], u'apple'] - <type 'list'>
|
이는 훨씬 간단하면서도 javascript나 다른 언어와도 호환이 가능하다.
하지만 복잡한 객체들의 경우 일부 정보가 유실될 수도 있으므로 주의해서 사용해야 한다.
문자열 압축
압축에 대해 얘기하면 보통 ZIP 파일 같은 것들을 생각하겠지만 파이썬에서는 그런 압축 파일을 생성하지 않고도 압축을 지원한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | import zlib
string = """ Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc ut elit id mi ultricies
adipiscing. Nulla facilisi. Praesent pulvinar,
sapien vel feugiat vestibulum, nulla dui pretium orci,
non ultricies elit lacus quis ante. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Aliquam
pretium ullamcorper urna quis iaculis. Etiam ac massa
sed turpis tempor luctus. Curabitur sed nibh eu elit
mollis congue. Praesent ipsum diam, consectetur vitae
ornare a, aliquam a nunc. In id magna pellentesque
tellus posuere adipiscing. Sed non mi metus, at lacinia
augue. Sed magna nisi, ornare in mollis in, mollis
sed nunc. Etiam at justo in leo congue mollis.
Nullam in neque eget metus hendrerit scelerisque
eu non enim. Ut malesuada lacus eu nulla bibendum
id euismod urna sodales. """
print "Original Size: {0}".format(len(string))
compressed = zlib.compress(string)
print "Compressed Size: {0}".format(len(compressed))
decompressed = zlib.decompress(compressed)
print "Decompressed Size: {0}".format(len(decompressed))
# output
# Original Size: 1022
# Compressed Size: 423
# Decompressed Size: 1022
|