Python 001


Life is short, you need Python -- Bruce Eckel

why


有趣、可鼓捣

解决问题快速、有效

思路广、快乐多~

省手指头

Python 是一门好语言

content


  • 环境准备
  • 包管理
  • hello, python
  • 基本语法
  • 日常任务
  • sexy part
  • 心得体会
  • what's next

environment


  • 不要在 Windows 中使用 Python
  • 先看这里:python.org(注意:不是 .com)
  • 2 or 3,先从 2 开始吧,3 很快也要续上~
  • 安装
  • 包管理工具:brew / pacman / apt-get / yum ...
    
    手动编译: ./configure --prefix= && make && make install
    
    Dear ops 已经替我们装好了:/home/q/python27/bin/python
  • 如无必要,不要自己手动编译安装
  • 如果安装出现错误,不要逃跑!

package management


  • 标准库功能不全或不好用时需要安扩展
  • 操作系统包管理器中一般都有常用扩展
  • 手动安装:python setup.py install (注意:which)
  • pip
  • 操作系统包管理器安装 pip
    
    命令行:get-pip.py (f^cking GFW)
    
    手动安装:wget http://xxx/pip-a.b.c.tar.gz 然后
    python setup.py install
    
    pip 安装扩展:pip install abc
    
    安装时指定来源:pip install abc -i http://pypi.douban.com/simple

hello python

which python

export PATH=/home/q/python27/bin:$PATH

python -V

Python 2.7.6 (default, Dec 28 2013, 20:51:17)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'hello, world'
hello, world

$ python -c "print 'hello, world'"
hello, world


pip install ipython

pip install bpython
Python 做日常不需要 IDE
REPL + 编辑器 =『试代码』= 正确的打开方式

basic syntax -- getting help


>>> help(5)
Help on int object:
(etc etc)

>>> dir(5)
['__abs__', '__add__', ...]

>>> abs.__doc__
'abs(number) -> number

Return the absolute value of the argument.'

basic syntax -- data types

a_int = 1
a_float = 3.14159265358979323846
a_str = 'a'

a_str, b_str = 'a', "b" # 单双引号有区别吗?

a_bool = False
a_list = [2, 1, 'x', True]

a_tuple = (3, 5)
b_tuple = (3, )
is_c_a_tuple = (3)
# 我是注释:看看 c 是什么类型
t = type(is_c_a_tuple)
'''
我是多行注释
也可以当做文档字符串
同时也是多行字符串的表示,写 sql 用这个可以排版哦
比 java[script] 一坨加号爽多了
'''
print t

a_set = {3, 1, 3, 2}
a_dict = { 'a': 22, 4: 'bb', 'u': u'哦,差点忘了 unicode string' }

basic syntax -- flow control

rangelist = range(10)
>>> print rangelist
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for number in rangelist:
    # Check if number is one of
    # the numbers in the tuple.
    if number in (3, 4, 7, 9):
        break
    else:
        continue
else:
    # The "else" clause is optional and is
    # executed only if the loop didn't "break".
    pass # Do nothing

if rangelist[1] == 2:
    print "The second item (lists are 0-based) is 2"
elif rangelist[1] == 3:
    print "The second item (lists are 0-based) is 3"
else:
    print "Dunno"

while rangelist[1] == 1:
    pass

basic syntax -- function

# Same as def funcvar(x): return x + 1
funcvar = lambda x: x + 1
>>> print funcvar(1)
2

# an_int and a_string are optional, they have default values
# if one is not passed (2 and "A default string", respectively).
def passing_example(a_list, an_int=2, a_string="A default string"):
    a_list.append("A new item")
    an_int = 4
    return a_list, an_int, a_string

>>> my_list = [1, 2, 3]
>>> my_int = 10
>>> print passing_example(my_list, my_int)
([1, 2, 3, 'A new item'], 4, "A default string")
>>> my_list
[1, 2, 3, 'A new item']
>>> my_int
10

basic syntax -- exception

def some_function():
    try:
        # Division by zero raises an exception
        10 / 0
    except ZeroDivisionError:
        print "Oops, invalid."
    else:
        # Exception didn't occur, we're good.
        pass
    finally:
        # This is executed after the code block is run
        # and all exceptions have been handled, even
        # if a new exception is raised while handling.
        print "We're done with that."

>>> some_function()
Oops, invalid.
We're done with that.

basic syntax -- class

# We subclass from object to get a class.
class Human(object):

    # A class attribute. It is shared by all instances of this class
    species = "H. sapiens"

    # Basic initializer
    def __init__(self, name):
        # Assign the argument to the instance's name attribute
        self.name = name

    # An instance method. All methods take "self" as the first argument
    def say(self, msg):
        return "%s: %s" % (self.name, msg)

    # A class method is shared among all instances
    # They are called with the calling class as the first argument
    @classmethod
    def get_species(cls):
        return cls.species

    # A static method is called without a class or instance reference
    @staticmethod
    def grunt():
        return "*grunt*"


power

  • 数据抓取
  • ETL
  • web UI、API
  • 科学计算、统计、机器学习
  • 系统运维
  • 网络连接
  • 安全
  • 图像处理
  • 数据库、cache、队列管理
  • 各种开发、测试小工具
  • 各种其他生态系统的 wrapper

daily routines -- begin

 #!/usr/bin/env python
# coding=utf-8

import os
import sys


reload(sys)
sys.setdefaultencoding('utf-8')


pwd = os.path.dirname(os.path.abspath(__file__)) + '/'


def main():
    print 'hello python'


if __name__ == '__main__':
    main()

daily routines -- postgres

import psycopg2
import psycopg2.extras

def get_hs():
    con = psycopg2.connect(
        database = 'hotel',
        user = 'searcher',
        password = '''abcdefg1234567''',
        host = 'l-abc.def.com',
        port = 5435
    )
    return con

def get_cursor(con):
    return con.cursor(cursor_factory=psycopg2.extras.DictCursor)
con = get_hs()
cur = get_cursor(con)
try:
    cur.execute('begin')
    cur.execute('truncate table city_suggest_app_info')
    insert_sql = 'insert into city_suggest_app_info(city_id, citytag, app, app_info) values (%s, %s, %s, %s)'
    cur.executemany(insert_sql, rows)
    cur.execute('commit')
except:
    logger.error('something wrong')
    cur.execute('rollback')
finally:
    cur.close()
    con.close()

daily routines -- mysql

import pymysql

def get_hotel_hive():
    con = pymysql.connect(
        host='l-abc.def.com',
        port=3306,
        user='hotel_hive',
        passwd='xxx',
        db='hotel_hive',
        charset='utf8'
    )
    return con
con = get_hotel_hive()
cur = con.cursor(pymysql.cursors.DictCursor)

seq_score = {}
cur.execute("select seq, score from top_query_all where cityurl = 'chengdu' and server_tag = 'A' and query = '7天连锁' ")
for r in cur.fetchall():
    seq = r['seq']
    seq_score[seq] = r['score']
con.commit()
cur.close()
con.close()

daily routines -- http request

import requests

resp = requests.get('http://tuan.aaa.bbb.com/render/cityHotelCount.jsp')
jd = resp.json()

for city, count in jd['cities'].items():
    info = t.get(city)
    if not info:
        continue

    info['tuan']['weight'] = info['hs']['weight']
    info['tuan']['online_count'] = count


daily routines -- json

In [71]: import json

In [72]: d = {'a': '你好', '世界': 'b'}

In [73]: print json.dumps(d)
{"a": "\u4f60\u597d", "\u4e16\u754c": "b"}

In [74]: print json.dumps(d, ensure_ascii=False, indent=2, sort_keys=True)
{
  "a": "你好",
  "世界": "b"
}
In [77]: s = '{"ping":"pong", "a":3, "中文":"2014-05-19"}'

In [78]: jd = json.loads(s)

In [79]: for k, v in jd.items():
   ....:     print k, v, type(v)
   ....:
a 3 <type 'int'>
中文 2014-05-19 <type 'unicode'>
ping pong <type 'unicode'>

daily routines -- http server

python -m SimpleHTTPServer 8000

# 比较简单的文件传文件策略(网上可找到支持带上传的版本)
# pip install Flask

from flask import Flask
app = Flask(__name__)


@app.route("/")
def hello():
    return "Hello World!"


if __name__ == "__main__":
    app.run()

# $ python hello.py
# * Running on http://localhost:5000/


daily routines -- dev ops

from fabric.api import *
import datetime, time, re

env.user = 'gavin'

def h(h_str):
    p = re.compile('\[(\d+)-(\d+)\]')
    m = p.search(h_str)
    a = int(m.group(1))
    b = int(m.group(2))
    env.hosts = [re.sub(p, str(i), h_str) for i in range(a, b + 1)]

def r(cmd):
    run(cmd)

def s(cmd):
    sudo(cmd)

daily routines -- dev ops

@parallel
scripts = ['export_ctrip_view.sh', 'export_detail_click.sh']
with cd('/home/q/tools/bin'):
    for s in scripts:
        sudo('rm %s' % s)
        put('./%s' % s, s, use_sudo=True)
        sudo('chown root:root %s' % s)
    sudo('chmod a+x %s' % s)

@parallel
def add_group_and_user():
    sudo('groupadd hadoop_hotel')
    sudo('sudo useradd hadoop_hotel -g hadoop_hotel -M')
    sudo('sudo usermod -p "your_password" hadoop_hotel')
 fab -f fab.py h:h_str=l-pgstats[1-2].h.xxx r:cmd=uptime

daily routines -- dev ops

[inet_http_server]         ; inet (TCP) server disabled by default
port=*:8091        ; (ip_address:port specifier, *:port for all iface)
username=gavin              ; (default is no username (open server))
password=gavin               ; (default is no password (open server))

[program:head_image_sync]
command = /home/work/python27/bin/python /home/work/app/head_image_sync/web.py
directory = /home/work/app/head_image_sync/
autostart = true
autorestart = true
stderr_logfile = /home/work/app/head_image_sync/logs/stderr.log
stdout_logfile = /home/work/app/head_image_sync/logs/stdout.log

supervisord -f xxx.conf
supervisorctl start/stop/restart your_app
supervisorctl update/reload

daily routines -- misc

 def get_logger():
    level = logging.DEBUG
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(module)s[%(lineno)d] - %(funcName)s - %(message)s')

    logger = logging.getLogger(__name__)
    logger.setLevel(level)

    ch = logging.StreamHandler()
    ch.setLevel(level)
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    return logger

logger = get_logger()

sexy part -- list comprehension

a = [1, 2, 3]

b = [ i**2 for i in a ]
print b
[1, 4, 9]

c = { str(i) : i / 2.5 for i in a }

print c
{'1': 0.4, '3': 1.2, '2': 0.8}

d = { i**2 for i in [-1, 0, 1] }

print d
set([0, 1])



sexy part -- functional

a = [1, 3, 5]

b = map(str, a)
print b
['1', '3', '5']

c = reduce(lambda x, y: x + y, a)
print c
9

d = filter(lambda x: x > 2, a)
print d
[3, 5]

# python lambda 表达式,是从 Lisp 借用来的,可以用在任何需要函数的地方# 可以当做变量、参数

sexy part -- decorator

def memo(fn):
    cache = {}
    miss = object()

    def wrapper(*args):
        result = cache.get(args, miss)
        if result is miss:
            result = fn(*args)
            cache[args] = result
        return result

    return wrapper
@memo
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

sexy part -- with statement

file = open("/tmp/foo.txt")
try:
    data = file.read()
finally:
    file.close()
    
# ==> 有了 with

with open('output.txt', 'w') as f:
    f.write('Hi there!')

# 数据库、HTTP 连接之类的都可以,只要按 python 标准实现 context 管理

sexy part -- simplicity

# 一句话搞定一棵树
def tree(): 
    return collections.defaultdict(tree)

t = tree()
t['public']['static']['void']['main'] = 'hello world'

print json.dumps(t, indent=2)
{
  "public": {
    "static": {
      "void": {
        "main": "hello world"
      }
    }
  }
}

sexy part -- simplicity

it = itertools.product([1, 3], [2, 4])

it.next()
(1, 2)
it.next()
(1, 4)

it = itertools.combinations([3, 4, 5], 2)

it.next()
(3, 4)
it.next()
(3, 5)
it.next()
(4, 5)

sexy part -- zen

In [125]: 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!

sexy part -- zen

优美胜于丑陋(Python 以编写优美的代码为目标)

明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)

简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)

复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)

扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)

间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)

可读性很重要(优美的代码是可读的)

即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)

不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)

当存在多种可能,不要尝试去猜测

而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)

虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )

做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)

如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)

命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)

gotcha


    • Python 多用于鼓捣、多数都是浅尝辄止,但是很有乐
    • 有问题先 STFW & RTFM
    • 官方文档、华蟒邮件列表、stackoverflow、reddit 多逛逛。其他 nodejs、ruby 社区也没事儿逛逛
    • 亲身经历的烂坑争取深挖一下
    • 发挥想象力,有很多好玩的东西






Questions ?




Thank you !

Python 001

By songchao

Python 001

人生苦短,快来一起鼓捣 Python ~

  • 2,258