Python从基础到精通day3

文件对象、函数基础、模块基础介绍:

案例1 九九乘法表

双层for循环的套用

# 打印3个hello
for j in range(3):
    print('hello')
# 将3个hello打印在一行,并且打印完成后,在下面打印回车
for j in range(3):
    print('hello', end=' ')
print()

# 打印3行,每行打印3个hello。只要将上面代码再放到一个循环里
for i in range(3):
    for j in range(3):
        print('hello', end=' ')
    print()

# 实现第一行打印1个hello,第2行2个hello,第3行3个hello,第i行i个hello。只要让range()函数不再产生固定个数的数字即可:
for i in range(3):
    for j in range(i + 1):
        print('hello', end=' ')
    print()
    
# 只要将数字改为从1到9,把打印的hello改为算式,就可以实现九九乘法表
for i in range(1, 10):
    for j in range(1, i + 1):
        print('%s x %s = %s' % (j, i, i * j), end=' ')
    print()

print函数默认会在结尾打印回车,即end='\n',如果希望自定义在结尾打印什么,可以使用end='xxx'

文件

  • 文件操作的三个步骤:打开、读写、关闭
  • 在python中,打开文件,实际上是找到文件在硬盘上的存储位置,返回一个文件对象。可以通过这个文件对象对硬盘实现读写
  • 在python中一切皆对象,如字符串对象、文件对象、数字对象等。不同的对象有不同的属性和方法。

读取文本文件

  • 字符:即str,就是现实世界中的文字,一个字母是一个字符,一个汉字也是一个字符
  • 字节:即byte,存储单位。计算中最小的存储单位是比特bit,一个字节等于8bit。
  • 使用utf8编码,一个英文字符占一个字节,一个汉字一般占3个字节。
  • 在python使用字节表示的时候,如果一个字节能表示成一个字符,就以字符的形式呈现;如果一个字节(8个0和1的组合)不能表示成一个字符,为了方便就用16进制数表示
>>> s1 = 'a'
>>> s2 = '中'
>>> type(s1)
<class 'str'>
>>> type(s2)
<class 'str'>
>>> b1 = s1.encode()  # 将s1转为bytes类型
>>> b1
b'a'   # b是bytes类型的前缀
>>> b2 = s2.encode()  # 将s2转为bytes类型
>>> b2
b'\xe4\xb8\xad'
>>> type(b1)
<class 'bytes'>
>>> type(b2)
<class 'bytes'>
>>> b1.decode()  # 将bytes类型转为str类型
'a'
>>> b2.decode()  # 将bytes类型转为str类型
'中'

utf8编码示例

A  01000001
B  01000010
C  01000011
... ...
a  01100001
b  01100010
c  01100011
... ...
中  11100100 10111000 10101101
[root@localhost day03]# vim /tmp/mytest.txt
Hello World!
How are you?
吃了吗?
没呢
# 默认以r的方式打开文件,文件不存在则报错
>>> open('/tmp/mytest.doc')   # 报错

# 以r方式打开文件,只能读,不能写
>>> f1 = open('/tmp/mytest.txt')  # 打开
>>> data = f1.read()   # read()默认读取全部内容
>>> f1.close()         # 关闭
>>> data
'Hello World!\nHow are you?\n吃了吗?\n没呢\n'
>>> print(data)
Hello World!
How are you?
吃了吗?
没呢

# 注意,文件打开后,每次读取都是继续向下读取,文件指针将会一直向后移动
>>> f1 = open('/tmp/mytest.txt')
>>> data = f1.read()  # 把全部内容读出赋值给变量data
>>> data = f1.read()  # 继续向后读,读出内容重新赋值给data
>>> f1.close()
>>> data
''
>>> f1.close()

# read()也可以指定一次读多少字节
>>> f1 = open('/tmp/mytest.txt')
>>> f1.read(5)
'Hello'
>>> f1.read(8)  # 继续向后读取8个字节
' World!\n'
>>> f1.close()

# readline()读取一行
>>> f1 = open('/tmp/mytest.txt')
>>> f1.readline()
'Hello World!\n'
# readlines()读取全部,并将结果保存到列表中
>>> f1.readlines()
['How are you?\n', '吃了吗?\n', '没呢\n']
>>> f1.close()

读取文本文件最常用的方法是for循环遍历

>>> f1 = open('/tmp/mytest.txt')
>>> for line in f1:
...   print(line, end='')
... 
Hello World!
How are you?
吃了吗?
没呢
>>> f1.close()

读取非文本文件

[root@localhost ]# wget https://i04picsos.sogoucdn.com/a3d305716dd0e456 -O /tmp/girl.jpg
>>> f1 = open('/tmp/girl.jpg', 'rb')
>>> f1.read(10)
b'\xff\xd8\xff\xe0\x00\x10JFIF'
>>> f1.close()

写入文本文件

# 以w方式打开文件,如果文件已存在,则清空,不存在则创建
>>> f1 = open('/tmp/mytest.txt', 'w')
[root@localhost day03]# cat /tmp/mytest.txt  # 已清空
>>> f1.write('Hello World!\n')
13   # 表示写入了13字节
# 查看时仍然为空。因为为了提升效率,是先将数据写入到了缓存,当缓存达到4K时,自动同步到硬盘。关闭文件时,也会同步到硬盘
[root@localhost day03]# cat /tmp/mytest.txt
>>> f1.flush()  # 立即同步数据到硬盘
[root@localhost day03]# cat /tmp/mytest.txt
Hello World!
>>> f1.writelines(['How are you?\n', '吃了吗?\n', '没呢\n'])
>>> f1.close()  #写完之后需要关闭才可查看到

写入非文本文件

  • 跟写入文本文件一样,只是打开时的打开模式需要为wb模式
  • 写入的数据是bytes类型
>>> f1 = open('/tmp/mytest2.txt', 'wb')
>>> f1.write(b'\xe4\xb8\xad')
3
>>> f1.close()
[root@localhost day03]# cat /tmp/mytest2.txt 

with语句

  • 使用with语句打开文件,with语句结束后,文件自动关闭
>>> with open('/tmp/mytest.txt') as f1:
...   f1.readline()
... 
'Hello World!\n'
>>> f1.readline()  # 文件已关闭,报错

总结

  • 读取文本文件默认使用r方式打开,文件不存在则报错,只能读,不能写.

  • 写入文本文件默认使用w方式打开,没有则创建,有则清空,所以重要文件不要以w方式打开。

  • 读取非文本文件时使用rb方式打开,写入非文本文件时使用wb方式打开

  • r表示read 读取

  • w表示write 书写

  • b表示byte字节,所以非文本文件无论是读取还是写入需要加b

案例1:模拟cp操作

[root@localhost day03]# vim cp.py

#!/usr/bin/env python3
with open('/bin/ls','rb') as f1:
with  open('/root/ls','wb') as f2:
data = read.f1()
f2.write(data)

案例2:模拟cp操作升级版

当需要一个复制的文件很大时,会非常消耗服务器的内存资源,可以用循环控制写入的数据大小。

src_fname = '/etc/passwd'
dst_fname = '/tmp/passwd'
src_open = open(src_fname,'rb')
dst_open = open(dst_fname,'wb')

while 1:
    data = src_open.read(4096)
    # if len(data) == 0:   零字节
    # if data == b'':	空串
    if not data:	有数据为真,没数据为假,前面加上not取反。 如果data有数据则为假,为假不执行breakbreak
    dst_open.write(data)

src_open.close()
dst_open.close()

函数

  • 为一组代码取名,完成某个功能
  • 定义函数时,函数体内的代码不执行
  • 调用函数时,需要在函数名后面加上(),来完成调用
  • 调用函数就是执行函数体内的代码
  • 函数定义语法结构
def 函数名(参数1, 参数2..., 参数n):
    代码块

参数

  • 可以理解为参数就是函数需要用到的变量,但是变量的值还不确定
  • 定义函数时,函数名后面括号里的名字就是参数,因为只是形式上占个位置,所以称作形式参数或形参
  • 调用函数时,相当于是变量赋值。调用函数将具体的数据传进去,这个数据是实际使用的数据,叫实际参数或实参
  • python的位置参数保存在sys模块的argv列表中。注意:位置参数都是字符类型

案例3 斐波那契数列之模块传参

def mk_fib(n):
    result = [0,1]
    for i in range(n-2):
        result.append(result[-1] + result[-2])
    print(result)
a = int(input('长度:')) #当用户输入时将参数传给函数
mk_fib(a)

#echo -n '10' > /tmp/len.txt   -n 表示去除回车\n
with open('/tmp/len.txt') as f1:
    data = f1.read()
    data = int(data)   #将读出的内容转换成int类型重新赋值
mk_fib(data)

python的位置参数保存在sys模块的argv列表中。

  • 注意:位置参数都是字符类型

位置变量:

[root@localhost day03]# vim weizhi.py 
import sys
 
print(sys.argv)
[root@localhost day03]# python3 weizhi.py 
['weizhi.py']
[root@localhost day03]# python3 weizhi.py hao 123
['weizhi.py', 'hao', '123']
# sys.argv[0] 相当于shell脚本中的 $0 输出文件本身的名称
# sys.argv[1] -> $1
# sys.argv[2] -> $2
  • 默认参数:提供了默认值的参数。传参时,如果给定了具体的值,就使用传递的值;如果没有传值,则使用默认值。

案例4:位置参数的使用

import sys
def copy(src_fname,dst_fname):  预定义参数
        src_fobj = open(src_fname,'rb')
        dst_fobj = open(dst_fname,'wb')
        while 1:
                data = src_fobj.read(4096)
                if not data:
                        break
                dst_fobj.write(data)

        src_fobj.close()
        dst_fobj.close()

#copy('/bin/touch','/tmp/touch')
copy(sys.argv[1],sys.argv[2]) $1对应src_fname,$2对应dst_fname
#python3 lianxi.py /etc/hosts   /tmp/hosts

运行测试:
[root@python day3]# python3 lianxi.py /etc/hosts /tmp/hosts
[root@python day3]# md5sum /etc/hosts
54fb6627dbaa37721048e4549db3224d /etc/hosts
[root@python day3]# md5sum /tmp/hosts
54fb6627dbaa37721048e4549db3224d /tmp/hosts

默认参数的使用

提供了默认值的参数,传参时,如果给定了具体的值则使用具体值;如果没有给定,则使用默认值。

>>> def pstar(n=50):
...   print('*' * n)
... 
>>> pstar(30)
******************************
>>> pstar()
**************************************************

返回值

  • 函数执行的结果,可以通过return关键字返回
  • 如果函数没有return,默认返回None
  • None是真空,相当于其他语言中的null

案例5: return的使用

def mk_fib(n):
    result = [0,1]
    for i in range(n -2):
        result.append(result[-1]+result[-2])
    print(result)
    return result  #利用return返回result的值
a = mk_fib(8)  #已w方式打开,只能写入str类型的字符
with open('/tmp/result.txt','w') as f1:
    f1.write(str(a))   #将值写入文件中

运行测试:
[root@python day3]# python3 lianxi.py
[0, 1, 1, 2, 3, 5, 8, 13]
[root@python day3]# cat /tmp/result.txt
[0, 1, 1, 2, 3, 5, 8, 13][root@python day3]#

模块

  • 模块就是一个python程序文件
  • .py扩展名去除后的文件名就是模块名
  • 文件是物理上组织代码的形式
  • 模块是逻辑上组织代码的形式
[root@localhost day03]# vim star.py 
hi = 'Hello World!'

def pstar(n=50):
    print('*' * n)

[root@localhost day03]# vim mytest.py 
import star

print(star.hi)  调用star函数中的h1
star.pstar()  调用star函数中的pstar模块

[root@localhost day03]# python3 mytest.py 
Hello World!
**************************************************
  • 模块导入方法
# 常用方法:
# 一行导入一个模块
>>> import sys
>>> sys.path
# 仅导入模块的一部分方法
>>> from random import choice, randint  从random模块里导入choice和randint
>>> choice('abcd')
'b'
>>> randint(1, 100)
96

# 不常用方法:
# 一行导入多个模块
>>> import time, os, shutil
>>> import getpass as gp   # 导入模块时,添加别名
>>> passwd = gp.getpass()
Password: 
>>> passwd
'123'
  • 模块被导入时,它的代码会被执行一遍,这个叫加载load。不管导入多少次,只加载一次。
>>> import this     # the zen of python
>>> import this     # 不再显示the zen of python
  • 模块特殊属性: __name__
    • __name__是一个变量,它的值有两个:__main__ 和 模块名
    • 当模块文件直接运行时是__main__
    • 当模块文件被其他文件import时,是模块名
[root@localhost day03]# cat foo.py 
print(__name__)
[root@localhost day03]# cat new.py 
import foo
[root@localhost day03]# python3 foo.py   直接运行脚本name的值就为_main_
__main__
[root@localhost day03]# python3 new.py  当脚本被当作一个模块被其他文件调用时,name的值就为脚本名。
foo
  • 可以根据__name__的值判断模块文件是直接运行,还是被导入

案例6:编写随机生产密码的脚本

#!/usr/bin/env python3
from random import choice
zifuji = '123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
result='' #定义存储结果的变量
for i in range(8):
	zifu = choice(zifuji)
	result += zifu #result = result + zifu
print(result)

测试运行:
[root@python python]# python3 lianxi.py
pUjqxcWD

案例7:使用函数再次编写生成密码脚本

from random import choice
from string import ascii_letters,digits #digits表示所有数字
#ascii_letters是python已经写好的变量它表示所有大小写字母
zifuji = ascii_letters + digits

def rand_chs(n=8): #预先定义n的值
    result =''
    for i in range(n):
        zifu = choice(zifuji)
        result += zifu
    return  result  #将拼接好的值返回出去,不返回就为none(空)
if __name__ == '__main__': #以下内容只在直接运行此程序时输出
    s1 = rand_chs() #默认循环8次
    s2 = rand_chs(6) #为n重新定义新值
    print(s1)
    print(s2)

运行测试:
[root@python day3]# python3 lianxi.py
L4MGcvCX
VMuGRK

调用

此时我们可以新建一个文件来调用刚才写好的随机密码代码

import lianxi  #去掉脚本的后缀名就是模块名
s1 = lianxi.rand_chs(20) 利用函数功能生成一个长度为20位的密码
print(s1)
changdu  = len(s1)  验证密码长度是否为20print(changdu)

[root@python day]# python3 diaoyong.py
fmzLms5Dtxrdb6D0FYZQ
20

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章