通過廖雪峯的Python2.7教程學習Python,此爲第二天。

Functional Programming

函數式編程

  • 變量可以指向函數
  • 函數名可以是變量
  • 函數可接收另一函數作爲變量
>>> abs(-9)
9
>>> abs
<built-in function abs>
>>> x = abs(-9)
>>>
>>> x
9
>>> f = abs
>>> f
<built-in function abs>
>>> f(-9)
9
>>> abs = 10
>>> abs(-10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>> exit()

將函數abs()作爲函數add()的參數

>>> def add(x,y,f):
...     return f(x)+f(y)
...
>>> add(-5,-6,abs)
11

map

map接收2個參數,一個是函數,一個是序列,將傳入的函數依次作用到序列的每個元素,並把結果作爲新的list返回

>>> def f(x):
...     return x * x
...
>>> map(f,[1,2,3,4,5])
[1, 4, 9, 16, 25]
>>>
>>> L = []
>>> for i in range(9):
...     i+=1
...     L.append(i*i)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81]

使用str()abs()函數

>>> map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])
['1', '2', '3', '4', '5', '6', '7', '8', '9']
>>> map(abs, [1, -2, 3, -4, 5, -6, 7, -8, 9])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

reduce

reduce把一個函數作用在一個序列上,該函數必須接收2個參數,reduce將結果與序列的下一個元素做累計計算

>>> def add(x,y):
...     return x + y
...
>>> reduce(add, [1,3,5,7,9])
25
>>>
>>> def fun(x,y):
...     return x * 10 + y
...
>>> reduce(fun,[1,3,5,7,9])
13579

將字符轉換成首字母大寫,其它字母小寫

>>> def aaa(x):
...     return x[0].upper() + x[1:].lower()
...
>>> map(aaa,['adam', 'LISA', 'barT'])
['Adam', 'Lisa', 'Bart']
>>>

filter

filter接收2個參數,一個是函數,一個是序列,將傳入的函數依次作用到序列的每個元素,並根據返回值(True或False)決定是否保留

保留奇數

>>> def is_odd(x):
...     return x % 2
...
>>> filter(is_odd,[1,2,3,4,5,6,7,8])
[1, 3, 5, 7]
>>>

Decorator

裝飾器:代碼運行期間動態增加功能

Partial function

functools.partial的作用是將函數的某些參數固定住,返回一個新的函數

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('100000')
32
>>> int2('100001')
33
>>>
>>> max2 = functools.partial(max, 10)
>>> max2(5,6,7)
10
>>>

Module

使用模塊的好處 * 提高代碼的可維護性 * 避免函數名與變量名衝突 * 爲避免模塊名衝突,通過包(Package)來組織模塊

每一個包目錄下須有__init__.py文件,可爲空文件,否則Python會將其當成普通目錄

導入模塊時可使用 *別名*,用於版本兼容,如模塊功能相同但名稱不同,如不同Python版本

通過import ... as ... 指定別名

try:
    import cStringIO as StringIO
except ImportError:
    import StringIO


try:
    import json
except ImportError:
    import simplejson as json

作用域:Python通過前綴_實現函數或變量是否公開,(public 或 private)

_abc, __abc不應被直接引用,但是類似於__xxxx__的特殊變量可被直接引用,如__author__, __name__

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def _private1(name):
    return 'Hello, %s' % name
def _private2(name):
    return 'Hi, %s' % name
def greeting(name):
    if len(name) > 3:
        return _private1(name)
    else:
        return _private2(name)

name = raw_input('Please input your name:')
print greeting(name)

不對外公開的函數以_開頭,可命名爲private

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def _private1(name):
    return 'Hello, %s' % name
def _private2(name):
    return 'Hi, %s' % name
def greeting(name):
    if len(name) > 3:
        return _private1(name)
    else:
        return _private2(name)

name = raw_input('Please input your name:')
print greeting(name)

Package Management

Python包管理工具pip,可用於安裝第三方庫

python-pip在EPEL源中

yum install epel-release
yum install python-pip
  • PIL(Python Imaging Library): 處理圖像
  • MySQL-python: MySQL驅動
  • numpy: 用於科學計算
  • Jinja2: 生成文本的模版工具

Python搜索目錄

>>> import sys
>>> sys.path
['', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/gtk-2.0', '/usr/lib/python2.7/site-packages']
>>> exit()

future

Python通過__future__模塊將下一個新版本的特性導入到當前版本,可在當前版本測試新特性。

>>> from __future__ import unicode_literals
>>> print '\'xxx\' is unicode?', isinstance('xxx', unicode)
'xxx' is unicode? True
>>> print 'u\'xxx\' is unicode?', isinstance(u'xxx', unicode)
u'xxx' is unicode? True
>>> print '\'xxx\' is str?', isinstance('xxx', str)
'xxx' is str? False
>>> print 'b\'xxx\' is str?', isinstance(b'xxx', str)
b'xxx' is str? True
>>>

Object Orient

面向對象

Python中所有的數據類型都可視爲對象,而面向對象中的類(Class)就是自定義的對象數據類型。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Student(object):
    def __init__(self,name,score):
        self.name = name
        self.score = int(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'

name = raw_input('Please input name:')
score = raw_input('Please input score:')

#調用類
result = Student(name,score)
result.print_score()
print result.get_grade()

Class & Instance

通過class定義類;後面緊跟 類名 ,通常首字母大寫;緊接着(object),表示該類繼承自哪個類。

可以給實例變量綁定屬性

__init__方法的第一個參數永遠是self,表示創建的實例本身。在__init__方法內部,可以把各種屬性綁定到self

如果有__init__方法,創建實例時,不能傳空的參數,須傳入與__init__方法匹配的參數,但self不需要傳,Python解釋器自己會把實例變量傳進去。

與普通函數相比,在 類中定義的函數,其第一個參數必須是self,且調用時不用傳遞該參數。

數據封裝

訪問限制

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Student(object):
    def __init__(self,name,score):
        self.__name = name
        self.__score = int(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'
    def get_name(self):
        return self.__name
    def get_score(self):
        return self.__score

name = raw_input('Please input name:')
score = raw_input('Please input score:')

result = Student(name,score)
result.print_score()
print result.get_grade()

在屬性的名稱前加兩個下劃線_,可保證內部屬性不被外部訪問。

Python中,實例的變量名如果以__開頭,就變成私有變量(private),只可內部訪問

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Student(object):
    def __init__(self,name,score):
        self.__name = name
        self.__score = int(score)
    def set_score(self,score):
        if 0 <= int(score) <= 100:
            self.__score = int(score)
        else:
            raise ValueError('bad 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'
    def get_name(self):
        return self.__name
    def get_score(self):
        return self.__score

name = raw_input('Please input name:')
score = raw_input('Please input score:')
newscore = raw_input('Please input newscore:')
result = Student(name,score)
print result.set_score(newscore)
result.print_score()
print result.get_grade()

Inherit & Polymorphism

繼承、多態

繼承

#名爲Animal的類
class Animal(object):
    def run(self):
        print 'Animal is running...'

#繼承自類Animal的Dog、Cat類
class Dog(Animal):
    pass

class Cat(Animal):
    pass

父類、子類,子類默認擁有父類的功能全部功能,如果子類有與父類中相同名稱的方法,子類方法覆蓋父類方法。代碼運行時,自動會調用子類的該方法,此爲 多態

Object info

  • 使用type()獲取對象類型
  • 使用isinstance()
>>> type(123)
<type 'int'>
>>> type('str')
<type 'str'>
>>> type('None')
<type 'str'>
>>> type(None)
<type 'NoneType'>
>>> type(True)
<type 'bool'>
>>> type(abs)
<type 'builtin_function_or_method'>
>>> type(123)==type(456)
True
>>> type('123')==type('abc')
True
>>> type(123)==type('abc')
False

通過導入模塊import判斷

>>> import types
>>> type('abc')==types.StringType
True
>>> type(u'abc')==types.StringType
False
>>> type(u'abc')==types.UnicodeType
True
>>> type([])==types.ListType
True
>>> type(str)==types.TypeType
True

所有類型的本身是TypeType

使用dir()可獲取一個對象的所有屬性和方法

>>> dir('ABC')
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>>
  • hasattr()
  • getattr()
  • setattr()

  • __slots__: 用於限制類的屬性,僅對當前類有效,對繼承的子類不起作用

  • @property

錯誤、調式和測試

try:
    print 'try...'
    r = 10 / 0
    print 'result:', r
except ZeroDivisionError, e:
    print 'except:', e
finally:
    print 'finally...'
print 'END'

assert 斷點 logging 日誌輸出

I/O

同步、異步I/O

  • open(): 打開文件
  • read(): 讀取文件內容(存儲在內存中)
  • close(): 關閉文件

使用try...finally...

print可把末尾的換行符去處

>>> try:
...     f = open('/tmp/test.txt','r')
...     print f.read()
... finally:
...     if f:
...             f.close()
...
Hello,world

>>>
  • readline(): 每次讀取一行數據
>>> f = open('/Users/michael/test.txt', 'w')
>>> f.write('Hello, world!')
>>> f.close()

使用with防止數據未寫入磁盤造成數據丟失

with open('/Users/michael/test.txt', 'w') as f:
    f.write('Hello, world!')
#!/usr/bin/env python
# -*- coding: utf-8 -*-

path = raw_input('Please input file path:')

try:
    f = open(path,'r')
    for line in f.readlines():
        #去除換行符
        print line.strip()
finally:
    if f:
        f.close()

file and dir

通過調用os模塊實現相關功能

>>> import os
>>> os.name
'posix'
>>> os.uname()
('Linux', 'lemp', '3.10.0-327.10.1.el7.x86_64', '#1 SMP Tue Feb 16 17:03:50 UTC 2016', 'x86_64')
>>> os.uname()[2]
'3.10.0-327.10.1.el7.x86_64'
>>>
  • 環境變量可通過os.environ實現
  • 使用os.getenv()獲取某個環境變量的值
>>> os.getenv('PATH')
'/usr/local/nodejs/bin/:/usr/lib64/qt-3.3/bin:/usr/local/nodejs/bin/:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/opt/go/bin:/usr/local/zabbix/bin:/usr/local/zabbix/sbin:/home/flying/.local/bin:/home/flying/bin:/opt/go/bin:/usr/local/zabbix/bin:/usr/local/zabbix/sbin'
>>>
>>> import os
>>> os.path.abspath('.')
'/tmp'
>>> os.path.join('/tmp','abc')
'/tmp/abc'
>>> os.path.split('/tmp/abc/abc.txt')
('/tmp/abc', 'abc.txt')
>>> os.path.splitext('/tmp/abc/abc.txt')
('/tmp/abc/abc', '.txt')
>>> os.mkdir('/tmp/aaa')
>>> os.redir('/tmp/bbb')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'redir'
>>> os.rmdir('/tmp/aaa')
>>> os.rename('/tmp/test.txt','/tmp/test.py')
>>> os.remove('/tmp/test.py')
>>> [x for x in os.listdir('/') if os.path.isdir(x)]
[]
>>> [x for x in os.listdir('/tmp') if os.path.isdir(x)]
['.vbox-flying-ipc', '.X11-unix', '.XIM-unix', '.font-unix', '.ICE-unix', '.Test-unix', '.vnc-1000', '.netdata-charts.d-zN8rxQSxLc', '.esd-1000', '.com.google.Chrome.Q7BQcM', '.com.google.Chrome.sNA1MU', '.com.google.Chrome.8DNmu8', '.com.google.Chrome.LbgHCR', '.netdata-charts.d-n8RDHw5hvs', '.netdata-charts.d-LFZIdJUKi5', 'Atom Crashes', 'test']
>>>

Serialization

通過模塊cPicklepickle實現序列化

try:
    import cPickle as pickle
except ImportError:
    import pickle
  • pickle.dumps():把對象序列化成str字符串
  • pickle.loads(): 反序列化出對象

json

使用json模塊處理json格式數據 * json.dumps(): 對象轉換成json * json.loads(): json反序列化

class Student(object):

    def get_score(self):
        return self._score

    def set_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

  • Note Time: 2016.04.11 22:48 Mon
  • Note Location: Asia/Beijing
  • Writer: lempstacker