前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python学习笔记_Day07

Python学习笔记_Day07

作者头像
非著名运维
发布2022-06-22 15:28:06
7020
发布2022-06-22 15:28:06
举报
文章被收录于专栏:非著名运维

函数

  • 函数声明的顺序不重要,重要的是什么时候调用
  • 函数的参数,只写成单一的名称,叫作位置参数;如果写成key=val形式,称作关键字参数
代码语言:javascript
复制
# 定义函数时,默认值参数必须在非默认值参数后面,否则将出现语法错误
>>> 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
  • 传递参数也有相应的约定
代码语言:javascript
复制
>>> 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
  • 参数组,当函数的参数不确定时可以使有参数组接收参数
  • *参数,表示使用元组接收参数
  • **参数,表示使用字典接收参数
代码语言:javascript
复制
>>> 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}
  • 传参的时候也可以加*号,表示把序列或字典拆开
代码语言:javascript
复制
* 表示拆分序列
** 表示拆分字典

>>> 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. 如果用户答错三次,程序给出正确答案
  • 思考程序运行方式:
代码语言:javascript
复制
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
  • 编写程序:
代码语言:javascript
复制
第一种方法:

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()
代码语言:javascript
复制
第二种方法:

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()
代码语言:javascript
复制
测试:
$ 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后面
  • 表达式的计算结果是返回值
代码语言:javascript
复制
>>> def func1(x):
...   return x + 10
...
>>> func1(2)
12
>>> add10 = lambda x: x + 10
>>> add10(2)
12

filter函数

  • 用于过滤数据
  • 它接受两个参数
  • 第一个参数是函数,返回值必须是True或False
  • 第二个参数是序列对象
  • 序列对象中的每一个元素传递给函数,结果为True的保留
代码语言:javascript
复制
>>> 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关键字
代码语言:javascript
复制
# 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

偏函数

改造现有函数,将其一些参数固定下来,生成新的函数。

代码语言:javascript
复制
>>> 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

递归函数

  • 函数自己又调用自己
代码语言:javascript
复制
5!=5x4x3x2x1
5!=5x4!
5!=5x4x3!
5!=5x4x3x2!
5!=5x4x3x2x1!
1!=1
代码语言:javascript
复制
>>> 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排序
  • 当列表只有一项或是空的,就不用再排了
代码语言:javascript
复制
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))
代码语言:javascript
复制
$ 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)排序后的值  

生成器

  • 潜在可以提供很多数据
  • 不会立即生成全部数据,所以节省内存空间
  • 可以通过生成器表达式实现
  • 也可以通过函数实现
代码语言:javascript
复制
# 生成器表达式与列表解析的语法一样,只是使用()
>>> 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等,常用于加密密码和文件完整性校验。

代码语言:javascript
复制
>>> 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值,打印到屏幕上
代码语言:javascript
复制
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]))
代码语言:javascript
复制
验证:
$ python 2.py /etc/hosts  #在计算md5值的python程序文件后直接跟位置参数,即文件路径即可
df8bdcf4591134e0fca820b7d07451c8

tarfile模块

代码语言:javascript
复制
>>> 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()
代码语言:javascript
复制
$ 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格式压缩

代码语言:javascript
复制
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()

  • 它可以递归列出某个目录下的所有内容
  • 返回值由多个元组构成
  • ('路径字符串', [路径下目录列表], [路径下文件列表])
  • 将路径字符串与文件拼接就可以得到文件的路径
代码语言:javascript
复制
>>> 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)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 非著名运维 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数
    • 匿名函数:没有名字的函数。
      • filter函数
        • 变量的作用域
        • 偏函数
          • 递归函数
            • 生成器
            • 模块
              • hashlib模块
                • tarfile模块
                  • os.walk()
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档