파이썬의 선(zen of python)를 보려면 파이썬 인터프리터에서 this를 임포트하면 된다. 이스터 에그(Easter Egg)..




>>> import this

The Zen of Python, by Tim Peters


Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren't special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one-- and preferably only one --obvious way to do it.

Although that way may not be obvious at first unless you're Dutch.

Now is better than never.

Although never is often better than *right* now.

If the implementation is hard to explain, it's a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea -- let's do more of those!




그동안의 경험을 기반으로 의역했다.



파이썬의 선, 팀 피터


아름다운 코드는 지저분한 코드보다 낫다.


명확한 코드는 암시적인 코드보다 낫다.


단순한 코드가 복잡한 코드보다 낫다.


복잡한 코드가 난해한 코드보다 낫다.


단조로운 코드가 복잡한 코드보다 낫다.


읽기 쉬운 코드는 읽기 어려운 코드보다 낫다.


가독성은 중요하다.


규칙을 깰 정도로 특별한 경우란 없다.


하지만 실용성은 이상을 능가한다.


에러를 결코 조용히 넘어가지 않도록 한다.


명시적으로 조용히 넘어가라고 하더라도 조용히 넘어가지 않는다.


모호한 코드를 대면할 때마다 추측하고 싶은 유혹을 거절하라.


문제를 해결할 단 하나의 명확하고 바람직한 방법이 있을 것이다. 


하지만 처음에 코딩을 할 때는 잘 모를 수 있기에 코드의 동작 방법을 정확히 알지 못 할 수 있다.


아무 것도 안하는 것보다 지금 하는 게 낫다.


하지만 아무 것도 하지 않는 것이 지금 *당장* 하는 것보다 나을 수도 있다.


설명하기 어려운 구현이라면 좋은 아이디어는 아니다.


쉽게 설명할 수 있는 구현이라면 좋은 아이디어일 것이다.


네임스페이스는 매우 훌륭한 아이디어이다. 많이 사용하자




'python' 카테고리의 다른 글

파이썬의 선(Zen of Python)  (0) 2018.09.23
[python] pickle 예시  (0) 2018.09.12
[python] urlsplit 예제  (0) 2018.09.12
파이썬 모듈 프로그래밍 예시 - __init__.py  (0) 2018.09.07
[python] whois 모듈  (0) 2018.09.03
[python] OptionParser 활용하는 사례  (0) 2018.07.04
Posted by 김용환 '김용환'

[python] pickle 예시

python 2018.09.12 14:57



자바의 serialization/deserialization은 언어/jvm 레벨에서 이루어지지만,


파이썬에서는 모듈 단에서 이루어진다. 대표적인 모듈이 pickle이다.


https://docs.python.org/3/library/pickle.html




파이썬에서 list를 바로 파일로 저장할 수 없다. 



>>> mylist = ['a', 'b', 'c', 'd']

>>> with open('test.txt','wb') as f:

...     pickle.dump(mylist,f)

...

>>> with open('test.txt','rb') as f:

...     yourlist=pickle.load(f)

...

>>> yourlist

['a', 'b', 'c', 'd']




주의할 점은 bytes가 아니라 string으로 읽고 저장, 즉 'wb', 'rb'를 해야 한다.


>>> with open('test.txt','w') as f:

...     pickle.dump(mylist,f)

...

Traceback (most recent call last):

  File "<stdin>", line 2, in <module>

TypeError: write() argument must be str, not bytes


'python' 카테고리의 다른 글

파이썬의 선(Zen of Python)  (0) 2018.09.23
[python] pickle 예시  (0) 2018.09.12
[python] urlsplit 예제  (0) 2018.09.12
파이썬 모듈 프로그래밍 예시 - __init__.py  (0) 2018.09.07
[python] whois 모듈  (0) 2018.09.03
[python] OptionParser 활용하는 사례  (0) 2018.07.04
Posted by 김용환 '김용환'

[python] urlsplit 예제

python 2018.09.12 13:12



python에서 URL을 파싱하려면 urllib.parse 모듈의 urlsplit 함수를 사용한다. urlsplit 함수는 URL을 각 구성 요소로 분리한다.




>>> from urllib.parse import urlsplit


>>> components = urlsplit('http://example.webscraping.com/places/default/view')


>>> print(components)

SplitResult(scheme='http', netloc='example.webscraping.com', path='/places/default/view', query='', fragment='')


>>> print(components.path)

/places/default/view





'python' 카테고리의 다른 글

파이썬의 선(Zen of Python)  (0) 2018.09.23
[python] pickle 예시  (0) 2018.09.12
[python] urlsplit 예제  (0) 2018.09.12
파이썬 모듈 프로그래밍 예시 - __init__.py  (0) 2018.09.07
[python] whois 모듈  (0) 2018.09.03
[python] OptionParser 활용하는 사례  (0) 2018.07.04
Posted by 김용환 '김용환'


파이썬 모듈/패키징 프로그래밍의 __init__.py를 활용한 예제이다.

__init__.py은 파이썬 3.3부터는 없어도 잘 동작하지만 호환성을 위해서 둔다.


개념은 파이썬 스터디 싸이트가 잘 되어 있다.

http://pythonstudy.xyz/python/article/18-%ED%8C%A8%ED%82%A4%EC%A7%80



간단한 예시를 만든다.


$ mkdir -p module


$ touch module/__init__.py



xxx라는 모듈을 추가한다.



$ cat > module/xxx.py

def echo():

print("echo")



$ ls -al module/

-rw-r--r--  1 samuel.kim  staff    0  9  7 12:30 __init__.py

-rw-r--r--  1 samuel.kim  staff   27  9  7 12:31 xxx.py



이제 python 인터프리터에서 xxx.py의 echo()를 호출한다.


$ python

Python 3.6.2 (default, Sep  5 2017, 15:21:12)

[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>> from module.xxx import echo

>>> echo

<function echo at 0x10c25d268>

>>> echo ()

echo

>>> echo()

echo


잘동작한다.





이번에는 yyy.py에서 xxx.py의 echo()를 호출하는 예이다.


$ cat > module/yyy.py


from module.xxx import echo


def test():

    echo()

    print("Test")



>>> from module.yyy import test

>>> test()

echo

Test




https://github.com/kjam/wswp 를 다운받아서 코드를 실행하고 싶다면,

code 디렉토 밑에서 python을 실행하고 다음과 같이 파이썬 모듈을 실행할 수 있다.



>>> from chp1.advanced_link_crawler import link_crawler

>>> start_url = 'http://example.webscraping.com/index'

>>> link_regex = '/(index|view)'

>>> link_crawler(start_url, link_regex, user_agent='BadCrawler')

Downloading: http://example.webscraping.com/index





'python' 카테고리의 다른 글

[python] pickle 예시  (0) 2018.09.12
[python] urlsplit 예제  (0) 2018.09.12
파이썬 모듈 프로그래밍 예시 - __init__.py  (0) 2018.09.07
[python] whois 모듈  (0) 2018.09.03
[python] OptionParser 활용하는 사례  (0) 2018.07.04
[python] pytz의 평양/서울 시간 버그  (0) 2018.06.19
Posted by 김용환 '김용환'

[python] whois 모듈

python 2018.09.03 14:24


python의 whois 모듈을 사용하면 whois 웹 검색과 동일한 결과를 얻을 수 있다..




$ pip install python-whois



$ python

Python 3.7.0 (default, Sep  3 2018, 12:00:39)

[Clang 7.3.0 (clang-703.0.31)] on darwin

Type "help", "copyright", "credits" or "license" for more information.




>>> import whois

>>> print(whois.whois('appspot.com'))


{

  "domain_name": [

    "APPSPOT.COM",

    "appspot.com"

  ],

  "registrar": "MarkMonitor, Inc.",

  "whois_server": "whois.markmonitor.com",

  "referral_url": null,

  "updated_date": [

    "2018-02-06 10:30:28",

    "2018-02-06 02:30:29-08:00"

  ],

  "creation_date": [

    "2005-03-10 02:27:55",

    "2005-03-09 18:27:55-08:00"

  ],

  "expiration_date": [

    "2019-03-10 01:27:55",

    "2019-03-09 00:00:00-08:00"

  ],

  "name_servers": [

    "NS1.GOOGLE.COM",

    "NS2.GOOGLE.COM",

    "NS3.GOOGLE.COM",

    "NS4.GOOGLE.COM",

    "ns1.google.com",

    "ns2.google.com",

    "ns4.google.com",

    "ns3.google.com"

  ],

  "status": [

    "clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited",

    "clientTransferProhibited https://icann.org/epp#clientTransferProhibited",

    "clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited",

    "serverDeleteProhibited https://icann.org/epp#serverDeleteProhibited",

    "serverTransferProhibited https://icann.org/epp#serverTransferProhibited",

    "serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited",

    "clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited)",

    "clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited)",

    "clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited)",

    "serverUpdateProhibited (https://www.icann.org/epp#serverUpdateProhibited)",

    "serverTransferProhibited (https://www.icann.org/epp#serverTransferProhibited)",

    "serverDeleteProhibited (https://www.icann.org/epp#serverDeleteProhibited)"

  ],

  "emails": [

    "abusecomplaints@markmonitor.com",

    "whoisrelay@markmonitor.com"

  ],

  "dnssec": "unsigned",

  "name": null,

  "org": "Google LLC",

  "address": null,

  "city": null,

  "state": "CA",

  "zipcode": null,

  "country": "US"

}

>>> print(whois.whois('naver.com'))

{

  "domain_name": [

    "NAVER.COM",

    "naver.com"

  ],

  "registrar": "Gabia, Inc.",

  "whois_server": "whois.gabia.com",

  "referral_url": null,

  "updated_date": [

    "2016-08-05 06:37:57",

    "2018-02-28 11:27:15"

  ],

  "creation_date": [

    "1997-09-12 04:00:00",

    "1997-09-12 00:00:00"

  ],

  "expiration_date": [

    "2023-09-11 04:00:00",

    "2023-09-11 00:00:00"

  ],

  "name_servers": [

    "NS1.NAVER.COM",

    "NS2.NAVER.COM",

    "ns1.naver.com",

    "ns2.naver.com"

  ],

  "status": [

    "clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited",

    "clientTransferProhibited https://icann.org/epp#clientTransferProhibited",

    "clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited",

    "ok https://icann.org/epp#ok"

  ],

  "emails": [

    "white.4818@navercorp.com",

    "dl_ssl@navercorp.com",

    "abuse@gabia.com"

  ],

  "dnssec": "unsigned",

  "name": "NAVER Corp.",

  "org": "NAVER Corp.",

  "address": "6 Buljung-ro, Bundang-gu, Seongnam-si, Gyeonggi-do, 463-867, Korea",

  "city": "Gyeonggi",

  "state": null,

  "zipcode": "463463",

  "country": "KR"

}

>>> print(whois.whois('abc.com'))

{

  "domain_name": [

    "ABC.COM",

    "abc.com"

  ],

  "registrar": "CSC CORPORATE DOMAINS, INC.",

  "whois_server": "whois.corporatedomains.com",

  "referral_url": null,

  "updated_date": [

    "2018-08-08 23:38:25",

    "2018-08-08 17:11:02"

  ],

  "creation_date": "1996-05-22 04:00:00",

  "expiration_date": "2019-05-23 04:00:00",

  "name_servers": [

    "ORNS01.DIG.COM",

    "ORNS02.DIG.COM",

    "SENS01.DIG.COM",

    "SENS02.DIG.COM",

    "orns02.dig.com",

    "orns01.dig.com",

    "sens02.dig.com",

    "sens01.dig.com"

  ],

  "status": [

    "clientTransferProhibited https://icann.org/epp#clientTransferProhibited",

    "serverDeleteProhibited https://icann.org/epp#serverDeleteProhibited",

    "serverTransferProhibited https://icann.org/epp#serverTransferProhibited",

    "serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited",

    "clientTransferProhibited http://www.icann.org/epp#clientTransferProhibited",

    "serverDeleteProhibited http://www.icann.org/epp#serverDeleteProhibited",

    "serverTransferProhibited http://www.icann.org/epp#serverTransferProhibited"

  ],

  "emails": [

    "domainabuse@cscglobal.com",

    "Corp.DNS.Domains@disney.com"

  ],

  "dnssec": "unsigned",

  "name": "ABC, Inc.; Domain Administrator",

  "org": "ABC, Inc.",

  "address": "77 West 66th Street",

  "city": "New York",

  "state": "NY",

  "zipcode": "10023-6298",

  "country": "US"

}



Posted by 김용환 '김용환'



python에서 옵션(매개 변수)를 받고, 공백(white space)가 있으면 처리해준다.



from optparse import OptionParser

import re


parser = OptionParser()

parser.add_option("--exclude_host", help="excluded host", type="string", default='')

..

exclude_host = re.split("^\s+|\s*,\s*|\s+$", options.exclude_host)




이외에 배열에 대해 A-B 같은 substract 같은 연산을 하고 싶으면 다음 예시를 참조한다.


..

if options.exclude_host is not '':

    fqdn_list = [item for item in fqdn_list if item not in exclude_host ]


Posted by 김용환 '김용환'


python pytz에 좀 버그가 있다. 



근데, 어디서 많이 본 정상혁 아저씨가 보인다

https://github.com/stub42/pytz/blob/master/tz/asia#L1928

(참고 썸머 타임 글 관련 기고 https://d2.naver.com/helloworld/645609)



>>> import pytz

>>> from datetime import datetime

>>> fmt = '%Y-%m-%d %H:%M:%S %Z%z'

>>> seoul = pytz.timezone('Asia/Seoul')

>>> seoul

<DstTzInfo 'Asia/Seoul' LMT+8:28:00 STD>

>>> seoul_dt = seoul.localize(datetime(2018, 6, 19, 17, 53))

>>> seoul_dt.strftime(fmt)

'2018-06-19 17:53:00 KST+0900'


관련해서 내용을 올렸다.


https://github.com/stub42/pytz/issues/15


Hi!

I found a time zone issue which changed Pyongyang(North Korea) time zoned recently.
According to 'https://en.wikipedia.org/wiki/Time_in_North_Korea', I found 'On 29 April 2018, North Korean leader Kim Jong-un announced his country would be returning to UTC+9 to realign its clocks with South Korea. '. It based on the Guadian Newspaper('https://www.theguardian.com/world/2018/may/05/time-for-change-north-korea-moves-clocks-forward-to-match-south')

Below code is not match the Wiki.

import pytz
import datetime

def main():
	
	seoul = pytz.timezone('Asia/Seoul')
	print(seoul.localize(datetime.datetime.now()))
	
	pyongyang = pytz.timezone('Asia/Pyongyang')
	print(pyongyang.localize(datetime.datetime.now()))
	
if __name__ == '__main__':
	main()

The result is below.

2018-06-19 18:23:36.818206+09:00
2018-06-19 18:23:36.818469+08:30

Second result should be equal to '2018-06-19 18:23:36.818469+09:00'

Could you change code and and document(https://github.com/stub42/pytz/blob/master/tz/asia#L1997)?

And When I test the previous example, I found another interesting sample code.

>>> import pytz

>>> from datetime import datetime

>>> fmt = '%Y-%m-%d %H:%M:%S %Z%z'

>>> seoul = pytz.timezone('Asia/Seoul')

>>> seoul

<DstTzInfo 'Asia/Seoul' KST+8:30:00 STD>
>>> pyongyang = pytz.timezone('Asia/Pyongyang')
>>> pyounyang

<DstTzInfo 'Asia/Pyongyang' KST+8:30:00 STD>

Finally, I found another interesting document. You described world timezone. Previsous menthioned, I think it should be changed.

https://github.com/stub42/pytz/blob/master/tz/asia#L47
https://github.com/stub42/pytz/blob/master/tz/asia#L50
-> I think it should be removed at '8:30 KST KDT Korea when at +0830', maintained at ''9:00 KST KDT Korea when at +09'.

Thanks in advance.






Posted by 김용환 '김용환'


간단 코드 예시


import requests


def main():
print('Hello, world!')
response = requests.get('https://httpbin.org/ip')
print(response.status_code)
print(response.headers)
print('Your IP is {0}'.format(response.json()['origin']))

if __name__ == '__main__':
main()



결과는 다음과 같다. 


Hello, world!

200

{'Connection': 'keep-alive', 'Server': 'gunicorn/19.8.1', 'Date': 'Mon, 04 Jun 2018 02:28:09 GMT', 'Content-Type': 'application/json', 'Content-Length': '26', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true', 'Via': '1.1 vegur'}

Your IP is 1.1.1.1





HTTPAdapter를 이용하는 코드이다.


from requests import Session
from requests.adapters import HTTPAdapter


def main():
print('Hello, world!')

session = Session()
session.mount("http://", HTTPAdapter(max_retries=3))
response = session.get('https://httpbin.org/ip', timeout=0)

print(response.status_code)
print(response.headers)
print('Your IP is {0}'.format(response.json()['origin']))

if __name__ == '__main__':
main()




결과는 동일하다.




from requests import Session
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry


def main():
print('Hello, world!')
retries_number = 3
backoff_factor = 0.3
status_forcelist = (500, 400)

retry = Retry(
total=retries_number,
read=retries_number,
connect=retries_number,
backoff_factor=backoff_factor,
status_forcelist=status_forcelist,
)
session = Session()
session.mount("http://", HTTPAdapter(max_retries=retry))
response = session.get('https://httpbin.org/ip', timeout=0)

print(response.status_code)
print(response.headers)
print('Your IP is {0}'.format(response.json()['origin']))

if __name__ == '__main__':
main()



아래 공식에 따르면, 다음과 같다.  총 소요되는 시간은 1.8인데... 


{backoff factor} * (2 ^ ({number of total retries} - 1))



0.3 * ( 2 ^ ( 1 - 1)) = 0

0.3 * ( 2 ^ ( 2 - 1)) = 0.6

0.3 * ( 2 ^ ( 3 - 1)) = 1.2



1.8 = 0 + 0.6 + 1.2






https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html#module-urllib3.util.retry


backoff_factor (float) –

A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a second try without a delay). urllib3 will sleep for:

{backoff factor} * (2 ^ ({number of total retries} - 1))

seconds. If the backoff_factor is 0.1, then sleep() will sleep for [0.0s, 0.2s, 0.4s, …] between retries. It will never be longer than Retry.BACKOFF_MAX.

By default, backoff is disabled (set to 0).






만약 타임아웃이 생기면, 중간에 쉬는 타임이 생긴다. retries와 timeout을 잘 사용하면 괜찮을 것 같다. 


response = session.get('https://httpbin.org/ip', timeout=5)

Posted by 김용환 '김용환'


python에 특이한 문법인 try-else문이 있어서 살펴본 예이다. 


except문이 실행되지 않으면 else 문이 실행된다. 

a=0
try:
a=1
except ZeroDivisionError as e:
print(str(e))
else:
print(a)


결과는 1이다.





다음은 일부러 0으로 나눠 ZeroDivisionError를 발생시키는 코드이다. 


except 문이 실행되면 else문이 실행되지 않는다. 

a=0
try:
a = 4/0
except ZeroDivisionError as e:
print(str(e))
else:
print(a)


결과는 다음과 같다.


division by zero




Posted by 김용환 '김용환'


python에 특이한 문법인 for else가 있다고 해서 살펴봤다. 


for - else를 실행하는 예이다.


data = [1, 2, 3, 4, 5]
for i in data:
print(i)
else:
print("aa")

print("end")


결과는 다음과 같다.


1

2

3

4

5

aa

end






왜 필요할까. break와 연관된 문법이다.



중간에 break 문을 만나 for 문 바깥으로 나가면 else 문이 출력되지 않는다. 


data = [1, 2, 3, 4, 5]
for i in data:
print(i)
if i == 3:
break
else:
print("aa")

print("end")




결과는 다음과 같다.




1

2

3

end





Posted by 김용환 '김용환'