程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python學習筆記_Day07

編輯:Python

函數

  • 函數聲明的順序不重要,重要的是什麼時候調用
  • 函數的參數,只寫成單一的名稱,叫作位置參數;如果寫成key=val形式,稱作關鍵字參數
# 定義函數時,默認值參數必須在非默認值參數後面,否則將出現語法錯誤
>>> def func1(name='bob', age):
... pass
...
File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
>>> def func1(name, age=20): # 正確
... pass
>>> def func1(age,name='bob'): #正確,意思就是定義函數時有默認參數的要放在後邊.
... pass
...
>>> def func1(age=20,name): #報錯,應該放在後面.
... pass
...
File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
  • 傳遞參數也有相應的約定
>>> def func1(name, age):
... print('%s is %s years old' % (name, age))
>>> func1('tom', 20) # 正確-
tom is 20 years old
>>> func1(20, 'tom') # 語法正確,但是語義不正確
20 is tom years old
>>> func1(age=20, name='tom') # 正確-
tom is 20 years old
>>> func1(age=20, 'tom') # 語法錯誤
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> func1(20, name='tom') # 錯誤,name得到了多個值
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func1() got multiple values for argument 'name'
>>> func1('tom', age=20) # 正確-
tom is 20 years old
  • 參數組,當函數的參數不確定時可以使有參數組接收參數
  • *參數,表示使用元組接收參數
  • **參數,表示使用字典接收參數
>>> def func1(*args):
... print(args)
...
>>> func1()
()
>>> func1('hao')
('hao',)
>>> func1('hao', 123, 'tom')
('hao', 123, 'tom')
>>> def func2(**kwargs):
... print(kwargs)
...
>>> func2()
{}
>>> func2(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func2() takes 0 positional arguments but 1 was given
>>> func2(name='tom', age=20)
{'name': 'tom', 'age': 20}
>>> def func3(*args, **kwargs):
... print(args)
... print(kwargs)
...
>>> func3()
()
{}
>>> func3(10, 20, 30, name='tom', age=20)
(10, 20, 30)
{'name': 'tom', 'age': 20}
  • 傳參的時候也可以加*號,表示把序列或字典拆開
* 表示拆分序列
** 表示拆分字典
>>> def add(a, b):
... return a + b
...
>>> nums = [10, 20]
>>> add(nums) # 因為nums只是一個參數,nums傳遞給a,b沒有得到值
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() missing 1 required positional argument: 'b'
>>> add(*nums) #將nums拆開,分別將值傳遞給a和b
30
>>> mydict = {'a': 100, 'b':200}
>>> add(**mydict) # **表示拆開字典,相當於add(a=100, b=200)
300

練習:簡單的加減法數學游戲

  1. 隨機生成兩個100以內的數字
  2. 隨機選擇加法或是減法
  3. 總是使用大的數字減去小的數字
  4. 如果用戶答錯三次,程序給出正確答案
  • 思考程序運行方式:
5 + 5 = 10
Very Good!!!
Continue(y/n)? y
42 + 26 = 50
Wrong Answer!!!
42 + 26 = 55
Wrong Answer!!!
42 + 26 = 60
Wrong Answer!!!
42 + 26 = 68
Continue(y/n)? n
Bye-bye
  • 編寫程序:
第一種方法:
from random import randint, choice
def exam():
nums = [randint(1, 100) for i in range(2)]
nums.sort(reverse=True) # 降序排列
op = choice('+-') # 隨機選擇加減號
# 計算出正確答案
if op == '+':
result = nums[0] + nums[1]
else:
result = nums[0] - nums[1]
# 讓用戶做答,判斷對錯
prompt = '%s %s %s = ' % (nums[0], op, nums[1])
counter = 0
while counter < 3:
try:
answer = int(input(prompt))
except: # 不指定異常可以捕獲所有異常,但是不推薦
print()
continue
if answer == result:
print('非常棒!!!')
break
print('不對喲!!!')
counter += 1
else:
print('%s%s' % (prompt, result))
def main():
"該函數先出題,然後詢問用戶是否繼續"
while True:
exam()
# 去除字符串兩端空白字符後,取出第一個字符
try:
yn = input('Continue(y/n)? ').strip()[0]
except IndexError:
yn = 'y'
except (KeyboardInterrupt, EOFError):
yn = 'n'
if yn in 'nN':
print('\nBye-bye')
break
if __name__ == '__main__':
main()
第二種方法:
from random import randint, choice
def add(x, y):
return x + y
def sub(x, y):
return x - y
def exam():
cmds ={'+': add, '-': sub}
nums = [randint(1, 100) for i in range(2)]
nums.sort(reverse=True) # 降序排列
op = choice('+-') # 隨機選擇加減號
# 計算出正確答案
result = cmds[op](*nums)
# 讓用戶做答,判斷對錯
prompt = '%s %s %s = ' % (nums[0], op, nums[1])
counter = 0
while counter < 3:
try:
answer = int(input(prompt))
except: # 不指定異常可以捕獲所有異常,但是不推薦
print()
continue
if answer == result:
print('非常棒!!!')
break
print('不對喲!!!')
counter += 1
else:
print('%s%s' % (prompt, result))
def main():
"該函數先出題,然後詢問用戶是否繼續"
while True:
exam()
# 去除字符串兩端空白字符後,取出第一個字符
try:
yn = input('Continue(y/n)? ').strip()[0]
except IndexError:
yn = 'y'
except (KeyboardInterrupt, EOFError):
yn = 'n'
if yn in 'nN':
print('\nBye-bye')
break
if __name__ == '__main__':
main()
測試:
$ python 2.py
26 + 9 = 2
不對喲!!!
26 + 9 = 2
不對喲!!!
26 + 9 = 2
不對喲!!!
26 + 9 = 35
Continue(y/n)? y
52 - 3 = 49
非常棒!!!
Continue(y/n)? skhdk #隨便輸入都可以繼續,只要不是nN,因為我們編寫了異常處理try語句
84 + 79 = 22
不對喲!!!
84 + 79 = 55
不對喲!!!
84 + 79 = 55
不對喲!!!
84 + 79 = 163
Continue(y/n)? n
Bye-bye

匿名函數:沒有名字的函數。

  • 代碼只有一行
  • 能過lambda關鍵字定義
  • 參數直接寫到lambda後面
  • 表達式的計算結果是返回值
>>> def func1(x):
... return x + 10
...
>>> func1(2)
12
>>> add10 = lambda x: x + 10
>>> add10(2)
12

filter函數

  • 用於過濾數據
  • 它接受兩個參數
  • 第一個參數是函數,返回值必須是True或False
  • 第二個參數是序列對象
  • 序列對象中的每一個元素傳遞給函數,結果為True的保留
>>> from random import randint
>>> nums = [randint(1, 100) for i in range(10)]
>>> nums
[93, 2, 11, 70, 16, 23, 89, 17, 47, 91]
>>> def func1(x):
... return True if x > 50 else False
>>> list(filter(func1, nums))
[93, 70, 89, 91]
>>> list(filter(lambda x: True if x > 50 else False, nums))
[93, 70, 89, 91]
```
### map函數
- 用於加工數據
- 接受兩個參數
- 第一個參數是函數,用於加工數據
- 第二個參數是序列,序列中的每個對象作為前面函數的參數
- 將序列中的每個數據作為函數的參數,加工後返回
>>> def func2(x):
... return x * 2
...
>>> list(map(func2, nums))
[186, 4, 22, 140, 32, 46, 178, 34, 94, 182]
>>> list(map(lambda x: x * 2, nums))
[186, 4, 22, 140, 32, 46, 178, 34, 94, 182]
>>> list(map(lambda x: x * 5,nums))
[265, 210, 95, 90, 170, 120, 455, 85, 220, 275]

變量的作用域

  1. 定義在函數外面的是全局變量,全局變量從定義開始到程序結束,一直可見可用
  2. 函數內部定義的變量是局部變量,只在函數內部可見可用
  3. 如果局部和全局有同名變量,優先使用局部,局部變量遮蓋住全局變量
  4. 如果需要在局部改變全局變量,使有global關鍵字
# 1.定義在函數外面的是全局變量,全局變量從定義開始到程序結束,一直可見可用
>>> x = 10
>>> def func1():
... print(x)
...
>>> func1()
10
# 2.函數內部定義的變量是局部變量,只在函數內部可見可用
>>> def func2():
... y = 10
... print(y)
...
>>> func2()
10
>>> print(y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
# 3.如果局部和全局有同名變量,優先使用局部,局部變量遮蓋住全局變量
>>> def func3():
... x = 100
... print(x)
...
>>> func3()
100
>>> print(x)
10
# 4.如果需要在局部改變全局變量,使有global關鍵字
>>> def func4():
... global x
... x = 1000
... print(x)
...
>>> func4()
1000
>>> print(x)
1000

偏函數

改造現有函數,將其一些參數固定下來,生成新的函數。

>>> def add(a, b, c, d, e):
... return a + b + c + d + e
...
>>> add(10, 20, 30, 40, 5)
105
>>> add(10, 20, 30, 40, 22)
122
>>> from functools import partial
>>> myadd = partial(add, 10, 20, 30, 40)
>>> myadd(10)
110
>>> myadd(5)
105
# int接受base指定字符串的進制
>>> int('11111111', base=2)
255
>>> int2 = partial(int, base=2) # 改造int函數,將2進制轉10進制
>>> int2('11111111')
255

遞歸函數

  • 函數自己又調用自己
5!=5x4x3x2x1
5!=5x4!
5!=5x4x3!
5!=5x4x3x2!
5!=5x4x3x2x1!
1!=1
>>> def func(x):
... if x == 1:
... return 1
... return x * func(x - 1)
...
>>> func(5)
120
>>> func(6)
720

快速排序

  • 假設第一個數是中間值。 middle = nums[0]
  • 比middle大的都放到larger列表中
  • 比middle小的都放到smaller列表中
  • 將三者拼接:smaller + [middle] + larger
  • 使用相同的方法繼續對smaller和larger排序
  • 當列表只有一項或是空的,就不用再排了
from random import randint
def qsort(seq):
if len(seq) < 2:
return seq
middle = seq[0]
smaller = []
larger = []
for data in seq[1:]:
if data >= middle:
larger.append(data)
else:
smaller.append(data)
return qsort(smaller) + [middle] + qsort(larger)
if __name__ == '__main__':
nums = [randint(1,100) for i in range(10)]
print(nums)
print(qsort(nums))
$ python 2.py
[31, 59, 24, 30, 20, 19, 23, 96, 38, 67] #輸出的nums的值
[19, 20, 23, 24, 30, 31, 38, 59, 67, 96] #輸出的qsort(nums)排序後的值

生成器

  • 潛在可以提供很多數據
  • 不會立即生成全部數據,所以節省內存空間
  • 可以通過生成器表達式實現
  • 也可以通過函數實現
# 生成器表達式與列表解析的語法一樣,只是使用()
>>> ips = ('192.168.1.%s' % i for i in range(1, 255))
>>> for ip in ips:
... print(ip)
# 使用函數,通過yield多次返回中間值
>>> def mygen():
... yield 100
... n = 10 + 20
... yield n
... yield 'hello world'
...
>>> mg = mygen()
>>> for i in mg:
... print(i)
...
100
30
hello world

模塊

  • 模塊就是把一個python文件名去掉.py後的部分
  • 導入模塊時,python在sys.path定義的路徑中搜索模塊

hashlib模塊

用於計算哈希值。哈希值如md5 / sha等,常用於加密密碼和文件完整性校驗。

>>> import hashlib
>>> m = hashlib.md5(b'123456')
>>> m.hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
# 如果數據量太大,可以創建md5對象後,每次更新一部分
>>> import hashlib
>>> m1 = hashlib.md5()
>>> m1.update(b'12')
>>> m1.update(b'34')
>>> m1.update(b'56')
>>> m1.hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
# 如果數據量太大,可以創建md5對象後,每次更新一部分
>>> m1 = hashlib.md5()
>>> m1.update(b'12')
>>> m1.update(b'34')
>>> m1.update(b'56')
>>> m1.hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
>>> with open('/bin/ls', 'rb') as fobj:
... data = fobj.read()
...
>>> m = hashlib.md5(data)
>>> m.hexdigest()
'038a0a2d35a503d299a46096f6ff9890'
練習:編寫checkmd5.py(生成md5校驗碼,驗證兩個文件內容是否一致.)
  1. 通過命令行的位置參數給定文件名
  2. 計算出文件的md5值,打印到屏幕上
import hashlib
import sys
def check_md5(fname):
m = hashlib.md5()
with open(fname,'rb') as fobj:
while True:
data = fobj.read(4096)
if not data:
break
m.update(data)
return m.hexdigest()
if __name__ == '__main__':
print(check_md5(sys.argv[1]))
驗證:
$ python 2.py /etc/hosts #在計算md5值的python程序文件後直接跟位置參數,即文件路徑即可
df8bdcf4591134e0fca820b7d07451c8

tarfile模塊

>>> import tarfile
# 壓縮
>>> tar = tarfile.open('/tmp/mytar.tar.gz', 'w:gz')
>>> tar.add('/etc/hosts')
>>> tar.add('/etc/security')
>>> tar.close()
# 解壓縮到/tmp/demo
>>> tar = tarfile.open('/tmp/mytar.tar.gz')
>>> tar.extractall(path='/tmp/demo/')
>>> tar.close()
$ python 2.py
$ ls /luo/
demo mytar.tar.gz
$ ll /luo/
drwxrwxr-x 3 student student 4096 8月 8 17:43 demo
-rw-rw-r-- 1 student student 288 8月 8 17:43 mytar.tar.gz

練習: 備份程序

1.需要支持完全和增量備份

2.周一執行完全備份

3.其他時間執行增量備份

4.備份文件需要打包為tar文件並使用gzip格式壓縮

import os
import tarfile
import hashlib
import pickle
from time import strftime
def check_md5(fname):
m = hashlib.md5()
with open(fname, 'rb') as fobj:
while True:
data = fobj.read(4096)
if not data:
break
m.update(data)
return m.hexdigest()
def full_backup(src, dst, md5file):
"完全備份需要打包目錄和計算每個文件的md5值"
# 備份的tar文件要有備份目錄名、備份類型、時間
fname = '%s_full_%s.tar.gz' % (os.path.basename(src), strftime('%Y%m%d'))
fname = os.path.join(dst, fname)
# 將源目錄打包
tar = tarfile.open(fname, 'w:gz')
tar.add(src)
tar.close()
# 計算每個文件的md5值,將其存入字典
md5dict = {}
for path, folders, files in os.walk(src):
for file in files:
key = os.path.join(path, file)
md5dict[key] = check_md5(key)
# 通過pickle永久地把字典存到文件中
with open(md5file, 'wb') as fobj:
pickle.dump(md5dict, fobj)
def incr_backup(src, dst, md5file):
"增量備份把新增文件和改動的文件打包;更新md5文件以便於後續比較"
# 備份的tar文件要有備份目錄名、備份類型、時間
fname = '%s_incr_%s.tar.gz' % (os.path.basename(src), strftime('%Y%m%d'))
fname = os.path.join(dst, fname)
# 計算每個文件的md5值,將其存入字典
md5dict = {}
for path, folders, files in os.walk(src):
for file in files:
key = os.path.join(path, file)
md5dict[key] = check_md5(key)
# 取出前一天的md5值
with open(md5file, 'rb') as fobj:
old_md5 = pickle.load(fobj)
# 將新增文件和有改動文件進行打包
tar = tarfile.open(fname, 'w:gz')
for key in md5dict:
if old_md5.get(key) != md5dict[key]:
tar.add(key)
tar.close()
# 更新md5字典文件
with open(md5file, 'wb') as fobj:
pickle.dump(md5dict, fobj)
if __name__ == '__main__':
src = '/tmp/demo/security'
dst = '/tmp/backup'
md5file = '/tmp/backup/md5.data'
if not os.path.isdir(dst):
os.mkdir(dst)
if strftime('%a') == 'Mon':
full_backup(src, dst, md5file)
else:
incr_backup(src, dst, md5file)

os.walk()

  • 它可以遞歸列出某個目錄下的所有內容
  • 返回值由多個元組構成
  • ('路徑字符串', [路徑下目錄列表], [路徑下文件列表])
  • 將路徑字符串與文件拼接就可以得到文件的路徑
>>> list(os.walk('/etc/security'))
[('/etc/security', ['console.apps', 'console.perms.d', 'limits.d', 'namespace.d'], ['access.conf', 'chroot.conf', 'console.handlers', 'console.perms', 'group.conf', 'limits.conf', 'namespace.conf', 'namespace.init', 'opasswd', 'pam_env.conf', 'sepermit.conf', 'time.conf', 'pwquality.conf']), ('/etc/security/console.apps', [], ['config-util', 'xserver', 'liveinst', 'setup']), ('/etc/security/console.perms.d', [], []), ('/etc/security/limits.d', [], ['20-nproc.conf']), ('/etc/security/namespace.d', [], [])]
>>> result = list(os.walk('/etc/security'))
>>> len(result)
5
>>> result[0]
('/etc/security', ['console.apps', 'console.perms.d', 'limits.d', 'namespace.d'], ['access.conf', 'chroot.conf', 'console.handlers', 'console.perms', 'group.conf', 'limits.conf', 'namespace.conf', 'namespace.init', 'opasswd', 'pam_env.conf', 'sepermit.conf', 'time.conf', 'pwquality.conf'])
>>> result[1]
('/etc/security/console.apps', [], ['config-util', 'xserver', 'liveinst', 'setup'])
>>> result[2]
('/etc/security/console.perms.d', [], [])
>>> for path, folers, files in os.walk('/etc/security'):
... for file in files:
... os.path.join(path, file)

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved