Python之路【第三篇】:Python基礎(二)


內置函數 一

詳細見python文檔,猛擊這里

文件操作

操作文件時,一般需要經歷如下步驟:

  • 打開文件
  • 操作文件

一、打開文件

文件句柄 = file('文件路徑', '模式')

注:python中打開文件有兩種方式,即:open(...) 和  file(...) ,本質上前者在內部會調用后者來進行文件操作,推薦使用 open

打開文件時,需要指定文件路徑和以何等方式打開文件,打開后,即可獲取該文件句柄,日后通過此文件句柄對該文件操作。

打開文件的模式有:

  • r,只讀模式(默認)。
  • w,只寫模式。【不可讀;不存在則創建;存在則刪除內容;】
  • a,追加模式。【可讀;   不存在則創建;存在則只追加內容;】

"+" 表示可以同時讀寫某個文件

  • r+,可讀寫文件。【可讀;可寫;可追加】
  • w+,寫讀
  • a+,同a

"U"表示在讀取時,可以將 \r \n \r\n自動轉換成 \n (與 r 或 r+ 模式同使用)

  • rU
  • r+U

"b"表示處理二進制文件(如:FTP發送上傳ISO鏡像文件,linux可忽略,windows處理二進制文件時需標注)

  • rb
  • wb
  • ab

二、操作操作

class file(object):
 
    def close(self): # real signature unknown; restored from __doc__
        關閉文件
        """
        close() -> None or (perhaps) an integer.  Close the file.
        
        Sets data attribute .closed to True.  A closed file cannot be used for
        further I/O operations.  close() may be called more than once without
        error.  Some kinds of file objects (for example, opened by popen())
        may return an exit status upon closing.
        """

    def fileno(self): # real signature unknown; restored from __doc__
        文件描述符   
         """
        fileno() -> integer "file descriptor".
        
        This is needed for lower-level file interfaces, such os.read().
        """
        return 0     

    def flush(self): # real signature unknown; restored from __doc__
        刷新文件內部緩沖區
        """ flush() -> None.  Flush the internal I/O buffer. """
        pass


    def isatty(self): # real signature unknown; restored from __doc__
        判斷文件是否是同意tty設備
        """ isatty() -> true or false.  True if the file is connected to a tty device. """
        return False


    def next(self): # real signature unknown; restored from __doc__
        獲取下一行數據,不存在,則報錯
        """ x.next() -> the next value, or raise StopIteration """
        pass

    def read(self, size=None): # real signature unknown; restored from __doc__
        讀取指定字節數據
        """
        read([size]) -> read at most size bytes, returned as a string.
        
        If the size argument is negative or omitted, read until EOF is reached.
        Notice that when in non-blocking mode, less data than what was requested
        may be returned, even if no size parameter was given.
        """
        pass

    def readinto(self): # real signature unknown; restored from __doc__
        讀取到緩沖區,不要用,將被遺棄
        """ readinto() -> Undocumented.  Don't use this; it may go away. """
        pass

    def readline(self, size=None): # real signature unknown; restored from __doc__
        僅讀取一行數據
        """
        readline([size]) -> next line from the file, as a string.
        
        Retain newline.  A non-negative size argument limits the maximum
        number of bytes to return (an incomplete line may be returned then).
        Return an empty string at EOF.
        """
        pass

    def readlines(self, size=None): # real signature unknown; restored from __doc__
        讀取所有數據,並根據換行保存值列表
        """
        readlines([size]) -> list of strings, each a line from the file.
        
        Call readline() repeatedly and return a list of the lines so read.
        The optional size argument, if given, is an approximate bound on the
        total number of bytes in the lines returned.
        """
        return []

    def seek(self, offset, whence=None): # real signature unknown; restored from __doc__
        指定文件中指針位置
        """
        seek(offset[, whence]) -> None.  Move to new file position.
        
        Argument offset is a byte count.  Optional argument whence defaults to
        0 (offset from start of file, offset should be >= 0); other values are 1
        (move relative to current position, positive or negative), and 2 (move
        relative to end of file, usually negative, although many platforms allow
        seeking beyond the end of a file).  If the file is opened in text mode,
        only offsets returned by tell() are legal.  Use of other offsets causes
        undefined behavior.
        Note that not all file objects are seekable.
        """
        pass

    def tell(self): # real signature unknown; restored from __doc__
        獲取當前指針位置
        """ tell() -> current file position, an integer (may be a long integer). """
        pass

    def truncate(self, size=None): # real signature unknown; restored from __doc__
        截斷數據,僅保留指定之前數據
        """
        truncate([size]) -> None.  Truncate the file to at most size bytes.
        
        Size defaults to the current file position, as returned by tell().
        """
        pass

    def write(self, p_str): # real signature unknown; restored from __doc__
        寫內容
        """
        write(str) -> None.  Write string str to file.
        
        Note that due to buffering, flush() or close() may be needed before
        the file on disk reflects the data written.
        """
        pass

    def writelines(self, sequence_of_strings): # real signature unknown; restored from __doc__
        將一個字符串列表寫入文件
        """
        writelines(sequence_of_strings) -> None.  Write the strings to the file.
        
        Note that newlines are not added.  The sequence can be any iterable object
        producing strings. This is equivalent to calling write() for each string.
        """
        pass

    def xreadlines(self): # real signature unknown; restored from __doc__
        可用於逐行讀取文件,非全部
        """
        xreadlines() -> returns self.
        
        For backward compatibility. File objects now include the performance
        optimizations previously implemented in the xreadlines module.
        """
        pass

三、with

為了避免打開文件后忘記關閉,可以通過管理上下文,即:

with open('log','r') as f: 
	
	...

如此方式,當with代碼塊執行完畢時,內部會自動關閉並釋放文件資源。

在Python 2.7 后,with又支持同時對多個文件的上下文進行管理,即:

with open('log1') as obj1, open('log2') as obj2:
    pass

四、那么問題來了...

1、如何在線上環境優雅的修改配置文件?

global       
        log 127.0.0.1 local2
        daemon
        maxconn 256
        log 127.0.0.1 local2 info
defaults
        log global
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
        option  dontlognull

listen stats :8888
        stats enable
        stats uri       /admin
        stats auth      admin:1234

frontend oldboy.org
        bind 0.0.0.0:80
        option httplog
        option httpclose
        option  forwardfor
        log global
        acl www hdr_reg(host) -i www.oldboy.org
        use_backend www.oldboy.org if www

backend www.oldboy.org
        server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000
原配置文件
1、查
    輸入:www.oldboy.org
    獲取當前backend下的所有記錄

2、新建
    輸入:
        arg = {
            'bakend': 'www.oldboy.org',
            'record':{
                'server': '100.1.7.9',
                'weight': 20,
                'maxconn': 30
            }
        }

3、刪除
    輸入:
        arg = {
            'bakend': 'www.oldboy.org',
            'record':{
                'server': '100.1.7.9',
                'weight': 20,
                'maxconn': 30
            }
        }
需求
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import json
import os


def fetch(backend):
    backend_title = 'backend %s' % backend
    record_list = []
    with open('ha') as obj:
        flag = False
        for line in obj:
            line = line.strip()
            if line == backend_title:
                flag = True
                continue
            if flag and line.startswith('backend'):
                flag = False
                break

            if flag and line:
                record_list.append(line)

    return record_list


def add(dict_info):
    backend = dict_info.get('backend')
    record_list = fetch(backend)
    backend_title = "backend %s" % backend
    current_record = "server %s %s weight %d maxconn %d" % (dict_info['record']['server'], dict_info['record']['server'], dict_info['record']['weight'], dict_info['record']['maxconn'])
    if not record_list:
        record_list.append(backend_title)
        record_list.append(current_record)
        with open('ha') as read_file, open('ha.new', 'w') as write_file:
            flag = False
            for line in read_file:
                write_file.write(line)
            for i in record_list:
                if i.startswith('backend'):
                    write_file.write(i+'\n')
                else:
                    write_file.write("%s%s\n" % (8*" ", i))
    else:
        record_list.insert(0, backend_title)
        if current_record not in record_list:
            record_list.append(current_record)

        with open('ha') as read_file, open('ha.new', 'w') as write_file:
            flag = False
            has_write = False
            for line in read_file:
                line_strip = line.strip()
                if line_strip == backend_title:
                    flag = True
                    continue
                if flag and line_strip.startswith('backend'):
                    flag = False
                if not flag:
                    write_file.write(line)
                else:
                    if not has_write:
                        for i in record_list:
                            if i.startswith('backend'):
                                write_file.write(i+'\n')
                            else:
                                write_file.write("%s%s\n" % (8*" ", i))
                    has_write = True
    os.rename('ha','ha.bak')
    os.rename('ha.new','ha')


def remove(dict_info):
    backend = dict_info.get('backend')
    record_list = fetch(backend)
    backend_title = "backend %s" % backend
    current_record = "server %s %s weight %d maxconn %d" % (dict_info['record']['server'], dict_info['record']['server'], dict_info['record']['weight'], dict_info['record']['maxconn'])
    if not record_list:
        return
    else:
        if current_record not in record_list:
            return
        else:
            del record_list[record_list.index(current_record)]
            if len(record_list) > 0:
                record_list.insert(0, backend_title)
        with open('ha') as read_file, open('ha.new', 'w') as write_file:
            flag = False
            has_write = False
            for line in read_file:
                line_strip = line.strip()
                if line_strip == backend_title:
                    flag = True
                    continue
                if flag and line_strip.startswith('backend'):
                    flag = False
                if not flag:
                    write_file.write(line)
                else:
                    if not has_write:
                        for i in record_list:
                            if i.startswith('backend'):
                                write_file.write(i+'\n')
                            else:
                                write_file.write("%s%s\n" % (8*" ", i))
                    has_write = True
    os.rename('ha','ha.bak')
    os.rename('ha.new','ha')

if __name__ == '__main__':
    """
    print '1、獲取;2、添加;3、刪除'
    num = raw_input('請輸入序號:')
    data = raw_input('請輸入內容:')
    if num == '1':
        fetch(data)
    else:
        dict_data = json.loads(data)
        if num == '2':
            add(dict_data)
        elif num == '3':
            remove(dict_data)
        else:
            pass
    """
    #data = "www.oldboy.org"
    #fetch(data)
    #data = '{"backend": "tettst.oldboy.org","record":{"server": "100.1.7.90","weight": 20,"maxconn": 30}}'
    #dict_data = json.loads(data)
    #add(dict_data)
    #remove(dict_data)
demo

2、文件處理中xreadlines的內部是如何實現的呢?

自定義函數

一、背景

在學習函數之前,一直遵循:面向過程編程,即:根據業務邏輯從上到下實現功能,其往往用一長段代碼來實現指定功能,開發過程中最常見的操作就是粘貼復制,也就是將之前實現的代碼塊復制到現需功能處,如下

while True:
    if cpu利用率 > 90%:
        #發送郵件提醒
        連接郵箱服務器
        發送郵件
        關閉連接
 
    if 硬盤使用空間 > 90%:
        #發送郵件提醒
        連接郵箱服務器
        發送郵件
        關閉連接
 
    if 內存占用 > 80%:
        #發送郵件提醒
        連接郵箱服務器
        發送郵件
        關閉連接

腚眼一看上述代碼,if條件語句下的內容可以被提取出來公用,如下:

def 發送郵件(內容)
    #發送郵件提醒
    連接郵箱服務器
    發送郵件
    關閉連接
 
while True:
 
    if cpu利用率 > 90%:
        發送郵件('CPU報警')
 
    if 硬盤使用空間 > 90%:
        發送郵件('硬盤報警')
 
    if 內存占用 > 80%:

對於上述的兩種實現方式,第二次必然比第一次的重用性和可讀性要好,其實這就是函數式編程和面向過程編程的區別:

  • 函數式:將某功能代碼封裝到函數中,日后便無需重復編寫,僅調用函數即可
  • 面向對象:對函數進行分類和封裝,讓開發“更快更好更強...”

函數式編程最重要的是增強代碼的重用性和可讀性

二、 函數的定義和使用

def 函數名(參數):
	
	...
	函數體
	...

函數的定義主要有如下要點:

  • def:表示函數的關鍵字
  • 函數名:函數的名稱,日后根據函數名調用函數
  • 函數體:函數中進行一系列的邏輯計算,如:發送郵件、計算出 [11,22,38,888,2]中的最大數等...
  • 參數:為函數體提供數據
  • 返回值:當函數執行完畢后,可以給調用者返回數據。

以上要點中,比較重要有參數和返回值:

1、返回值

函數是一個功能塊,該功能到底執行成功與否,需要通過返回值來告知調用者。

def 發送短信():
	
	發送短信的代碼...

	if 發送成功:
		return True
	else:
		return False


while True:
	
	# 每次執行發送短信函數,都會將返回值自動賦值給result
	# 之后,可以根據result來寫日志,或重發等操作

	result = 發送短信()
	if result == False:
		記錄日志,短信發送失敗...

2、參數

為什么要有參數?

def CPU報警郵件()
    #發送郵件提醒
    連接郵箱服務器
    發送郵件
    關閉連接

def 硬盤報警郵件()
    #發送郵件提醒
    連接郵箱服務器
    發送郵件
    關閉連接

def 內存報警郵件()
    #發送郵件提醒
    連接郵箱服務器
    發送郵件
    關閉連接
 
while True:
 
    if cpu利用率 > 90%:
        CPU報警郵件()
 
    if 硬盤使用空間 > 90%:
        硬盤報警郵件()
 
    if 內存占用 > 80%:
        內存報警郵件()
上例,無參數實現
def 發送郵件(郵件內容)

    #發送郵件提醒
    連接郵箱服務器
    發送郵件
    關閉連接

 
while True:
 
    if cpu利用率 > 90%:
        發送郵件("CPU報警了。")
 
    if 硬盤使用空間 > 90%:
        發送郵件("硬盤報警了。")
 
    if 內存占用 > 80%:
        發送郵件("內存報警了。")
上列,有參數實現

函數的有三中不同的參數:

  • 普通參數
  • 默認參數
  • 動態參數
# ######### 定義函數 ######### 

# name 叫做函數func的形式參數,簡稱:形參
def func(name):
    print name

# ######### 執行函數 ######### 
#  'wupeiqi' 叫做函數func的實際參數,簡稱:實參
func('wupeiqi')
普通參數
def func(name, age = 18):
    
    print "%s:%s" %(name,age)

# 指定參數
func('wupeiqi', 19)
# 使用默認參數
func('alex')

注:默認參數需要放在參數列表最后
默認參數
def func(*args):

    print args


# 執行方式一
func(11,33,4,4454,5)

# 執行方式二
li = [11,2,2,3,3,4,54]
func(*li)
動態參數一
def func(**kwargs):

    print args


# 執行方式一
func(name='wupeiqi',age=18)

# 執行方式二
li = {'name':'wupeiqi', age:18, 'gender':'male'}
func(**li)
動態參數二
def func(*args, **kwargs):

    print args
    print kwargs
動態參數三

擴展:發送郵件實例

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr


msg = MIMEText('郵件內容', 'plain', 'utf-8')
msg['From'] = formataddr(["武沛齊",'wptawy@126.com'])
msg['To'] = formataddr(["走人",'424662508@qq.com'])
msg['Subject'] = "主題"

server = smtplib.SMTP("smtp.126.com", 25)
server.login("wptawy@126.com", "郵箱密碼")
server.sendmail('wptawy@126.com', ['424662508@qq.com',], msg.as_string())
server.quit()

lambda表達式

學習條件運算時,對於簡單的 if else 語句,可以使用三元運算來表示,即:

# 普通條件語句
if 1 == 1:
    name = 'wupeiqi'
else:
    name = 'alex'
 
# 三元運算
name = 'wupeiqi' if 1 == 1 else 'alex'

對於簡單的函數,也存在一種簡便的表示方式,即:lambda表達式

# ###################### 普通函數 ######################
# 定義函數(普通方式)
def func(arg):
    return arg + 1
 
# 執行函數
result = func(123)
 
# ###################### lambda ######################
 
# 定義函數(lambda表達式)
my_lambda = lambda arg : arg + 1
 
# 執行函數
result = my_lambda(123)

lambda存在意義就是對簡單函數的簡潔表示

內置函數 二

一、map

遍歷序列,對序列中每個元素進行操作,最終獲取新的序列。

li = [11, 22, 33]

new_list = map(lambda a: a + 100, li)
每個元素增加100
li = [11, 22, 33]
sl = [1, 2, 3]
new_list = map(lambda a, b: a + b, li, sl)
兩個列表對應元素相加

二、filter

對於序列中的元素進行篩選,最終獲取符合條件的序列

li = [11, 22, 33]

new_list = filter(lambda arg: arg > 22, li)

#filter第一個參數為空,將獲取原來序列
獲取列表中大於12的所有元素集合

三、reduce

對於序列內所有元素進行累計操作

li = [11, 22, 33]

result = reduce(lambda arg1, arg2: arg1 + arg2, li)

# reduce的第一個參數,函數必須要有兩個參數
# reduce的第二個參數,要循環的序列
# reduce的第三個參數,初始值
獲取序列所有元素的和

yield生成器

1、對比range 和 xrange 的區別

>>> print range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print xrange(10)
xrange(10)

如上代碼所示,range會在內存中創建所有指定的數字,而xrange不會立即創建,只有在迭代循環時,才去創建每個數組。

def nrange(num):
    temp = -1
    while True:
        temp = temp + 1
        if temp >= num:
            return
        else:
            yield temp
自定義生成器nrange

2、文件操作的 read 和 xreadlinex 的的區別

read會讀取所有內容到內存
xreadlines則只有在循環迭代時才獲取
def NReadlines():
    with open('log','r') as f:
        while True:
            line = f.next()
            if line:
                yield line
            else:
                return

for i in NReadlines():
    print i
基於next自定義生成器NReadlines
def NReadlines():
    with open('log','r') as f:
        seek = 0
        while True:
            f.seek(seek)
            data = f.readline()
            if data:
                seek = f.tell()
                yield data
            else:
                return

for item in NReadlines():
    print item
基於seek和tell自定義生成器NReadlines

裝飾器

裝飾器是函數,只不過該函數可以具有特殊的含義,裝飾器用來裝飾函數或類,使用裝飾器可以在函數執行前和執行后添加相應操作。

def wrapper(func):
    def result():
        print 'before'
        func()
        print 'after'
    return result

@wrapper
def foo():
    print 'foo'
import functools


def wrapper(func):
    @functools.wraps(func)
    def wrapper():
        print 'before'
        func()
        print 'after'
    return wrapper

@wrapper
def foo():
    print 'foo'
View Code
#!/usr/bin/env python
#coding:utf-8
 
def Before(request,kargs):
    print 'before'
     
def After(request,kargs):
    print 'after'
 
 
def Filter(before_func,after_func):
    def outer(main_func):
        def wrapper(request,kargs):
             
            before_result = before_func(request,kargs)
            if(before_result != None):
                return before_result;
             
            main_result = main_func(request,kargs)
            if(main_result != None):
                return main_result;
             
            after_result = after_func(request,kargs)
            if(after_result != None):
                return after_result;
             
        return wrapper
    return outer
     
@Filter(Before, After)
def Index(request,kargs):
    print 'index'
     
     
if __name__ == '__main__':
    Index(1,2)
View Code

冒泡算法

需求:請按照從小到大對列表 [13, 22, 6, 99, 11] 進行排序

思路:相鄰兩個值進行比較,將較大的值放在右側,依次比較!

li = [13, 22, 6, 99, 11]

for m in range(4):     # 等價於 #for m in range(len(li)-1):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp
第一步
li = [13, 22, 6, 99, 11]

for m in range(4):     # 等價於 #for m in range(len(li)-1):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

for m in range(3):     # 等價於 #for m in range(len(li)-2):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

for m in range(2):     # 等價於 #for m in range(len(li)-3):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

for m in range(1):     # 等價於 #for m in range(len(li)-4):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp
print li
第二步
li = [13, 22, 6, 99, 11]

for i in range(1,5):
    for m in range(len(li)-i): 
        if li[m] > li[m+1]:
            temp = li[m+1]
            li[m+1] = li[m]
            li[m] = temp
第三步

遞歸

利用函數編寫如下數列:

斐波那契數列指的是這樣一個數列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368

def func(arg1,arg2):
    if arg1 == 0:
        print arg1, arg2
    arg3 = arg1 + arg2
    print arg3
    func(arg2, arg3)

func(0,1)
demo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM