From 1780a431a55c1673390e89c7f50591bc9384fc0b Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Mon, 30 Mar 2015 21:24:04 +0800 Subject: [PATCH 01/44] add py3 source for basic --- py3/basic/do_for.py | 11 +++++++++++ py3/basic/do_if.py | 15 +++++++++++++++ py3/basic/do_input.py | 5 +++++ py3/basic/do_print.py | 7 +++++++ py3/basic/do_while.py | 10 ++++++++++ py3/basic/hello.py | 4 ++++ py3/basic/the_dict.py | 12 ++++++++++++ py3/basic/the_list.py | 12 ++++++++++++ py3/basic/the_set.py | 8 ++++++++ py3/basic/the_string.py | 8 ++++++++ py3/basic/the_tuple.py | 13 +++++++++++++ 11 files changed, 105 insertions(+) create mode 100755 py3/basic/do_for.py create mode 100755 py3/basic/do_if.py create mode 100755 py3/basic/do_input.py create mode 100755 py3/basic/do_print.py create mode 100755 py3/basic/do_while.py create mode 100755 py3/basic/hello.py create mode 100755 py3/basic/the_dict.py create mode 100755 py3/basic/the_list.py create mode 100755 py3/basic/the_set.py create mode 100755 py3/basic/the_string.py create mode 100755 py3/basic/the_tuple.py diff --git a/py3/basic/do_for.py b/py3/basic/do_for.py new file mode 100755 index 0000000..8db278f --- /dev/null +++ b/py3/basic/do_for.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# 打印list: +names = ['Michael', 'Bob', 'Tracy'] +for name in names: + print(name) + +# 打印数字 0 - 9 +for x in range(10): + print(x) diff --git a/py3/basic/do_if.py b/py3/basic/do_if.py new file mode 100755 index 0000000..c0c16d7 --- /dev/null +++ b/py3/basic/do_if.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# 注意: +# input()返回的是字符串 +# 必须通过int()将字符串转换为整数 +# 才能用于数值比较: +age = int(input('Input your age: ')) + +if age >= 18: + print('adult') +elif age >= 6: + print('teenager') +else: + print('kid') diff --git a/py3/basic/do_input.py b/py3/basic/do_input.py new file mode 100755 index 0000000..783523a --- /dev/null +++ b/py3/basic/do_input.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +name = input() +print('Hello,', name) diff --git a/py3/basic/do_print.py b/py3/basic/do_print.py new file mode 100755 index 0000000..1330003 --- /dev/null +++ b/py3/basic/do_print.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +print('The quick brown fox', 'jumps over', 'the lazy dog') +print(300) +print(100 + 200) +print('100 + 200 =', 100 + 200) diff --git a/py3/basic/do_while.py b/py3/basic/do_while.py new file mode 100755 index 0000000..9eca97d --- /dev/null +++ b/py3/basic/do_while.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# 计算1+2+3+...+100: +sum = 0 +n = 1 +while n <= 100: + sum = sum + n + n = n + 1 +print(sum) diff --git a/py3/basic/hello.py b/py3/basic/hello.py new file mode 100755 index 0000000..0c86710 --- /dev/null +++ b/py3/basic/hello.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +print('Hello, world') diff --git a/py3/basic/the_dict.py b/py3/basic/the_dict.py new file mode 100755 index 0000000..edd90ff --- /dev/null +++ b/py3/basic/the_dict.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +d = { + 'Michael': 95, + 'Bob': 75, + 'Tracy': 85 +} +print('d[\'Michael\'] =', d['Michael']) +print('d[\'Bob\'] =', d['Bob']) +print('d[\'Tracy\'] =', d['Tracy']) +print('d.get(\'Thomas\', -1) =', d.get('Thomas', -1)) diff --git a/py3/basic/the_list.py b/py3/basic/the_list.py new file mode 100755 index 0000000..8dac133 --- /dev/null +++ b/py3/basic/the_list.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +classmates = ['Michael', 'Bob', 'Tracy'] +print('classmates =', classmates) +print('len(classmates) =', len(classmates)) +print('classmates[0] =', classmates[0]) +print('classmates[1] =', classmates[1]) +print('classmates[2] =', classmates[2]) +print('classmates[-1] =', classmates[-1]) +classmates.pop() +print('classmates =', classmates) diff --git a/py3/basic/the_set.py b/py3/basic/the_set.py new file mode 100755 index 0000000..67162e6 --- /dev/null +++ b/py3/basic/the_set.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +s1 = set([1, 1, 2, 2, 3, 3]) +print(s1) +s2 = set([2, 3, 4]) +print(s1 & s2) +print(s1 | s2) diff --git a/py3/basic/the_string.py b/py3/basic/the_string.py new file mode 100755 index 0000000..41c41fb --- /dev/null +++ b/py3/basic/the_string.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +s = 'Python-中文' +print(s) +b = s.encode('utf-8') +print(b) +print(b.decode('utf-8')) diff --git a/py3/basic/the_tuple.py b/py3/basic/the_tuple.py new file mode 100755 index 0000000..382c3aa --- /dev/null +++ b/py3/basic/the_tuple.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +classmates = ('Michael', 'Bob', 'Tracy') +print('classmates =', classmates) +print('len(classmates) =', len(classmates)) +print('classmates[0] =', classmates[0]) +print('classmates[1] =', classmates[1]) +print('classmates[2] =', classmates[2]) +print('classmates[-1] =', classmates[-1]) + +# cannot modify tuple: +classmates[0] = 'Adam' From 1aac93f32cddc4f6f575b6fd48cf8ea91c1bab63 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Mon, 30 Mar 2015 22:21:36 +0800 Subject: [PATCH 02/44] add function examples --- py3/function/call_func.py | 9 +++++++++ py3/function/def_func.py | 26 ++++++++++++++++++++++++++ py3/function/params.py | 9 +++++++++ py3/function/recur.py | 24 ++++++++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100755 py3/function/call_func.py create mode 100755 py3/function/def_func.py create mode 100755 py3/function/params.py create mode 100755 py3/function/recur.py diff --git a/py3/function/call_func.py b/py3/function/call_func.py new file mode 100755 index 0000000..d864134 --- /dev/null +++ b/py3/function/call_func.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +x = abs(100) +y = abs(-20) +print(x, y) +print('max(1, 2, 3) =', max(1, 2, 3)) +print('min(1, 2, 3) =', min(1, 2, 3)) +print('sum([1, 2, 3]) =', sum([1, 2, 3])) diff --git a/py3/function/def_func.py b/py3/function/def_func.py new file mode 100755 index 0000000..d7c09a1 --- /dev/null +++ b/py3/function/def_func.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import math + +def my_abs(x): + if not isinstance(x, (int, float)): + raise TypeError('bad operand type') + if x >= 0: + return x + else: + return -x + +def move(x, y, step, angle=0): + nx = x + step * math.cos(angle) + ny = y - step * math.sin(angle) + return nx, ny + +n = my_abs(-20) +print(n) + +x, y = move(100, 100, 60, math.pi / 6) +print(x, y) + +# TypeError: bad operand type: +my_abs('123') diff --git a/py3/function/params.py b/py3/function/params.py new file mode 100755 index 0000000..12410a9 --- /dev/null +++ b/py3/function/params.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def power(x, n=2): + return x ** n + +print('power(5) =', power(5)) +print('power(5, 2) =', power(5, 2)) +print('power(5, 4) =', power(5, 4)) diff --git a/py3/function/recur.py b/py3/function/recur.py new file mode 100755 index 0000000..18ec40a --- /dev/null +++ b/py3/function/recur.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# 利用递归函数计算阶乘 +# N! = 1 * 2 * 3 * ... * N +def fact(n): + if n == 1: + return 1 + return n * fact(n-1) + +print('fact(1) =', fact(1)) +print('fact(5) =', fact(5)) +print('fact(10) =', fact(10)) + +# 利用递归函数移动汉诺塔: +def move(n, a, b, c): + if n == 1: + print('move', a, '-->', c) + return + move(n-1, a, c, b) + print('move', a, '-->', c) + move(n-1, b, a, c) + +move(4, 'A', 'B', 'C') From 55adb464d5a14fb9e1395bbc5938a5ec049febde Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Mon, 30 Mar 2015 22:33:13 +0800 Subject: [PATCH 03/44] add slice and map --- py3/advance/do_slice.py | 16 ++++++++++++++++ py3/functional/do_map.py | 7 +++++++ 2 files changed, 23 insertions(+) create mode 100755 py3/advance/do_slice.py create mode 100755 py3/functional/do_map.py diff --git a/py3/advance/do_slice.py b/py3/advance/do_slice.py new file mode 100755 index 0000000..fd8d7c6 --- /dev/null +++ b/py3/advance/do_slice.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] + +print('L[0:3] =', L[0:3]) +print('L[:3] =', L[:3]) +print('L[1:3] =', L[1:3]) +print('L[-2:] =', L[-2:]) + +R = list(range(100)) +print('R[:10] =', R[:10]) +print('R[-10:] =', R[-10:]) +print('R[10:20] =', R[10:20]) +print('R[:10:2] =', R[:10:2]) +print('R[::5] =', R[::5]) diff --git a/py3/functional/do_map.py b/py3/functional/do_map.py new file mode 100755 index 0000000..9360a50 --- /dev/null +++ b/py3/functional/do_map.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def f(x): + return x * x + +print(list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]))) From 22d92c0de39d5c9b42710cf62bf523254924fa57 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Tue, 31 Mar 2015 13:04:25 +0800 Subject: [PATCH 04/44] add new samples --- .gitignore | 3 +++ py3/commonlib/do_base64.py | 14 +++++++++++ py3/coroutine/async_hello.py | 14 +++++++++++ py3/db/do_sqlite.py | 34 ++++++++++++++++++++++++++ py3/debug/do_try.py | 12 +++++++++ py3/functional/decorator.py | 33 +++++++++++++++++++++++++ py3/functional/do_filter.py | 14 +++++++++++ py3/functional/do_partial.py | 9 +++++++ py3/functional/do_reduce.py | 25 +++++++++++++++++++ py3/functional/do_sorted.py | 23 ++++++++++++++++++ py3/functional/return_func.py | 46 +++++++++++++++++++++++++++++++++++ py3/io/file.py | 18 ++++++++++++++ 12 files changed, 245 insertions(+) create mode 100755 py3/commonlib/do_base64.py create mode 100755 py3/coroutine/async_hello.py create mode 100755 py3/db/do_sqlite.py create mode 100755 py3/debug/do_try.py create mode 100755 py3/functional/decorator.py create mode 100755 py3/functional/do_filter.py create mode 100755 py3/functional/do_partial.py create mode 100755 py3/functional/do_reduce.py create mode 100755 py3/functional/do_sorted.py create mode 100755 py3/functional/return_func.py create mode 100755 py3/io/file.py diff --git a/.gitignore b/.gitignore index ded6067..43df6b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ *.py[cod] +test.db +test.txt + # C extensions *.so diff --git a/py3/commonlib/do_base64.py b/py3/commonlib/do_base64.py new file mode 100755 index 0000000..b3e4df2 --- /dev/null +++ b/py3/commonlib/do_base64.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import base64 + +s = base64.b64encode('在Python中使用BASE 64编码'.encode('utf-8')) +print(s) +d = base64.b64decode(s).decode('utf-8') +print(d) + +s = base64.urlsafe_b64encode('在Python中使用BASE 64编码'.encode('utf-8')) +print(s) +d = base64.urlsafe_b64decode(s).decode('utf-8') +print(d) diff --git a/py3/coroutine/async_hello.py b/py3/coroutine/async_hello.py new file mode 100755 index 0000000..f323c48 --- /dev/null +++ b/py3/coroutine/async_hello.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import asyncio + +@asyncio.coroutine +def hello(): + print("Hello world!") + yield from asyncio.sleep(1) + print("Hello again!") + +loop = asyncio.get_event_loop() +loop.run_until_complete(hello()) +loop.close() diff --git a/py3/db/do_sqlite.py b/py3/db/do_sqlite.py new file mode 100755 index 0000000..dd36b7e --- /dev/null +++ b/py3/db/do_sqlite.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sqlite3 + +# 连接到SQLite数据库 +# 数据库文件是test.db +# 如果文件不存在,会自动在当前目录创建: +conn = sqlite3.connect('test.db') +# 创建一个Cursor: +cursor = conn.cursor() +# 执行一条SQL语句,创建user表: +cursor.execute('create table user (id varchar(20) primary key, name varchar(20))') +# 继续执行一条SQL语句,插入一条记录: +cursor.execute('insert into user (id, name) values (\'1\', \'Michael\')') +# 通过rowcount获得插入的行数: +print('rowcount =', cursor.rowcount) +# 关闭Cursor: +cursor.close() +# 提交事务: +conn.commit() +# 关闭Connection: +conn.close() + +# 查询记录: +conn = sqlite3.connect('test.db') +cursor = conn.cursor() +# 执行查询语句: +cursor.execute('select * from user where id=?', '1') +# 获得查询结果集: +values = cursor.fetchall() +print(values) +cursor.close() +conn.close() diff --git a/py3/debug/do_try.py b/py3/debug/do_try.py new file mode 100755 index 0000000..9133856 --- /dev/null +++ b/py3/debug/do_try.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +try: + print('try...') + r = 10 / 0 + print('result:', r) +except ZeroDivisionError as e: + print('except:', e) +finally: + print('finally...') +print('END') diff --git a/py3/functional/decorator.py b/py3/functional/decorator.py new file mode 100755 index 0000000..938bedf --- /dev/null +++ b/py3/functional/decorator.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import functools + +def log(func): + @functools.wraps(func) + def wrapper(*args, **kw): + print('call %s():' % func.__name__) + return func(*args, **kw) + return wrapper + +@log +def now(): + print('2015-3-25') + +now() + +def logger(text): + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kw): + print('%s %s():' % (text, func.__name__)) + return func(*args, **kw) + return wrapper + return decorator + +@logger('DEBUG') +def today(): + print('2015-3-25') + +today() +print(today.__name__) diff --git a/py3/functional/do_filter.py b/py3/functional/do_filter.py new file mode 100755 index 0000000..8a9081c --- /dev/null +++ b/py3/functional/do_filter.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def is_odd(n): + return n % 2 == 1 + +L = range(100) + +print(list(filter(is_odd, L))) + +def not_empty(s): + return s and s.strip() + +print(list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))) diff --git a/py3/functional/do_partial.py b/py3/functional/do_partial.py new file mode 100755 index 0000000..05da7b6 --- /dev/null +++ b/py3/functional/do_partial.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import functools + +int2 = functools.partial(int, base=2) + +print('1000000 =', int2('1000000')) +print('1010101 =', int2('1010101')) diff --git a/py3/functional/do_reduce.py b/py3/functional/do_reduce.py new file mode 100755 index 0000000..b1475bd --- /dev/null +++ b/py3/functional/do_reduce.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from functools import reduce + +CHAR_TO_INT = { + '0': 0, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9 +} + +def str2int(s): + ints = map(lambda ch: CHAR_TO_INT[ch], s) + return reduce(lambda x, y: x * 10 + y, ints) + +print(str2int('0')) +print(str2int('12300')) +print(str2int('0012345')) diff --git a/py3/functional/do_sorted.py b/py3/functional/do_sorted.py new file mode 100755 index 0000000..7d7a0e8 --- /dev/null +++ b/py3/functional/do_sorted.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from operator import itemgetter + +L = ['bob', 'about', 'Zoo', 'Credit'] + +print(sorted(L)) +print(sorted(L, key=str.lower)) + +students = [ + ('Adam', 90), + ('Tim', 60), + ('Lisa', 80), + ('Bart', 60) +] + +print(sorted(students, key=itemgetter(1))) + +def student_to_key(t): + return '%+02d%s' % (100-t[1], t[0]) + +print(sorted(students, key=student_to_key)) diff --git a/py3/functional/return_func.py b/py3/functional/return_func.py new file mode 100755 index 0000000..147bd9f --- /dev/null +++ b/py3/functional/return_func.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def lazy_sum(*args): + def sum(): + ax = 0 + for n in args: + ax = ax + n + return ax + return sum + +f = lazy_sum(1, 2, 4, 5, 7, 8, 9) +print(f) +print(f()) + +# why f1(), f2(), f3() returns 9, 9, 9 rather than 1, 4, 9? +def count(): + fs = [] + for i in range(1, 4): + def f(): + return i * i + fs.append(f) + return fs + +f1, f2, f3 = count() + +print(f1()) +print(f2()) +print(f3()) + +# fix: +def count(): + fs = [] + def f(n): + def j(): + return n * n + return j + for i in range(1, 4): + fs.append(f(i)) + return fs + +f1, f2, f3 = count() + +print(f1()) +print(f2()) +print(f3()) diff --git a/py3/io/file.py b/py3/io/file.py new file mode 100755 index 0000000..003e92d --- /dev/null +++ b/py3/io/file.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from datetime import datetime + +with open('test.txt', 'w') as f: + f.write('今天是 ') + f.write(datetime.now().strftime('%Y-%m-%d')) + +with open('test.txt', 'r') as f: + s = f.read() + print('open for read...') + print(s) + +with open('test.txt', 'rb') as f: + s = f.read() + print('open as binary for read...') + print(s) From eccc8e9989517f602da6819dbbca2ed92332fa90 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Tue, 31 Mar 2015 13:23:13 +0800 Subject: [PATCH 05/44] add send_mail and regex --- py3/mail/send_mail.py | 28 ++++++++++++++++++++++++++++ py3/regex/regex.py | 13 +++++++++++++ 2 files changed, 41 insertions(+) create mode 100755 py3/mail/send_mail.py create mode 100755 py3/regex/regex.py diff --git a/py3/mail/send_mail.py b/py3/mail/send_mail.py new file mode 100755 index 0000000..be76c71 --- /dev/null +++ b/py3/mail/send_mail.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from email import encoders +from email.header import Header +from email.mime.text import MIMEText +from email.utils import parseaddr, formataddr +import smtplib + +def _format_addr(s): + name, addr = parseaddr(s) + return formataddr((Header(name, 'utf-8').encode(), addr)) + +from_addr = input('From: ') +password = input('Password: ') +to_addr = input('To: ') +smtp_server = input('SMTP server: ') + +msg = MIMEText('hello, send by Python...', 'plain', 'utf-8') +msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr) +msg['To'] = _format_addr('管理员 <%s>' % to_addr) +msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode() + +server = smtplib.SMTP(smtp_server, 25) +server.set_debuglevel(1) +server.login(from_addr, password) +server.sendmail(from_addr, [to_addr], msg.as_string()) +server.quit() diff --git a/py3/regex/regex.py b/py3/regex/regex.py new file mode 100755 index 0000000..89ef876 --- /dev/null +++ b/py3/regex/regex.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import re + +print('Test: 010-12345') +m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345') +print(m.group(1), m.group(2)) + +t = '19:05:30' +print('Test:', t) +m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t) +print(m.groups()) From 7bfdcdef14aaad308ba5a7f7de1ba056c66783b8 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 10:25:01 +0800 Subject: [PATCH 06/44] add unittest and doctest --- py3/test/dict_doctest.py | 41 +++++++++++++++++++++++++++++ py3/test/dict_test.py | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100755 py3/test/dict_doctest.py create mode 100755 py3/test/dict_test.py diff --git a/py3/test/dict_doctest.py b/py3/test/dict_doctest.py new file mode 100755 index 0000000..a0bc4ac --- /dev/null +++ b/py3/test/dict_doctest.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Dict(dict): + ''' + Simple dict but also support access as x.y style. + + >>> d1 = Dict() + >>> d1['x'] = 100 + >>> d1.x + 100 + >>> d1.y = 200 + >>> d1['y'] + 200 + >>> d2 = Dict(a=1, b=2, c='3') + >>> d2.c + '3' + >>> d2['empty'] + Traceback (most recent call last): + ... + KeyError: 'empty' + >>> d2.empty + Traceback (most recent call last): + ... + AttributeError: 'Dict' object has no attribute 'empty' + ''' + def __init__(self, **kw): + super(Dict, self).__init__(**kw) + + def __getattr__(self, key): + try: + return self[key] + except KeyError: + raise AttributeError(r"'Dict' object has no attribute '%s'" % key) + + def __setattr__(self, key, value): + self[key] = value + +if __name__=='__main__': + import doctest + doctest.testmod() diff --git a/py3/test/dict_test.py b/py3/test/dict_test.py new file mode 100755 index 0000000..ab550b1 --- /dev/null +++ b/py3/test/dict_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import unittest + +class Dict(dict): + + def __init__(self, **kw): + super(Dict, self).__init__(**kw) + + def __getattr__(self, key): + try: + return self[key] + except KeyError: + raise AttributeError(r"'Dict' object has no attribute '%s'" % key) + + def __setattr__(self, key, value): + self[key] = value + +class TestDict(unittest.TestCase): + + def setUp(self): + print('setUp...') + + def tearDown(self): + print('tearDown...') + + def test_init(self): + d = Dict(a=1, b='test') + self.assertEqual(d.a, 1) + self.assertEqual(d.b, 'test') + self.assertTrue(isinstance(d, dict)) + + def test_key(self): + d = Dict() + d['key'] = 'value' + self.assertEqual(d.key, 'value') + + def test_attr(self): + d = Dict() + d.key = 'value' + self.assertTrue('key' in d) + self.assertEqual(d['key'], 'value') + + def test_keyerror(self): + d = Dict() + with self.assertRaises(KeyError): + value = d['empty'] + + def test_attrerror(self): + d = Dict() + with self.assertRaises(AttributeError): + value = d.empty + +if __name__ == '__main__': + unittest.main() From 01ce72d7a5f0dd6f3b7f2e4e988616db17511e89 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 10:25:36 +0800 Subject: [PATCH 07/44] rename dict_test.py to dict_unittest.py --- py3/test/{dict_test.py => dict_unittest.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename py3/test/{dict_test.py => dict_unittest.py} (100%) diff --git a/py3/test/dict_test.py b/py3/test/dict_unittest.py similarity index 100% rename from py3/test/dict_test.py rename to py3/test/dict_unittest.py From 1dff390ab3d27def7503715dd7e219bf39318378 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 10:40:49 +0800 Subject: [PATCH 08/44] add list dir --- py3/io/do_dir.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100755 py3/io/do_dir.py diff --git a/py3/io/do_dir.py b/py3/io/do_dir.py new file mode 100755 index 0000000..dc80853 --- /dev/null +++ b/py3/io/do_dir.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from datetime import datetime +import os + +pwd = os.path.abspath('.') + +print(' Size Last Modified Name') +print('------------------------------------------------------------') + +for f in os.listdir(pwd): + fsize = os.path.getsize(f) + mtime = datetime.fromtimestamp(os.path.getmtime(f)).strftime('%Y-%m-%d %H:%M') + flag = '/' if os.path.isdir(f) else '' + print('%10d %s %s%s' % (fsize, mtime, f, flag)) From 4ec9ad83cfc250269332601726ef15f1e59443ad Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 10:50:10 +0800 Subject: [PATCH 09/44] add wsgi app --- py3/web/do_wsgi.py | 11 +++++++++++ py3/web/hello.py | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100755 py3/web/do_wsgi.py create mode 100644 py3/web/hello.py diff --git a/py3/web/do_wsgi.py b/py3/web/do_wsgi.py new file mode 100755 index 0000000..1e60a6b --- /dev/null +++ b/py3/web/do_wsgi.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from wsgiref.simple_server import make_server + +from hello import application + +httpd = make_server('', 8000, application) +print('Serving HTTP on port 8000...') + +httpd.serve_forever() diff --git a/py3/web/hello.py b/py3/web/hello.py new file mode 100644 index 0000000..3150c22 --- /dev/null +++ b/py3/web/hello.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def application(environ, start_response): + start_response('200 OK', [('Content-Type', 'text/html')]) + body = '

Hello, %s!

' % (environ['PATH_INFO'][1:] or 'web') + return [body.encode('utf-8')] From c54bfc11074017b4997e5b9edc0a142146c9cd66 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 10:58:23 +0800 Subject: [PATCH 10/44] add flask app --- py3/web/do_flask.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 py3/web/do_flask.py diff --git a/py3/web/do_flask.py b/py3/web/do_flask.py new file mode 100755 index 0000000..4f86584 --- /dev/null +++ b/py3/web/do_flask.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from flask import Flask +from flask import request + +app = Flask(__name__) + +@app.route('/', methods=['GET', 'POST']) +def home(): + return '

Home

' + +@app.route('/signin', methods=['GET']) +def signin_form(): + return '''
+

+

+

+
''' + +@app.route('/signin', methods=['POST']) +def signin(): + # 需要从request对象读取表单内容: + if request.form['username']=='admin' and request.form['password']=='password': + return '

Hello, admin!

' + return '

Bad username or password.

' + +if __name__ == '__main__': + app.run() From b001d0c418ccc51e4d3ecfe996d7e545037d494d Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 10:58:47 +0800 Subject: [PATCH 11/44] add flask app with jinja2 templates --- py3/web/mvc/app.py | 25 +++++++++++++++++++++++++ py3/web/mvc/templates/form.html | 16 ++++++++++++++++ py3/web/mvc/templates/home.html | 8 ++++++++ py3/web/mvc/templates/signin-ok.html | 8 ++++++++ 4 files changed, 57 insertions(+) create mode 100755 py3/web/mvc/app.py create mode 100644 py3/web/mvc/templates/form.html create mode 100644 py3/web/mvc/templates/home.html create mode 100644 py3/web/mvc/templates/signin-ok.html diff --git a/py3/web/mvc/app.py b/py3/web/mvc/app.py new file mode 100755 index 0000000..3431919 --- /dev/null +++ b/py3/web/mvc/app.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from flask import Flask, request, render_template + +app = Flask(__name__) + +@app.route('/', methods=['GET', 'POST']) +def home(): + return render_template('home.html') + +@app.route('/signin', methods=['GET']) +def signin_form(): + return render_template('form.html') + +@app.route('/signin', methods=['POST']) +def signin(): + username = request.form['username'] + password = request.form['password'] + if username=='admin' and password=='password': + return render_template('signin-ok.html', username=username) + return render_template('form.html', message='Bad username or password', username=username) + +if __name__ == '__main__': + app.run() diff --git a/py3/web/mvc/templates/form.html b/py3/web/mvc/templates/form.html new file mode 100644 index 0000000..316092a --- /dev/null +++ b/py3/web/mvc/templates/form.html @@ -0,0 +1,16 @@ + + + Please Sign In + + + {% if message %} +

{{ message }}

+ {% endif %} +
+ Please sign in: +

+

+

+
+ + diff --git a/py3/web/mvc/templates/home.html b/py3/web/mvc/templates/home.html new file mode 100644 index 0000000..a53b4af --- /dev/null +++ b/py3/web/mvc/templates/home.html @@ -0,0 +1,8 @@ + + + Home + + +

Home

+ + diff --git a/py3/web/mvc/templates/signin-ok.html b/py3/web/mvc/templates/signin-ok.html new file mode 100644 index 0000000..6187939 --- /dev/null +++ b/py3/web/mvc/templates/signin-ok.html @@ -0,0 +1,8 @@ + + + Welcome, {{ username }} + + +

Welcome, {{ username }}!

+ + From 87a225c25cac1c9d249d510791972fda71c2592b Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 11:31:45 +0800 Subject: [PATCH 12/44] add mysql sample --- py3/db/do_mysql.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100755 py3/db/do_mysql.py diff --git a/py3/db/do_mysql.py b/py3/db/do_mysql.py new file mode 100755 index 0000000..d1d1db8 --- /dev/null +++ b/py3/db/do_mysql.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +########## prepare ########## + +# install mysql-connector-python: +# pip3 install mysql-connector-python --allow-external mysql-connector-python + +import mysql.connector + +# change root password to yours: +conn = mysql.connector.connect(user='root', password='password', database='test') + +cursor = conn.cursor() +# 创建user表: +cursor.execute('create table user (id varchar(20) primary key, name varchar(20))') +# 插入一行记录,注意MySQL的占位符是%s: +cursor.execute('insert into user (id, name) values (%s, %s)', ('1', 'Michael')) +print('rowcount =', cursor.rowcount) +# 提交事务: +conn.commit() +cursor.close() + +# 运行查询: +cursor = conn.cursor() +cursor.execute('select * from user where id = %s', ('1',)) +values = cursor.fetchall() +print(values) +# 关闭Cursor和Connection: +cursor.close() +conn.close() From 723d4904a79b43f844abbd1b1b57520cbada7ece Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 12:30:45 +0800 Subject: [PATCH 13/44] add sqlalchemy sample --- py3/db/do_sqlalchemy.py | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 py3/db/do_sqlalchemy.py diff --git a/py3/db/do_sqlalchemy.py b/py3/db/do_sqlalchemy.py new file mode 100755 index 0000000..85f137d --- /dev/null +++ b/py3/db/do_sqlalchemy.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from sqlalchemy import Column, String, create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +# 创建对象的基类: +Base = declarative_base() + +# 定义User对象: +class User(Base): + # 表的名字: + __tablename__ = 'user' + + # 表的结构: + id = Column(String(20), primary_key=True) + name = Column(String(20)) + +# 初始化数据库连接: +engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test') +# 创建DBSession类型: +DBSession = sessionmaker(bind=engine) + +# 创建session对象: +session = DBSession() +# 创建新User对象: +new_user = User(id='5', name='Bob') +# 添加到session: +session.add(new_user) +# 提交即保存到数据库: +session.commit() +# 关闭session: +session.close() + +# 创建Session: +session = DBSession() +# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行: +user = session.query(User).filter(User.id=='5').one() +# 打印类型和对象的name属性: +print('type:', type(user)) +print('name:', user.name) +# 关闭Session: +session.close() From fe13d542a3e594e261c25ace7cdbe3fbf4603d52 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 12:46:19 +0800 Subject: [PATCH 14/44] add iter, gener and list compr --- py3/advance/do_generator.py | 19 ++++++++++++++++++ py3/advance/do_iter.py | 39 +++++++++++++++++++++++++++++++++++++ py3/advance/do_listcompr.py | 12 ++++++++++++ 3 files changed, 70 insertions(+) create mode 100755 py3/advance/do_generator.py create mode 100755 py3/advance/do_iter.py create mode 100755 py3/advance/do_listcompr.py diff --git a/py3/advance/do_generator.py b/py3/advance/do_generator.py new file mode 100755 index 0000000..90cb99c --- /dev/null +++ b/py3/advance/do_generator.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +g = (x * x for x in range(10)) +print(g) +for x in g: + print(x) + +def fib(max): + n, a, b = 0, 0, 1 + while n < max: + yield b + a, b = b, a + b + n = n + 1 + +f = fib(10) +print('fib(10):', f) +for x in f: + print(x) diff --git a/py3/advance/do_iter.py b/py3/advance/do_iter.py new file mode 100755 index 0000000..b70068e --- /dev/null +++ b/py3/advance/do_iter.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from collections import Iterable +print('iterable? [1, 2, 3]:', isinstance([1, 2, 3], Iterable)) +print('iterable? \'abc\':', isinstance('abc', Iterable)) +print('iterable? 123:', isinstance(123, Iterable)) + +# iter list: +print('iter [1, 2, 3, 4, 5]') +for x in [1, 2, 3, 4, 5]: + print(x) + +d = {'a': 1, 'b': 2, 'c': 3} + +# iter each key: +print('iter key:', d) +for k in d.keys(): + print('key:', k) + +# iter each value: +print('iter value:', d) +for v in d.values(): + print('value:', v) + +# iter both key and value: +print('iter item:', d) +for k, v in d.items(): + print('item:', k, v) + +# iter list with index: +print('iter enumerate([\'A\', \'B\', \'C\']') +for i, value in enumerate(['A', 'B', 'C']): + print(i, value) + +# iter complex list: +print('iter [(1, 1), (2, 4), (3, 9)]:') +for x, y in [(1, 1), (2, 4), (3, 9)]: + print(x, y) diff --git a/py3/advance/do_listcompr.py b/py3/advance/do_listcompr.py new file mode 100755 index 0000000..328d5c5 --- /dev/null +++ b/py3/advance/do_listcompr.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +print([x * x for x in range(1, 11)]) +print([x * x for x in range(1, 11) if x % 2 == 0]) +print([m + n for m in 'ABC' for n in 'XYZ']) + +d = {'x': 'A', 'y': 'B', 'z': 'C' } +print([k + '=' + v for k, v in d.items()]) + +L = ['Hello', 'World', 'IBM', 'Apple'] +print([s.lower() for s in L]) From dbea25a88a0756feaee8aad46e7d0f4844a5e5dd Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 12:51:07 +0800 Subject: [PATCH 15/44] add class definition --- py3/oop_basic/student.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 py3/oop_basic/student.py diff --git a/py3/oop_basic/student.py b/py3/oop_basic/student.py new file mode 100755 index 0000000..8a832ff --- /dev/null +++ b/py3/oop_basic/student.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + + def __init__(self, name, score): + self.name = name + self.score = score + + def print_score(self): + print('%s: %s' % (self.name, self.score)) + + def get_grade(self): + if self.score >= 90: + return 'A' + elif self.score >= 60: + return 'B' + else: + return 'C' + +bart = Student('Bart Simpson', 59) +lisa = Student('Lisa Simpson', 87) + +print('bart.name =', bart.name) +print('bart.score =', bart.score) +bart.print_score() + +print('grade of Bart:', bart.get_grade()) +print('grade of Lisa:', lisa.get_grade()) From 34865c0652b1b5366f9fe5092503d6d676c3ee1e Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 13:32:48 +0800 Subject: [PATCH 16/44] add logging, pdb, assert samples --- py3/debug/do_assert.py | 12 ++++++++++++ py3/debug/do_logging.py | 10 ++++++++++ py3/debug/do_pdb.py | 9 +++++++++ 3 files changed, 31 insertions(+) create mode 100755 py3/debug/do_assert.py create mode 100755 py3/debug/do_logging.py create mode 100755 py3/debug/do_pdb.py diff --git a/py3/debug/do_assert.py b/py3/debug/do_assert.py new file mode 100755 index 0000000..b94bd70 --- /dev/null +++ b/py3/debug/do_assert.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def foo(s): + n = int(s) + assert n != 0, 'n is zero!' + return 10 / n + +def main(): + foo('0') + +main() diff --git a/py3/debug/do_logging.py b/py3/debug/do_logging.py new file mode 100755 index 0000000..a4b9417 --- /dev/null +++ b/py3/debug/do_logging.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import logging +logging.basicConfig(level=logging.INFO) + +s = '0' +n = int(s) +logging.info('n = %d' % n) +print(10 / n) diff --git a/py3/debug/do_pdb.py b/py3/debug/do_pdb.py new file mode 100755 index 0000000..8e22883 --- /dev/null +++ b/py3/debug/do_pdb.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import pdb + +s = '0' +n = int(s) +pdb.set_trace() # 运行到这里会自动暂停 +print(10 / n) From 0ce9ce42b18b24009a10f349836a0ed49fa6873a Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 13:33:06 +0800 Subject: [PATCH 17/44] add oop basic samples --- py3/oop_basic/animals.py | 32 +++++++++++++++++++++++++++ py3/oop_basic/attrs.py | 25 +++++++++++++++++++++ py3/oop_basic/get_instance.py | 30 +++++++++++++++++++++++++ py3/oop_basic/get_type.py | 14 ++++++++++++ py3/oop_basic/protected_student.py | 35 ++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100755 py3/oop_basic/animals.py create mode 100755 py3/oop_basic/attrs.py create mode 100755 py3/oop_basic/get_instance.py create mode 100755 py3/oop_basic/get_type.py create mode 100755 py3/oop_basic/protected_student.py diff --git a/py3/oop_basic/animals.py b/py3/oop_basic/animals.py new file mode 100755 index 0000000..e2153ea --- /dev/null +++ b/py3/oop_basic/animals.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Animal(object): + def run(self): + print('Animal is running...') + +class Dog(Animal): + def run(self): + print('Dog is running...') + +class Cat(Animal): + def run(self): + print('Cat is running...') + +def run_twice(animal): + animal.run() + animal.run() + +a = Animal() +d = Dog() +c = Cat() + +print('a is Animal?', isinstance(a, Animal)) +print('a is Dog?', isinstance(a, Dog)) +print('a is Cat?', isinstance(a, Cat)) + +print('d is Animal?', isinstance(d, Animal)) +print('d is Dog?', isinstance(d, Dog)) +print('d is Cat?', isinstance(d, Cat)) + +run_twice(c) diff --git a/py3/oop_basic/attrs.py b/py3/oop_basic/attrs.py new file mode 100755 index 0000000..1f8462d --- /dev/null +++ b/py3/oop_basic/attrs.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class MyObject(object): + + def __init__(self): + self.x = 9 + + def power(self): + return self.x * self.x + +obj = MyObject() + +print('hasattr(obj, \'x\') =', hasattr(obj, 'x')) # 有属性'x'吗? +print('hasattr(obj, \'y\') =', hasattr(obj, 'y')) # 有属性'y'吗? +setattr(obj, 'y', 19) # 设置一个属性'y' +print('hasattr(obj, \'y\') =', hasattr(obj, 'y')) # 有属性'y'吗? +print('getattr(obj, \'y\') =', getattr(obj, 'y')) # 获取属性'y' +print('obj.y =', obj.y) # 获取属性'y' + +print('getattr(obj, \'z\') =',getattr(obj, 'z', 404)) # 获取属性'z',如果不存在,返回默认值404 + +f = getattr(obj, 'power') # 获取属性'power' +print(f) +print(f()) diff --git a/py3/oop_basic/get_instance.py b/py3/oop_basic/get_instance.py new file mode 100755 index 0000000..e2e2c92 --- /dev/null +++ b/py3/oop_basic/get_instance.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Animal(object): + pass + +class Dog(Animal): + pass + +class Husky(Dog): + pass + +a = Animal() +d = Dog() +h = Husky() + +print('check a = Animal()...') +print('isinstance(a, Animal) =', isinstance(a, Animal)) +print('isinstance(a, Dog) =', isinstance(a, Dog)) +print('isinstance(a, Husky) =', isinstance(a, Husky)) + +print('check d = Dog()...') +print('isinstance(d, Animal) =', isinstance(d, Animal)) +print('isinstance(d, Dog) =', isinstance(d, Dog)) +print('isinstance(d, Husky) =', isinstance(d, Husky)) + +print('check h = Husky()...') +print('isinstance(h, Animal) =', isinstance(h, Animal)) +print('isinstance(h, Dog) =', isinstance(h, Dog)) +print('isinstance(h, Husky) =', isinstance(h, Husky)) diff --git a/py3/oop_basic/get_type.py b/py3/oop_basic/get_type.py new file mode 100755 index 0000000..ae079e6 --- /dev/null +++ b/py3/oop_basic/get_type.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# type() + +print('type(123) =', type(123)) +print('type(\'123\') =', type('123')) +print('type(None) =', type(None)) +print('type(abs) =', type(abs)) + +import types + +print('type(\'abc\')==str?', type('abc')==str) + diff --git a/py3/oop_basic/protected_student.py b/py3/oop_basic/protected_student.py new file mode 100755 index 0000000..6d67a71 --- /dev/null +++ b/py3/oop_basic/protected_student.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + + def __init__(self, name, score): + self.__name = name + self.__score = score + + def get_name(self): + return self.__name + + def get_score(self): + return self.__score + + def set_score(self, score): + if 0 <= score <= 100: + self.__score = score + else: + raise ValueError('bad score') + + def get_grade(self): + if self.__score >= 90: + return 'A' + elif self.__score >= 60: + return 'B' + else: + return 'C' + +bart = Student('Bart Simpson', 59) +print('bart.get_name() =', bart.get_name()) +bart.set_score(60) +print('bart.get_score() =', bart.get_score()) + +print('DO NOT use bart._Student__name:', bart._Student__name) From a435e631704789a50000492830c98979324834f5 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 13:33:26 +0800 Subject: [PATCH 18/44] add slots sample --- py3/oop_advance/use_slots.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 py3/oop_advance/use_slots.py diff --git a/py3/oop_advance/use_slots.py b/py3/oop_advance/use_slots.py new file mode 100755 index 0000000..ff98c2f --- /dev/null +++ b/py3/oop_advance/use_slots.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称 + +class GraduateStudent(Student): + pass + +s = Student() # 创建新的实例 +s.name = 'Michael' # 绑定属性'name' +s.age = 25 # 绑定属性'age' +# ERROR: AttributeError: 'Student' object has no attribute 'score' +try: + s.score = 99 +except AttributeError as e: + print('AttributeError:', e) + +g = GraduateStudent() +g.score = 99 +print('g.score =', g.score) From 2ac43de992b8c4522d509dfc0dc181b2c5918b0e Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 13:47:47 +0800 Subject: [PATCH 19/44] add magic methods --- py3/oop_advance/special_call.py | 12 ++++++++++++ py3/oop_advance/special_getattr.py | 21 +++++++++++++++++++++ py3/oop_advance/special_getitem.py | 30 ++++++++++++++++++++++++++++++ py3/oop_advance/special_iter.py | 19 +++++++++++++++++++ py3/oop_advance/special_str.py | 14 ++++++++++++++ py3/oop_advance/use_property.py | 22 ++++++++++++++++++++++ 6 files changed, 118 insertions(+) create mode 100755 py3/oop_advance/special_call.py create mode 100755 py3/oop_advance/special_getattr.py create mode 100755 py3/oop_advance/special_getitem.py create mode 100755 py3/oop_advance/special_iter.py create mode 100755 py3/oop_advance/special_str.py create mode 100755 py3/oop_advance/use_property.py diff --git a/py3/oop_advance/special_call.py b/py3/oop_advance/special_call.py new file mode 100755 index 0000000..7fc27f7 --- /dev/null +++ b/py3/oop_advance/special_call.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + def __init__(self, name): + self.name = name + + def __call__(self): + print('My name is %s.' % self.name) + +s = Student('Michael') +s() diff --git a/py3/oop_advance/special_getattr.py b/py3/oop_advance/special_getattr.py new file mode 100755 index 0000000..930141a --- /dev/null +++ b/py3/oop_advance/special_getattr.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + + def __init__(self): + self.name = 'Michael' + + def __getattr__(self, attr): + if attr=='score': + return 99 + if attr=='age': + return lambda: 25 + raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr) + +s = Student() +print(s.name) +print(s.score) +print(s.age()) +# AttributeError: 'Student' object has no attribute 'grade' +print(s.grade) diff --git a/py3/oop_advance/special_getitem.py b/py3/oop_advance/special_getitem.py new file mode 100755 index 0000000..19f5bcd --- /dev/null +++ b/py3/oop_advance/special_getitem.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Fib(object): + + def __getitem__(self, n): + if isinstance(n, int): + a, b = 1, 1 + for x in range(n): + a, b = b, a + b + return a + if isinstance(n, slice): + start = n.start + stop = n.stop + if start is None: + start = 0 + a, b = 1, 1 + L = [] + for x in range(stop): + if x >= start: + L.append(a) + a, b = b, a + b + return L + +f = Fib() +print(f[0]) +print(f[5]) +print(f[100]) +print(f[0:5]) +print(f[:10]) diff --git a/py3/oop_advance/special_iter.py b/py3/oop_advance/special_iter.py new file mode 100755 index 0000000..90e1f8f --- /dev/null +++ b/py3/oop_advance/special_iter.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Fib(object): + + def __init__(self): + self.a, self.b = 0, 1 # 初始化两个计数器a,b + + def __iter__(self): + return self # 实例本身就是迭代对象,故返回自己 + + def __next__(self): + self.a, self.b = self.b, self.a + self.b # 计算下一个值 + if self.a > 100000: # 退出循环的条件 + raise StopIteration(); + return self.a # 返回下一个值 + +for n in Fib(): + print(n) diff --git a/py3/oop_advance/special_str.py b/py3/oop_advance/special_str.py new file mode 100755 index 0000000..1071b69 --- /dev/null +++ b/py3/oop_advance/special_str.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + + def __init__(self, name): + self.name = name + + def __str__(self): + return 'Student object (name: %s)' % self.name + + __repr__ = __str__ + +print(Student('Michael')) diff --git a/py3/oop_advance/use_property.py b/py3/oop_advance/use_property.py new file mode 100755 index 0000000..9edcb02 --- /dev/null +++ b/py3/oop_advance/use_property.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class Student(object): + + @property + def score(self): + return self._score + + @score.setter + def score(self, value): + if not isinstance(value, int): + raise ValueError('score must be an integer!') + if value < 0 or value > 100: + raise ValueError('score must between 0 ~ 100!') + self._score = value + +s = Student() +s.score = 60 +print('s.score =', s.score) +# ValueError: score must between 0 ~ 100! +s.score = 9999 From 32347c199cc1559132cd3faf816c02f79a38f113 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 14:00:19 +0800 Subject: [PATCH 20/44] add metaclass samples --- py3/oop_advance/create_class_on_the_fly.py | 13 ++++ py3/oop_advance/orm.py | 77 ++++++++++++++++++++++ py3/oop_advance/use_metaclass.py | 19 ++++++ 3 files changed, 109 insertions(+) create mode 100755 py3/oop_advance/create_class_on_the_fly.py create mode 100755 py3/oop_advance/orm.py create mode 100755 py3/oop_advance/use_metaclass.py diff --git a/py3/oop_advance/create_class_on_the_fly.py b/py3/oop_advance/create_class_on_the_fly.py new file mode 100755 index 0000000..3897023 --- /dev/null +++ b/py3/oop_advance/create_class_on_the_fly.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def fn(self, name='world'): # 先定义函数 + print('Hello, %s.' % name) + +Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class + +h = Hello() +print('call h.hello():') +h.hello() +print('type(Hello) =', type(Hello)) +print('type(h) =', type(h)) diff --git a/py3/oop_advance/orm.py b/py3/oop_advance/orm.py new file mode 100755 index 0000000..11899b3 --- /dev/null +++ b/py3/oop_advance/orm.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +' Simple ORM using metaclass ' + +class Field(object): + + def __init__(self, name, column_type): + self.name = name + self.column_type = column_type + + def __str__(self): + return '<%s:%s>' % (self.__class__.__name__, self.name) + +class StringField(Field): + + def __init__(self, name): + super(StringField, self).__init__(name, 'varchar(100)') + +class IntegerField(Field): + + def __init__(self, name): + super(IntegerField, self).__init__(name, 'bigint') + +class ModelMetaclass(type): + + def __new__(cls, name, bases, attrs): + if name=='Model': + return type.__new__(cls, name, bases, attrs) + print('Found model: %s' % name) + mappings = dict() + for k, v in attrs.items(): + if isinstance(v, Field): + print('Found mapping: %s ==> %s' % (k, v)) + mappings[k] = v + for k in mappings.keys(): + attrs.pop(k) + attrs['__mappings__'] = mappings # 保存属性和列的映射关系 + attrs['__table__'] = name # 假设表名和类名一致 + return type.__new__(cls, name, bases, attrs) + +class Model(dict, metaclass=ModelMetaclass): + + def __init__(self, **kw): + super(Model, self).__init__(**kw) + + def __getattr__(self, key): + try: + return self[key] + except KeyError: + raise AttributeError(r"'Model' object has no attribute '%s'" % key) + + def __setattr__(self, key, value): + self[key] = value + + def save(self): + fields = [] + params = [] + args = [] + for k, v in self.__mappings__.items(): + fields.append(v.name) + params.append('?') + args.append(getattr(self, k, None)) + sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params)) + print('SQL: %s' % sql) + print('ARGS: %s' % str(args)) + +# testing code: + +class User(Model): + id = IntegerField('id') + name = StringField('username') + email = StringField('email') + password = StringField('password') + +u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') +u.save() diff --git a/py3/oop_advance/use_metaclass.py b/py3/oop_advance/use_metaclass.py new file mode 100755 index 0000000..b0e9d6b --- /dev/null +++ b/py3/oop_advance/use_metaclass.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# metaclass是创建类,所以必须从`type`类型派生: +class ListMetaclass(type): + def __new__(cls, name, bases, attrs): + attrs['add'] = lambda self, value: self.append(value) + return type.__new__(cls, name, bases, attrs) + +# 指示使用ListMetaclass来定制类 +class MyList(list, metaclass=ListMetaclass): + pass + +L = MyList() +L.add(1) +L.add(2) +L.add(3) +L.add('END') +print(L) From 38624c31dfd241878da3b083faeca0f62ff73c99 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 14:12:38 +0800 Subject: [PATCH 21/44] add pickle and json samples --- py3/io/use_json.py | 26 ++++++++++++++++++++++++++ py3/io/use_pickle.py | 11 +++++++++++ 2 files changed, 37 insertions(+) create mode 100755 py3/io/use_json.py create mode 100755 py3/io/use_pickle.py diff --git a/py3/io/use_json.py b/py3/io/use_json.py new file mode 100755 index 0000000..5e3c708 --- /dev/null +++ b/py3/io/use_json.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json + +d = dict(name='Bob', age=20, score=88) +data = json.dumps(d) +print('JSON Data is a str:', data) +reborn = json.loads(data) +print(reborn) + +class Student(object): + + def __init__(self, name, age, score): + self.name = name + self.age = age + self.score = score + + def __str__(self): + return 'Student object (%s, %s, %s)' % (self.name, self.age, self.score) + +s = Student('Bob', 20, 88) +std_data = json.dumps(s, default=lambda obj: obj.__dict__) +print('Dump Student:', std_data) +rebuild = json.loads(std_data, object_hook=lambda d: Student(d['name'], d['age'], d['score'])) +print(rebuild) diff --git a/py3/io/use_pickle.py b/py3/io/use_pickle.py new file mode 100755 index 0000000..d14eba9 --- /dev/null +++ b/py3/io/use_pickle.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import pickle + +d = dict(name='Bob', age=20, score=88) +data = pickle.dumps(d) +print(data) + +reborn = pickle.loads(data) +print(reborn) From f58e9ea230d8e6c8d6006b3fd8a585d4ae473305 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 14:40:28 +0800 Subject: [PATCH 22/44] add struct, collections and hashlib sample --- py3/commonlib/check_bmp.py | 8 ++++++++ py3/commonlib/use_collections.py | 28 ++++++++++++++++++++++++++++ py3/commonlib/use_hashlib.py | 13 +++++++++++++ 3 files changed, 49 insertions(+) create mode 100755 py3/commonlib/check_bmp.py create mode 100755 py3/commonlib/use_collections.py create mode 100755 py3/commonlib/use_hashlib.py diff --git a/py3/commonlib/check_bmp.py b/py3/commonlib/check_bmp.py new file mode 100755 index 0000000..f55c1f6 --- /dev/null +++ b/py3/commonlib/check_bmp.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import struct + +bmp_header = b'\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00' + +print(struct.unpack(' Date: Wed, 1 Apr 2015 16:02:28 +0800 Subject: [PATCH 23/44] add datetime, itertools and sax --- py3/commonlib/use_datetime.py | 40 ++++++++++++++++++++++++++++++++++ py3/commonlib/use_itertools.py | 18 +++++++++++++++ py3/commonlib/use_sax.py | 28 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100755 py3/commonlib/use_datetime.py create mode 100755 py3/commonlib/use_itertools.py create mode 100755 py3/commonlib/use_sax.py diff --git a/py3/commonlib/use_datetime.py b/py3/commonlib/use_datetime.py new file mode 100755 index 0000000..625fad8 --- /dev/null +++ b/py3/commonlib/use_datetime.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from datetime import datetime, timedelta, timezone + +# 获取当前datetime: +now = datetime.now() +print('now =', now) +print('type(now) =', type(now)) + +# 用指定日期时间创建datetime: +dt = datetime(2015, 4, 19, 12, 20) +print('dt =', dt) + +# 把datetime转换为timestamp: +print('datetime -> timestamp:', dt.timestamp()) + +# 把timestamp转换为datetime: +t = dt.timestamp() +print('timestamp -> datetime:', datetime.fromtimestamp(t)) +print('timestamp -> datetime as UTC+0:', datetime.utcfromtimestamp(t)) + +# 从str读取datetime: +cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S') +print('strptime:', cday) + +# 把datetime格式化输出: +print('strftime:', cday.strftime('%a, %b %d %H:%M')) + +# 对日期进行加减: +print('current datetime =', cday) +print('current + 10 hours =', cday + timedelta(hours=10)) +print('current - 1 day =', cday - timedelta(days=1)) +print('current + 2.5 days =', cday + timedelta(days=2, hours=12)) + +# 把时间从UTC+0时区转换为UTC+8: +utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc) +utc8_dt = utc_dt.astimezone(timezone(timedelta(hours=8))) +print('UTC+0:00 now =', utc_dt) +print('UTC+8:00 now =', utc8_dt) diff --git a/py3/commonlib/use_itertools.py b/py3/commonlib/use_itertools.py new file mode 100755 index 0000000..65a908c --- /dev/null +++ b/py3/commonlib/use_itertools.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import itertools + +natuals = itertools.count(1) +for n in natuals: + print(n) + if n >= 100: + break + +cs = itertools.cycle('ABC') +t = 10 +for c in cs: + print(c) + t = t - 1 + if t == 0: + break diff --git a/py3/commonlib/use_sax.py b/py3/commonlib/use_sax.py new file mode 100755 index 0000000..c8bb8ba --- /dev/null +++ b/py3/commonlib/use_sax.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from xml.parsers.expat import ParserCreate + +class DefaultSaxHandler(object): + def start_element(self, name, attrs): + print('sax:start_element: %s, attrs: %s' % (name, str(attrs))) + + def end_element(self, name): + print('sax:end_element: %s' % name) + + def char_data(self, text): + print('sax:char_data: %s' % text) + +xml = r''' +
    +
  1. Python
  2. +
  3. Ruby
  4. +
+''' + +handler = DefaultSaxHandler() +parser = ParserCreate() +parser.StartElementHandler = handler.start_element +parser.EndElementHandler = handler.end_element +parser.CharacterDataHandler = handler.char_data +parser.Parse(xml) From 99b8bd66eb1f8ef22986db61886b2d00c68754db Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 16:11:13 +0800 Subject: [PATCH 24/44] add htmlparser sample --- py3/commonlib/use_htmlparser.py | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 py3/commonlib/use_htmlparser.py diff --git a/py3/commonlib/use_htmlparser.py b/py3/commonlib/use_htmlparser.py new file mode 100755 index 0000000..29e7b1a --- /dev/null +++ b/py3/commonlib/use_htmlparser.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from html.parser import HTMLParser +from html.entities import name2codepoint + +class MyHTMLParser(HTMLParser): + + def handle_starttag(self, tag, attrs): + print('<%s>' % tag) + + def handle_endtag(self, tag): + print('' % tag) + + def handle_startendtag(self, tag, attrs): + print('<%s/>' % tag) + + def handle_data(self, data): + print(data) + + def handle_comment(self, data): + print('') + + def handle_entityref(self, name): + print('&%s;' % name) + + def handle_charref(self, name): + print('&#%s;' % name) + +parser = MyHTMLParser() +parser.feed(''' + + + +

Some html HTML tutorial...
END

+''') From a787f80c29207f720e9e59557cbf82f4f089ae98 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 16:19:30 +0800 Subject: [PATCH 25/44] add multi-process --- py3/multitask/do_folk.py | 12 +++++++++++ py3/multitask/do_queue.py | 34 ++++++++++++++++++++++++++++++ py3/multitask/multi_processing.py | 17 +++++++++++++++ py3/multitask/pooled_processing.py | 22 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100755 py3/multitask/do_folk.py create mode 100755 py3/multitask/do_queue.py create mode 100755 py3/multitask/multi_processing.py create mode 100755 py3/multitask/pooled_processing.py diff --git a/py3/multitask/do_folk.py b/py3/multitask/do_folk.py new file mode 100755 index 0000000..2cabba8 --- /dev/null +++ b/py3/multitask/do_folk.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os + +print('Process (%s) start...' % os.getpid()) +# Only works on Unix/Linux/Mac: +pid = os.fork() +if pid == 0: + print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) +else: + print('I (%s) just created a child process (%s).' % (os.getpid(), pid)) diff --git a/py3/multitask/do_queue.py b/py3/multitask/do_queue.py new file mode 100755 index 0000000..02a8ef8 --- /dev/null +++ b/py3/multitask/do_queue.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from multiprocessing import Process, Queue +import os, time, random + +# 写数据进程执行的代码: +def write(q): + print('Process to write: %s' % os.getpid()) + for value in ['A', 'B', 'C']: + print('Put %s to queue...' % value) + q.put(value) + time.sleep(random.random()) + +# 读数据进程执行的代码: +def read(q): + print('Process to read: %s' % os.getpid()) + while True: + value = q.get(True) + print('Get %s from queue.' % value) + +if __name__=='__main__': + # 父进程创建Queue,并传给各个子进程: + q = Queue() + pw = Process(target=write, args=(q,)) + pr = Process(target=read, args=(q,)) + # 启动子进程pw,写入: + pw.start() + # 启动子进程pr,读取: + pr.start() + # 等待pw结束: + pw.join() + # pr进程里是死循环,无法等待其结束,只能强行终止: + pr.terminate() diff --git a/py3/multitask/multi_processing.py b/py3/multitask/multi_processing.py new file mode 100755 index 0000000..3cb7660 --- /dev/null +++ b/py3/multitask/multi_processing.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from multiprocessing import Process +import os + +# 子进程要执行的代码 +def run_proc(name): + print('Run child process %s (%s)...' % (name, os.getpid())) + +if __name__=='__main__': + print('Parent process %s.' % os.getpid()) + p = Process(target=run_proc, args=('test',)) + print('Child process will start.') + p.start() + p.join() + print('Child process end.') diff --git a/py3/multitask/pooled_processing.py b/py3/multitask/pooled_processing.py new file mode 100755 index 0000000..97130f2 --- /dev/null +++ b/py3/multitask/pooled_processing.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from multiprocessing import Pool +import os, time, random + +def long_time_task(name): + print('Run task %s (%s)...' % (name, os.getpid())) + start = time.time() + time.sleep(random.random() * 3) + end = time.time() + print('Task %s runs %0.2f seconds.' % (name, (end - start))) + +if __name__=='__main__': + print('Parent process %s.' % os.getpid()) + p = Pool(4) + for i in range(5): + p.apply_async(long_time_task, args=(i,)) + print('Waiting for all subprocesses done...') + p.close() + p.join() + print('All subprocesses done.') From 3d77f04a6ce10201827d25976d804eb3d776dd2e Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 16:30:27 +0800 Subject: [PATCH 26/44] add lock, multithreading, threadlocal samples --- py3/multitask/do_lock.py | 33 ++++++++++++++++++++++++++++++++ py3/multitask/multi_threading.py | 20 +++++++++++++++++++ py3/multitask/use_threadlocal.py | 24 +++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100755 py3/multitask/do_lock.py create mode 100755 py3/multitask/multi_threading.py create mode 100755 py3/multitask/use_threadlocal.py diff --git a/py3/multitask/do_lock.py b/py3/multitask/do_lock.py new file mode 100755 index 0000000..23a3f1e --- /dev/null +++ b/py3/multitask/do_lock.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import time, threading + +# 假定这是你的银行存款: +balance = 0 +lock = threading.Lock() + +def change_it(n): + # 先存后取,结果应该为0: + global balance + balance = balance + n + balance = balance - n + +def run_thread(n): + for i in range(100000): + # 先要获取锁: + lock.acquire() + try: + # 放心地改吧: + change_it(n) + finally: + # 改完了一定要释放锁: + lock.release() + +t1 = threading.Thread(target=run_thread, args=(5,)) +t2 = threading.Thread(target=run_thread, args=(8,)) +t1.start() +t2.start() +t1.join() +t2.join() +print(balance) diff --git a/py3/multitask/multi_threading.py b/py3/multitask/multi_threading.py new file mode 100755 index 0000000..5da05de --- /dev/null +++ b/py3/multitask/multi_threading.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import time, threading + +# 新线程执行的代码: +def loop(): + print('thread %s is running...' % threading.current_thread().name) + n = 0 + while n < 5: + n = n + 1 + print('thread %s >>> %s' % (threading.current_thread().name, n)) + time.sleep(1) + print('thread %s ended.' % threading.current_thread().name) + +print('thread %s is running...' % threading.current_thread().name) +t = threading.Thread(target=loop, name='LoopThread') +t.start() +t.join() +print('thread %s ended.' % threading.current_thread().name) diff --git a/py3/multitask/use_threadlocal.py b/py3/multitask/use_threadlocal.py new file mode 100755 index 0000000..77c0c9c --- /dev/null +++ b/py3/multitask/use_threadlocal.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import threading + +# 创建全局ThreadLocal对象: +local_school = threading.local() + +def process_student(): + # 获取当前线程关联的student: + std = local_school.student + print('Hello, %s (in %s)' % (std, threading.current_thread().name)) + +def process_thread(name): + # 绑定ThreadLocal的student: + local_school.student = name + process_student() + +t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A') +t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B') +t1.start() +t2.start() +t1.join() +t2.join() From 1e1333be339edbdbc70feca66f049f3b161db1b3 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 16:39:55 +0800 Subject: [PATCH 27/44] add task master, worker sample --- py3/multitask/task_master.py | 38 ++++++++++++++++++++++++++++++++++++ py3/multitask/task_worker.py | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100755 py3/multitask/task_master.py create mode 100755 py3/multitask/task_worker.py diff --git a/py3/multitask/task_master.py b/py3/multitask/task_master.py new file mode 100755 index 0000000..c01bf71 --- /dev/null +++ b/py3/multitask/task_master.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import random, time, queue +from multiprocessing.managers import BaseManager + +# 发送任务的队列: +task_queue = queue.Queue() +# 接收结果的队列: +result_queue = queue.Queue() + +# 从BaseManager继承的QueueManager: +class QueueManager(BaseManager): + pass + +# 把两个Queue都注册到网络上, callable参数关联了Queue对象: +QueueManager.register('get_task_queue', callable=lambda: task_queue) +QueueManager.register('get_result_queue', callable=lambda: result_queue) +# 绑定端口5000, 设置验证码'abc': +manager = QueueManager(address=('', 5000), authkey=b'abc') +# 启动Queue: +manager.start() +# 获得通过网络访问的Queue对象: +task = manager.get_task_queue() +result = manager.get_result_queue() +# 放几个任务进去: +for i in range(10): + n = random.randint(0, 10000) + print('Put task %d...' % n) + task.put(n) +# 从result队列读取结果: +print('Try get results...') +for i in range(10): + r = result.get(timeout=10) + print('Result: %s' % r) +# 关闭: +manager.shutdown() +print('master exit.') diff --git a/py3/multitask/task_worker.py b/py3/multitask/task_worker.py new file mode 100755 index 0000000..6a18760 --- /dev/null +++ b/py3/multitask/task_worker.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import time, sys, queue +from multiprocessing.managers import BaseManager + +# 创建类似的QueueManager: +class QueueManager(BaseManager): + pass + +# 由于这个QueueManager只从网络上获取Queue,所以注册时只提供名字: +QueueManager.register('get_task_queue') +QueueManager.register('get_result_queue') + +# 连接到服务器,也就是运行taskmanager.py的机器: +server_addr = '127.0.0.1' +print('Connect to server %s...' % server_addr) +# 端口和验证码注意保持与taskmanager.py设置的完全一致: +m = QueueManager(address=(server_addr, 5000), authkey=b'abc') +# 从网络连接: +m.connect() +# 获取Queue的对象: +task = m.get_task_queue() +result = m.get_result_queue() +# 从task队列取任务,并把结果写入result队列: +for i in range(10): + try: + n = task.get(timeout=1) + print('run task %d * %d...' % (n, n)) + r = '%d * %d = %d' % (n, n, n*n) + time.sleep(1) + result.put(r) + except Queue.Empty: + print('task queue is empty.') +# 处理结束: +print('worker exit.') From f63c8549b463ea163ba6120b796442aea77bbfd6 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 16:49:29 +0800 Subject: [PATCH 28/44] add gui app sample --- py3/gui/hello_gui.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 py3/gui/hello_gui.py diff --git a/py3/gui/hello_gui.py b/py3/gui/hello_gui.py new file mode 100755 index 0000000..005a8a3 --- /dev/null +++ b/py3/gui/hello_gui.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from tkinter import * +import tkinter.messagebox as messagebox + +class Application(Frame): + def __init__(self, master=None): + Frame.__init__(self, master) + self.pack() + self.createWidgets() + + def createWidgets(self): + self.nameInput = Entry(self) + self.nameInput.pack() + self.alertButton = Button(self, text='Hello', command=self.hello) + self.alertButton.pack() + + def hello(self): + name = self.nameInput.get() or 'world' + messagebox.showinfo('Message', 'Hello, %s' % name) + +app = Application() +# 设置窗口标题: +app.master.title('Hello World') +# 主消息循环: +app.mainloop() From efc52c7550769ca1734694633c03154feef8d289 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 23:14:12 +0800 Subject: [PATCH 29/44] add tcp sample --- py3/network/do_tcp.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 py3/network/do_tcp.py diff --git a/py3/network/do_tcp.py b/py3/network/do_tcp.py new file mode 100755 index 0000000..73007d8 --- /dev/null +++ b/py3/network/do_tcp.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import socket + +# 创建一个socket: +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# 建立连接: +s.connect(('www.sina.com.cn', 80)) + +# 发送数据: +s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n') + +# 接收数据: +buffer = [] +while True: + # 每次最多接收1k字节: + d = s.recv(1024) + if d: + buffer.append(d) + else: + break + +data = b''.join(buffer) + +# 关闭连接: +s.close() + +header, html = data.split(b'\r\n\r\n', 1) +print(header.decode('utf-8')) +# 把接收的数据写入文件: +with open('sina.html', 'wb') as f: + f.write(html) From db303ae3c944eaf63f8dfa5c7eb5b1af32af5dbb Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 23:14:46 +0800 Subject: [PATCH 30/44] update git ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 43df6b5..0b7acd0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ test.db test.txt +sina.html # C extensions *.so From 5e1514c6a999f3c8ceb309b251a1240c77ba5478 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 23:16:34 +0800 Subject: [PATCH 31/44] rename to socket --- py3/{network => socket}/do_tcp.py | 1 + 1 file changed, 1 insertion(+) rename py3/{network => socket}/do_tcp.py (99%) diff --git a/py3/network/do_tcp.py b/py3/socket/do_tcp.py similarity index 99% rename from py3/network/do_tcp.py rename to py3/socket/do_tcp.py index 73007d8..c2bd1fc 100755 --- a/py3/network/do_tcp.py +++ b/py3/socket/do_tcp.py @@ -29,6 +29,7 @@ header, html = data.split(b'\r\n\r\n', 1) print(header.decode('utf-8')) + # 把接收的数据写入文件: with open('sina.html', 'wb') as f: f.write(html) From 8e468752cfd425ffe69ae3f64299cb965b69646c Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Wed, 1 Apr 2015 23:21:38 +0800 Subject: [PATCH 32/44] add udp sample --- py3/socket/udp_client.py | 14 ++++++++++++++ py3/socket/udp_server.py | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100755 py3/socket/udp_client.py create mode 100755 py3/socket/udp_server.py diff --git a/py3/socket/udp_client.py b/py3/socket/udp_client.py new file mode 100755 index 0000000..a795773 --- /dev/null +++ b/py3/socket/udp_client.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import socket + +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +for data in [b'Michael', b'Tracy', b'Sarah']: + # 发送数据: + s.sendto(data, ('127.0.0.1', 9999)) + # 接收数据: + print(s.recv(1024).decode('utf-8')) + +s.close() diff --git a/py3/socket/udp_server.py b/py3/socket/udp_server.py new file mode 100755 index 0000000..7f54915 --- /dev/null +++ b/py3/socket/udp_server.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import socket + +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +# 绑定端口: +s.bind(('127.0.0.1', 9999)) + +print('Bind UDP on 9999...') + +while True: + # 接收数据: + data, addr = s.recvfrom(1024) + print('Received from %s:%s.' % addr) + reply = 'Hello, %s!' % data.decode('utf-8') + s.sendto(reply.encode('utf-8'), addr) From 59d1de9afc7ba5bb51142629de3d5650b9e3b140 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Thu, 2 Apr 2015 10:23:58 +0800 Subject: [PATCH 33/44] add stringio and bytesio --- py3/io/do_bytesio.py | 16 ++++++++++++++++ py3/io/do_stringio.py | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100755 py3/io/do_bytesio.py create mode 100755 py3/io/do_stringio.py diff --git a/py3/io/do_bytesio.py b/py3/io/do_bytesio.py new file mode 100755 index 0000000..eb316bd --- /dev/null +++ b/py3/io/do_bytesio.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from io import BytesIO + +# write to BytesIO: +f = BytesIO() +f.write(b'hello') +f.write(b' ') +f.write(b'world!') +print(f.getvalue()) + +# read from BytesIO: +data = '人闲桂花落,夜静春山空。月出惊山鸟,时鸣春涧中。'.encode('utf-8') +f = BytesIO(data) +print(f.read()) diff --git a/py3/io/do_stringio.py b/py3/io/do_stringio.py new file mode 100755 index 0000000..dad4f99 --- /dev/null +++ b/py3/io/do_stringio.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from io import StringIO + +# write to StringIO: +f = StringIO() +f.write('hello') +f.write(' ') +f.write('world!') +print(f.getvalue()) + +# read from StringIO: +f = StringIO('水面细风生,\n菱歌慢慢声。\n客亭临小市,\n灯火夜妆明。') +while True: + s = f.readline() + if s == '': + break + print(s.strip()) From 1f1d535a9996dab0fda46c831a08dd7ba2cb53d7 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Thu, 2 Apr 2015 15:55:44 +0800 Subject: [PATCH 34/44] add async http client --- py3/coroutine/async_wget.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 py3/coroutine/async_wget.py diff --git a/py3/coroutine/async_wget.py b/py3/coroutine/async_wget.py new file mode 100755 index 0000000..3a9e6a5 --- /dev/null +++ b/py3/coroutine/async_wget.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import asyncio + +@asyncio.coroutine +def wget(host): + print('wget %s...' % host) + connect = asyncio.open_connection(host, 80) + reader, writer = yield from connect + header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host + writer.write(header.encode('utf-8')) + yield from writer.drain() + while True: + line = yield from reader.readline() + if line == b'\r\n': + break + print('%s header > %s' % (host, line.decode('utf-8').rstrip())) + # Ignore the body, close the socket + writer.close() + +loop = asyncio.get_event_loop() +tasks = [asyncio.async(wget(host)) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']] +for task in tasks: + loop.run_until_complete(task) +loop.close() From 565993ea394610bf384446e0f17848e3cd41ab52 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Thu, 2 Apr 2015 22:52:17 +0800 Subject: [PATCH 35/44] rename coroutine to async --- py3/{coroutine => async}/async_hello.py | 0 py3/{coroutine => async}/async_wget.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename py3/{coroutine => async}/async_hello.py (100%) rename py3/{coroutine => async}/async_wget.py (100%) diff --git a/py3/coroutine/async_hello.py b/py3/async/async_hello.py similarity index 100% rename from py3/coroutine/async_hello.py rename to py3/async/async_hello.py diff --git a/py3/coroutine/async_wget.py b/py3/async/async_wget.py similarity index 100% rename from py3/coroutine/async_wget.py rename to py3/async/async_wget.py From dc7a167a47082cf21af18ab8fca7fea89745d9c3 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Fri, 3 Apr 2015 10:07:31 +0800 Subject: [PATCH 36/44] add yield sample --- py3/advance/do_yield.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100755 py3/advance/do_yield.py diff --git a/py3/advance/do_yield.py b/py3/advance/do_yield.py new file mode 100755 index 0000000..b558f62 --- /dev/null +++ b/py3/advance/do_yield.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import random, math + +def rnd(count): + while count > 0: + count = count - 1 + r = random.randint(0, 100) + print('-- random number --') + # 返回随机数r: + yield r + # 代理返回tri(r)的yield,可能有很多次: + ok = yield from tri(r) + # 相当于: + # for x in tri(r): + # yield x + print('-- %s --' % ok) + return 'done' + +def tri(r): + yield r * r + yield r * r * r + # 相当于: raise StopIteration('ok') + return 'ok' + +def main(): + for x in rnd(3): + print(x) + +main() From ba8b99576c05d3249aa6e6d0babf70dc81a701c7 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Fri, 3 Apr 2015 10:07:58 +0800 Subject: [PATCH 37/44] display thread in coro --- py3/async/async_wget.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py3/async/async_wget.py b/py3/async/async_wget.py index 3a9e6a5..38b807c 100755 --- a/py3/async/async_wget.py +++ b/py3/async/async_wget.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +import threading import asyncio @asyncio.coroutine def wget(host): print('wget %s...' % host) + print('current thread: %s' % threading.current_thread()) connect = asyncio.open_connection(host, 80) reader, writer = yield from connect header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host @@ -24,3 +26,4 @@ def wget(host): for task in tasks: loop.run_until_complete(task) loop.close() +print('main thread: %s' % threading.current_thread()) From e9d9ef6c187378872c2f9477637e2c14dc5ecac0 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Fri, 3 Apr 2015 10:25:46 +0800 Subject: [PATCH 38/44] update generator --- py3/advance/do_generator.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/py3/advance/do_generator.py b/py3/advance/do_generator.py index 90cb99c..67cdc5d 100755 --- a/py3/advance/do_generator.py +++ b/py3/advance/do_generator.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -g = (x * x for x in range(10)) -print(g) -for x in g: +s = (x * x for x in range(5)) +print(s) +for x in s: print(x) def fib(max): @@ -12,8 +12,29 @@ def fib(max): yield b a, b = b, a + b n = n + 1 + return 'done' f = fib(10) print('fib(10):', f) for x in f: print(x) + +# call generator manually: +g = fib(5) +while 1: + try: + x = g.send(None) + print('g:', x) + except StopIteration as e: + print('Generator return value:', e.value) + break + +# call generator using iter: +i = iter(fib(5)) +while 1: + try: + r = next(i) + print('i:', r) + except StopIteration as e: + print('Generator return value:', e.value) + break From b491d693d8cf52b9ce941487a247c88a2ef0cd36 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Fri, 3 Apr 2015 10:26:10 +0800 Subject: [PATCH 39/44] add producer/consumer sample --- py3/advance/do_prod_cons.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 py3/advance/do_prod_cons.py diff --git a/py3/advance/do_prod_cons.py b/py3/advance/do_prod_cons.py new file mode 100755 index 0000000..c4a43d5 --- /dev/null +++ b/py3/advance/do_prod_cons.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import time + +def consumer(): + r = '' + while True: + n = yield r + if not n: + return + print('[CONSUMER] Consuming %s...' % n) + time.sleep(1) + r = '200 OK' + +def produce(c): + c.send(None) + n = 0 + while n < 5: + n = n + 1 + print('[PRODUCER] Producing %s...' % n) + r = c.send(n) + print('[PRODUCER] Consumer return: %s' % r) + c.close() + +c = consumer() +produce(c) From 06430830634e6fd68d701b2d260d8e065d91d0ca Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Fri, 3 Apr 2015 10:27:25 +0800 Subject: [PATCH 40/44] update git ignore --- .gitignore | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.gitignore b/.gitignore index 0b7acd0..2cc2704 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,20 @@ pip-log.txt .tox nosetests.xml +###################### +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db +dist +MANIFEST + # Translations *.mo From 88abcd873347178123b94322fb89f1c734c7e95a Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Sat, 4 Apr 2015 19:35:49 +0800 Subject: [PATCH 41/44] add contextlib samples --- py3/context/do_closing.py | 17 +++++++++++++++++ py3/context/do_suppress.py | 11 +++++++++++ py3/context/do_with.py | 14 ++++++++++++++ 3 files changed, 42 insertions(+) create mode 100755 py3/context/do_closing.py create mode 100755 py3/context/do_suppress.py create mode 100755 py3/context/do_with.py diff --git a/py3/context/do_closing.py b/py3/context/do_closing.py new file mode 100755 index 0000000..320f1f7 --- /dev/null +++ b/py3/context/do_closing.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from contextlib import contextmanager + +@contextmanager +def closing(fname): + f = None + try: + f = open(fname, 'r') + yield f + finally: + if f: + f.close() + +with closing('test.txt') as f: + print(f.read()) diff --git a/py3/context/do_suppress.py b/py3/context/do_suppress.py new file mode 100755 index 0000000..3a750c4 --- /dev/null +++ b/py3/context/do_suppress.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os + +from contextlib import suppress + +with suppress(FileNotFoundError): + os.remove('tempfile.1') + os.remove('tempfile.2') + os.remove('tempfile.3') diff --git a/py3/context/do_with.py b/py3/context/do_with.py new file mode 100755 index 0000000..073399e --- /dev/null +++ b/py3/context/do_with.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from contextlib import contextmanager + +@contextmanager +def log(name): + print('[%s] start...' % name) + yield + print('[%s] end.' % name) + +with log('DEBUG'): + print('Hello, world!') + print('Hello, Python!') From 475fd336bda2f9ad3818dbe18f7951936a275945 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Sat, 4 Apr 2015 20:45:53 +0800 Subject: [PATCH 42/44] add subprocess sample --- py3/multitask/do_subprocess.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 py3/multitask/do_subprocess.py diff --git a/py3/multitask/do_subprocess.py b/py3/multitask/do_subprocess.py new file mode 100755 index 0000000..4c8b9db --- /dev/null +++ b/py3/multitask/do_subprocess.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import subprocess + +print('$ nslookup www.python.org') +r = subprocess.call(['nslookup', 'www.python.org']) +print('Exit code:', r) + +print('$ nslookup') +p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) +output, err = p.communicate(b'set q=mx\npython.org\nexit\n') +print(output.decode('utf-8')) +print('Exit code:', p.returncode) From 808431634ca3954d871176c5a8781069e3e0dc20 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Sat, 4 Apr 2015 20:46:04 +0800 Subject: [PATCH 43/44] add enum sample --- py3/oop_advance/use_enum.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 py3/oop_advance/use_enum.py diff --git a/py3/oop_advance/use_enum.py b/py3/oop_advance/use_enum.py new file mode 100755 index 0000000..7d23b30 --- /dev/null +++ b/py3/oop_advance/use_enum.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from enum import Enum, unique + +@unique +class Weekday(Enum): + Sun = 0 + Mon = 1 + Tue = 2 + Wed = 3 + Thu = 4 + Fri = 5 + Sat = 6 + +day1 = Weekday.Mon + +print('day1 =', day1) +print('Weekday.Tue =', Weekday.Tue) +print('Weekday[\'Tue\'] =', Weekday['Tue']) +print('Weekday.Tue.value =', Weekday.Tue.value) +print('day1 == Weekday.Mon ?', day1 == Weekday.Mon) +print('day1 == Weekday.Tue ?', day1 == Weekday.Tue) +print('day1 == Weekday(1) ?', day1 == Weekday(1)) + +for name, member in Weekday.__members__.items(): + print(name, '=>', member) + +Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) + +for name, member in Month.__members__.items(): + print(name, '=>', member, ',', member.value) From ac2aadb95a801704aa37e0066d12bb8dae133e0a Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Sat, 25 Apr 2015 20:22:38 +0800 Subject: [PATCH 44/44] add prime numbers --- py3/functional/prime_numbers.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 py3/functional/prime_numbers.py diff --git a/py3/functional/prime_numbers.py b/py3/functional/prime_numbers.py new file mode 100755 index 0000000..e6a6a9e --- /dev/null +++ b/py3/functional/prime_numbers.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +def main(): + for n in primes(): + if n < 1000: + print(n) + else: + break + +def _odd_iter(): + n = 1 + while True: + n = n + 2 + yield n + +def _not_divisible(n): + return lambda x: x % n > 0 + +def primes(): + yield 2 + it = _odd_iter() + while True: + n = next(it) + yield n + it = filter(_not_divisible(n), it) + +if __name__ == '__main__': + main()