python期末简答题及答案,python期末题库和答案

这篇文章主要介绍了python期末简答题及答案,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。

期末复习知识点总结

第一章

1.6 Python编程规范与代码优化建议
1.7 模块 模块的导入方式

补:Python编程规范与代码优化建议

  • 注释

    以符号#开始,表示本行#之后的内容为注释。

    #eg1_2.py coding=gbk
    n = int(input("请输入一个整数:"))
    k=1;sum=0
    for i in range(1,n+1):
        sum=sum+k
    print("sum=",sum)
    
  • 缩进

    • 类定义、函数定义、选择结构、循环结构、with快,行尾的冒号表示缩进的开始python turtle画三角形的树
    • Python是依靠代码块的缩进来体现代码之间的逻辑关系的,缩进结束就表示一个代码块结束了。
    • 同一个级别的代码块的缩进量必须相同。
    • 以4个空格为基本缩进单位。
  • 最好在每个类、函数定义和一段完整的功能代码之后增加一个空行

    def empty(self):
      self._content = []
      self._current = ()
    
    def isEmpty(self):
      return not self._content
    
  • 尽量不要写过长的语句。如果语句确实太长而超过屏幕宽度,最好使用续行符\,或者使用圆括号将多行代码括起来表示是一条语句。

    x = 1+2+3\
        +4+5\
        +6
    y= (1+2+3
       +4+5
       +6)
    
  • 虽然Python运算符有明确的优先级,但对于复杂的表达式建议在适当的位置使用括号使得各种运算的隶属关系和顺序更加明确、清晰。

  • 每个import语句只导入一个模块,最好按标准库、扩展库、自定义库的顺序依次导入。

    import csv
    import random
    import datetime
    import pandas as pd
    import matplotlib.pyplot as plt
    
模块
  • 模块是一种程序的组织形式。它将彼此具有特定关系的一组Python可执行代码、函数或类组织到一个独立文件中,可以供其它程序使用。

  • 模块可以分为标准模块和第三方模块。

    • 标准模块:安装好Python后,本身就带有的模块被称为标准模块,也被称为Python的标准库。
    • 第三方模块:并不是Python的标准库,在使用import语句前必须提前安装到开发环境中。
模块导入的方式
  • import 模块名

    这种方法一次可以导入多个模块。但在使用模块中的类、方法、函数、常数等内容时,需要在它们前面加上模块名。

    >>> import math
    >>> math.pow(2,3)
    8.0
    
  • import moduleName1 as name2

    >>> import math as a
    >>> a.pow(2,3)
    8.0
    
  • from moduleName import *

    这种方法一次导入一个模块中的所有内容。使用时不需要添加模块名为前缀。

    >>> from math import*
    >>> pow(2,3)
    8.0
    >>> sqrt(9)
    3.0
    
  • from moduleName import object1[,object2[...]]

    这种方法一次导入一个模块中指定的内容,如某个函数。调用时不需要添加模块名为前缀。

    >>> from math import pow,e
    >>> e
    2.718281828459045
    >>> pow(2,3)
    8.0
    

第二章

了解变量的命名规则
知道 type函数和isinstance函数功能
input()函数 、eval()函数、 print()函数

2.2.3 命名与保留字

标识符命名规则:

  • 标识符由**大小写字母、数字、下划线、汉字**组成
  • 变量名**不能以数字**开头
  • 变量名是**区分大小写**的
  • 变量名不能有空格以及标点符号(括号、引号、逗号、斜线、反斜线、冒号、句号、问号等)

下列哪些是合法的变量名

A、6a2b、aBc、abc-123、ab_123、_ _、hello world

保留字,也称关键字,指被编程语言内部定义并保留使用的标识符。

and, elif, import, raise, as, else, in, return, assert, except, is, try, break, finally, lambda, while, class, for, nonlocal, with, continue, from, not, yield, def, global, or, True, del, if, pass, False, None

type函数
  • 功能:type()函数查看变量类型
  • 格式:type(变量)
>>> a=100
>>> type(a)
<class 'int'>
isinstance函数
  • 功能:isinstance函数判断变量是否为指定的类型

  • 格式:isinstance(变量,类型)

>>> a=100
>>> isinstance(a,int)
True
input()函数
  • 功能:input()函数执行时在屏幕上显示提示字符串,用户输入完毕后,并将用户输入都以文本形式返回。

  • 格式:<变量>=input(<提示性文字>)

    >>> x=input("请输入x值:")
    请输入x值:100
    >>> x
    '100'   # 字符类型
    

    input的所有值都是以文本形式表达的

eval()函数
  • 功能:eval()函数用于执行一个字符串表达式,并返回表达式计算结果值

  • 格式:eval(<字符串>)

>>> x =4 
>>> "3*x"
'3*x'
>>> eval('3*x')
12
>>> eval('pow(x,2)')
16
>>> eval("'3*x'")
'3*x'
print()函数
  • 功能:print()函数用来输出字符信息。print()函数可以输出各种类型变量的值

  • 常用格式:

    1.print(): 用于输出一个空白行

    2.print(<表达式>): 在屏幕显示表达式的值

    3.print(<表达式1>, <表达式2>, …, <表达式n>): 将各表达式的值从左到右显示在同一行

[例]

print("Hello")
print()         # 输出一个空白行
print(3+2,1+2,"hello")  
print("here")  
print(3+2,1+2,"hello",end=";")  # 用分号作为分隔符,把回车符修改掉打在同一行
print("here")

程序结果:

Hello

5 3 hello
here
5 3 hello;her

[例]

a ="有理想"
print(a,"有担当")
print()
print("有本领",end="")
print("青年一代")

运行结果:

有理想 有担当

有本领青年一代

思考题:#TempConvert_1.py

  • 让用户输入摄氏度C,输入对应的华氏度F

  • 公示:F = C *1.8 + 32

  • 样例:

请输入摄氏度:25
25对应的华摄度为:77.0
C = eval(input("请输入摄氏度:"))
F = C * 1.8 + 32
print(C,"对应的华摄度为:",F)

程序结果:

请输入摄氏度:25
25 对应的华摄度为: 77.0

第三章

熟悉 数据类型
3.2.1 算术运算操作符

3.2.2关系运算操作符

3.2.3逻辑运算符
abs(x)
divmod(x, y)
pow(x, y[, z])
round(x[, ndigits])
max(x1, x2, …, xn)
min(x1, x2, …, xn)
int(x)
float(x)
complex(re[, im])
map()
3.5 字符串类型及其操作
3.5.1字符串类型
3.5.2 基本的字符串操作符 + * in not in
操作
len(x)
str(x)
chr(x)
ord(x)

str.replace()
str.split()
str.join()
str.count()
str.find()
str.trip()

str.upper()
str.lower()
str.islower()
str.isupper

3.2.1 内置的数值运算操作符
操作符描述
x+yx与y之和
x-yx与y之差
x*yx与y之积
x/yx与y之商
x//yx与y之整数商,向下取整
x%yx与y之商的余数
-xx的负值,即:x*(-1)
+xx本身
x**yx的y次幂 x y x^y xy,等价于pow(3,2)
  • +运算符还可以用于列表、元组、字符串的连接,但不支持不同类型的对象之间相加或连接。

    >>> [1,2,3]+[4,5,6]   # 连接两个列表
    [1, 2, 3, 4, 5, 6]
    >>> (1,2,3)+(4,)     # 连接两个元组
    (1, 2, 3, 4)
    >>> 'ab'+'12'        # 连接两个字符串
    'ab12'
    
  • *运算符还可以用于列表、元组、字符串类型与整数的乘法,表示序列元素的重复,生成新的序列对象。

    >>> [1,2,3]*3
    [1, 2, 3, 1, 2, 3, 1, 2, 3]
    >>> (1,2,3)*3
    (1, 2, 3, 1, 2, 3, 1, 2, 3)
    >>> 'abc'*3
    'abcabcabc'
    
    
  • Python还有赋值运算符+=、-=、*=、/=、//=、**=、%=等大量复合赋值运算符。

    例如:x+=3等价于x=x+3

练习题:

1.语句a=(3/4)+3%2;运行后,a的值为( )。a=0.75+1=1.75

2.若x=3.5;z=8x+z%3/4的值为( ). 3.5+(8%3)/4=3.5+8%3/4=3.5+2/4=3.5+0.5=4.0

3.设f=g=2.0,使f为4.0的表达式是( ). D

A. f/=g*10 # f=f/(g*10)=2/20=0.1

B. f-=g+2 # f=f-g-2=-2

C. f*=g-6 # f=f*(g-6)=2 *(2-6)=-8

D. f+=g # f= f+g=4

  1. x=1,x*=3+5**2的值为( ) x*=x*(3+25)=1*28=28

思考与练习

请将下面数学表达式用Python写出来,并运算结果。

1. x = ( 2 4 + 7 − 3 × 4 ) 5 x=\frac{(2^4+7-3\times4)}{5} x=5(24+7−3×4)​

2. x = ( 1 + 3 2 ) × ( 16 m o d 7 ) / 7 x=(1+3^2)\times(16 mod 7)/7 x=(1+32)×(16mod7)/7

>>> x=(2**4+7-3*4)/5
>>> x
2.2

>>> x=(1+3**2)*(16%7)/7
>>> x
2.857142857142857
关系运算操作符 补充

关系运算符根据表达式的值得真假返回布尔值:

<(小于)、> (大于)、<= (小于等于)、 >=(大于等于)、 ==(等于)、!=(不等于)

Python关系运算符最大的特点是可以连用。如5>2<7

>>> a = 3
>>> a == 2
False
>>> 1<a<5    # 等价于1<a 且 a<5
True
>>> 5<a>1
False

思考

1.让用户输入一个值赋值给x,判断x是否为’男‘

2.让用户输入一个值赋值给x,判断x是否在[0,100]间

>>> x=input("")
>? 男
>>> x == "男"
True
>>> x=int(input())
>? 45
>>> 0<=x<=100
True
逻辑运算符 补充

逻辑运算符将表达式连接在一起,一般会返回布尔值

and(与):两边都是真,结果为真
or(或):只要一个为真,结果为真
not(非):取反

>>> x = False
>>> y = True
>>> x or y
True
>>> not (x or y)
False
>>> not x or y
True
>>> i = 7
>>> j = 8
>>> i>=j and i<j
False
>>> a=5; b=2; c=1
>>> a-b>2 or b ==c
True

习题

1.若希望当a的值为奇数时,表达式的值为“真”,a的值为偶数时,表达式的值为“假”。则不能满足要求的表达式是( ) C

A. a%2 ==1

B. not a%2 == 0

C. not a%2 # not 8%2 = True not 9%2 =False

D. a%2

2.判断t是否为闰年。闰年的条件:年份t能被400整除,或者能被4整除但不能被100整除。

t = eval(input("请输入年份:"))
if t%400==0 or t%4==0 and t%100!=0:
    print(str(t)+"年是闰年")
else:
    print(str(t)+"年不是闰年")

and和or具有惰性求值或逻辑短路的特点,当连接多个表达式时只计算必须要计算的值

>>> 3<5 or a>3  # a没有定义
True
>>> 3>5 or a>3 # a没有定义
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'a' is not defined
3.2.2 内置的数值运算函数

Python解释器提供了一些内置函数,在这些内置函数之中,有6个函数与数值运算相关

函数描述
abs(x)x的绝对值
divmod(x,y)(x//y,x%y)求商和余数,输出为二元组形式(也称为元组类型)
pow(x,y[,z])(x**y)%z 求幂,[…]表示该参数可以省略,即pow(x,y),它与x**y相同
round(x[,ndigits])对x四舍五入,保留ndigits位小数。round(x)返回四舍五入的整数值
max(x1,x2,…,xn)求最大值,n没有限定
min(x1,x2,…,xn)求最小值,n没有限定
>>> x=-100
>>> y=abs(x)
>>> y
100
>>> x=10
>>> y=3
>>> z=divmod(x,y)
>>> z
(3, 1)
>>> x=10
>>> y=2
>>> z=3
>>> m=pow(x,y,z)
>>> m
1
>>> x = 3.14159
>>> round(x,2)
3.14
>>> a = [3,0,5]
>>> max(a)
5
>>> min(a)
0
>>> sum(a)
8
3.2.3 内置的数字类型转换函数
函数描述
int(x)将x转换为整数,x可以是浮点数或字符串
float(x)将x转换为浮点数,x是整数或字符串
complex(re[,im])生成一个复数,实部为re,虚部为im,re可以是整数、浮点数或字串符,im可以是整数或浮点数但不能为字符串
>>> int("123")
123
>>> int(0b10)
2
>>> int(0o10)
8
>>> int(0x10)
16
>>> int(-2.34)
-2
>>> float(3)     # 把整数转换为实数
3.0
>>> float('3.5')  # 把数字字符串转换为实数
3.5
>>> complex(3)    # 指定实部
(3+0j)
>>> complex(3,5)  # 指定实部和虚部
(3+5j)
map()

==map()是接收一个函数f依次映射到序列或迭代对象上的每个元素,并返回一个map对象。==格式:

map(函数f,list数据)

>>> x,y=map(int,["45","56"])
>>> x,y
(45, 56)
>>> a,b=map(round,[3.4546,4.6757],(3,2))
>>> a,b
(3.455, 4.68)
>>> round(3.4546,3)
3.455
>>> round(4.6757,2)
4.68

思考

Exer1:用户输入一个三位自然数,计算并输出其百位、十位和个位上的数字。

x = int(input("请输入一个三位自然数:"))      
a = x//100
b = (x-a*100)//10
c = x-a*100-b*10
print("百位数字为:"+str(a),"十位数字为:"+str(b),"个位数字为:"+str(c))

程序结果:

请输入一个三位自然数:324
百位数字为:3 十位数字为:2 个位数字为:4
x=int(input())      # 324
a=x//100            # 3
b=x//10%10          # 324//10 = 32 32%10=2
c=x%10              # 324%10=4
print(a,b,c)
i=input("请输入一个三位自然数:")
print("百位数字为"+i[0])
print("十位数字为"+i[1])
print("个位数字为"+i[2])
x=int(input('请输入一个三位数:'))
a,b=divmod(x,100)
b,c=divmod(b,10)
print(a,b,c)
x=input("请输入一个三位数:")
a,b,c=map(int,x)  
print(a,b,c)

3.5 字符串类型及其操作

  • 字符串是用双引号“”或者单引号''括起来的一个或多个字符
  • 字符串对象是不可变的。字符串对象提供的涉及到字符串”修改“的方法都是返回修改后的新字符串,并不对原始字符串做任何修改。
3.5.1 字符串类型的表示

字符串是一个字符序列:字符串最左端位置标记为0,依次增加。字符串中的编号叫做”索引“。

012345678910
  • 单个索引辅助访问字符串中的特定位置

格式为:<string>[<索引>]

  • 切片,通过两个索引值返回一个子串

格式为:<string>[<start>:<end>:step]

  • 这个子序列从索引start开始直到索引end结束,但不包括end位置。step代表步长
>>> a='国无德不兴 人无德不立'
>>> a[2]
'德'
>>> x=8
>>> a[x-2]
'人'
>>> a[-7]
'兴'
>>> a[-11:-7]        
'国无德不'
>>> a[1:-1]
'无德不兴 人无德不'
>>> a[2:-2:2]
'德兴人德'

反斜杠字符(\)是一个特殊字符,在字符串中表示转义,即该字符与后面相邻的一个字符共同组成了新的含义。

\n:表示换行

\\:表示反斜杠

\':表示单引号

\"表示双引号

\b:退格,把光标移动到前一列位置

\f:换页符

\n:换行符

\r:回车

\v:垂直制表符

\ooo:3位八进制数对应的字符

\xhh:2位十六进制数对应的字符

\uhhhh:4位十六进制数表示的Unicode字符

\t:表示制表符(Tab)等。

>>> print("Python\n语言\t程序\t设计")
Python
语言	程序	设计
>>> print("c:\\now")
c:\now
>>> a= 'Let\'s go'
>>> print(a)
Let's go
3.5.3 基本的字符串操作符

字符串之间可以通过+或*进行连接

  • 加法操作(+)将两个字符串连接成为一个新的字符串

  • 乘法操作(*)生成一个由其本身字符串重复连接而成的字符串

    >>> "pine"+"apple"
    'pineapple'
    >>> 3*'pine'
    'pinepinepine'
    
操作符描述
x in s如果x是s的元素,返回True,否则返回False
x not in s如果x不是s的元素,返回True,否则返回False
>>> c='cat,dog'
>>> "d" in c
True
>>> "z" in c
False
>>> "z" not in c
True

思考1:A=“5”+“8” A的值是多少? ’ 58’

思考2:name=”志存高远、脚踏实地“;name[5:]、name[0:-1]、name[:5]、name[0:-5]的值分别是多少?

>>> name="志存高远、脚踏实地"
>>> name[5:]
'脚踏实地'
>>> name[0:-1]
'志存高远、脚踏实'
>>> name[:5]
'志存高远、'
>>> name[0:-5]
'志存高远'

[例]获取星期字符串

程序读入一个表示星期几的数字(1~7),输出对应的星期字符串名称。例如,输入3,返回“星期三”。代码如下:

weekstr = "星期一星期二星期三星期四星期五星期六星期日"
weekid=eval(input("请输入星期数字(1-7):"))
pos = (weekid-1)*3
print(weekstr[pos:pos+3])

程序结果:

请输入星期数字(1-7):3
星期三
3.5.3 内置的字符串处理函数
操作含义
len(x)返回字符串x的长度,也可返回其他组合数据类型元素个数
str(x)返回任意类型x所对应的字符串形式
chr(x)Unicode码对应的单个字符
ord(x)返回单字符表示的Unicode编码
hex(x)返回整数x对应十六进制数的小写形式字符串
oct(x)返回整数x对应八进制的小写形式字符串
bin(x)整数转换为二进制形式字符串
>>> len("pine")
4
>>> len("祖国,你好!")
6
>>> bin(16)
'0b10000'
>>> oct(16)
'0o20'
>>> hex(16)
'0x10'
>>> ord('A')
65
>>> chr(65)
'A'
>>> chr(ord('A')+1)
'B'

3.5.4 内置的字符串处理方法
操作含义
str.upper()字符串中字母大写
str.lower()字符串中字母小写
str.islower()判断字符串是否都是小写,是时,返回True,否则False
str.isnumeric()判断字符串是否都是数字,是时,返回True,否则False
str.isdigit()同str.isnumeric()
str.isupper()判断字符串是否都是大写,是时,返回True,否则False
str.isspace()当str所有字符都是空格,返回True,否则返回False
str.replace(old,new[,count])返回字符串str的副本,所有old子串被替换为new,如果count给出,则前count次old出现被替换。查找字符串所有匹配项并替换,返回字符串。
str.split(sep=None,maxsplit=-1)返回一个列表,由str根据sub子串出现的次数。用来将字符串分隔成序列。如果不指定分隔符,则空格、换行符、制表符等都将被认为是分隔符,把连续多个空白字符看作一个分隔符。
str.join(iterable)用来连接元组、列表等中的元素,注意其元素一定要是字符串。返回一个新字符串,由组合数据类型iterable变量的每个元素组成,元素间用str分隔。
str.find()可以在一个较长的字符串中查找子串,并返回子串所在位置的左端索引位置,如果没有找到则返回-1
str.strip([chars])去掉字符串两侧的空格,并返回字符串。返回字符串str的副本,在其左侧和右侧去掉chars中列出的字符。
str.count()统计子字符串出现的次数
>>> a='Python'
>>> a.lower()
'python'
>>> a.upper()
'PYTHON'
>>> string = 'Python is a programming language.'
>>> string.replace('a','A')
'Python is A progrAmming lAnguAge.'
>>> string.split()
['Python', 'is', 'a', 'programming', 'language.']
>>> s="2017-10-31"
>>> s.split("-")
['2017', '10', '31']
>>> a=["1","2"]
>>> "t".join(a)   # "t"为连接符
'1t2'
>>> b=s.split("-")
>>> '/'.join(b)
'2017/10/31'
>>> s="apple,peach,banana,peach,pear"
>>> s.find("peach")
6
>>> s.find("peach",7)  #从7位置字符开始往后找
19

>>> string = '   Python is a programming languages'
>>> string.strip()
'Python is a programming languages'

思考题:

>>>x='aaa bb c d e fff '
>>>b=','.join(x.split())
>>>b
结果为:
'aaa,bb,c,d,e,fff'
>>>b.replace("c",'cc').upper()
'AAA,BB,CC,D,E,FFF'

测试题:

  1. 复数 z,_________________________________可获得它的实数部分。 z.real

  2. 下面类型中,Python不支持的数据类型有( ) A.double

A.double B.int    C.float D.list

  1. 关于Python内存管理,下列说法错误的是 B.

A.变量不必事先声明

B.变量无须先创建和赋值而直接使用

C.变量无须指定类型

D.可以使用del释放资源

4.下列表达式的值为True的是( ) C

A.5<3>1 B.3>2>2 C.5%2 D.‟abc‟ > “xyz‟

5.下列表达式的值为True的是( ) C

A.(2**=3)<(2*=3)  # 2**=3 2=2^3 x 正常写应该为 a**=2 a=a^2 ;

B.3>2 and 5<2

C.1==1 and 2!=1

D.not(1==1 and 0!=1) #括号里头为True但加上 not则为False

6.a=3*4**2/8%5,a的值是 1 a=3 * 4 * * 2/8%5=3 * 4^2/8%5=3 * 16/8 %5=6 % 5 =1

7.判断t是否为润年。润年的条件:年份t能被400整除,或者能被4整除但不能被100整除

(t%400==0) or (t%4==0 and t%100 !=0)

8.x=3;y=4;z=5下面选项中哪个值为True( ) B

A. x and y B.x<=y C. z or x D.not x A.4 ;B.True; C.5;D.False

9.请将下面数学表达式用Python写出来,并运算结果x=(2^4+7-3×4)/5

x=(2^4+7-3*4)/5=(16+7-12)/5=(23-12)/5=1111/5=2.2

10.请将下面数学表达式用Python写出来x=(1+3^2)×(16 mod 7)/7

x=(1+3^2)*(16%7)/7=(1+9)*(2)/7=(10)*2/7=20/7=2.857142

4.5 模块2:random库的使用

要点:随机运算的标准函数库random共提供9个常用函数

4.5.1 random库概述
  • Python内置的random库主要用于产生各种分布的伪随机数序列
  • random库采用梅森旋转算法生成伪随机数序列,可用于除随机性要求更高的加解密算法外的大多数工程应用
  • 这个库提供了不同类型的随机数函数,所有函数都是基于random.random()函数扩展而来
函数描述
seed(a=None)初始化随机数种子,默认值为当前系统时间
random()生成一个[0.0,1.0)之间的随机小数
randint(a,b)生成一个[a,b]之间的整数
getrandbits(k)生成一个k比特长度的随机整数
randrange(start,stop[,step])生成一个[start,stop]之间以step为步数的随机整数
uniform(a,b)生成一个[a,b]之间的随机小数
choice(seq)从序列类型,例如列表中随机返回一个元素
shuffle(seq)将序列类型中的元素随机排列,返回打乱后的序列
sample(pop,k)从pop类型中随机选取k个元素,以列表类型返回
>>> import random       
>>> random.random()     # 调用系统时间这个种子 每次都会不一样
0.5018134450345285      
>>> random.random()
0.032973558931030156
>>> random.random()
0.6449492388301401

>>> random.seed(2)      # 调用这个种子 可以使产生的随机数一样 即种子一样
>>> random.random()     
0.9560342718892494      
>>> random.seed(2)
>>> random.random()
0.9560342718892494

>>> random.uniform(2,5)   
3.8885526850015695
>>> random.random()*3+2   # (0,1) 上下两者区别是5是否能取到

>>> random.randint(1,5)
5
>>> random.randint(1,5)
2

>>> random.getrandbits(3)   # 随机整数占k比特,即 000-111之间二进制 1-7
7
>>> random.getrandbits(2)   # 00-11  1-3
1

>>> random.randrange(0,100,4)  # 产生一个[0,100)间能被4整除的随机整数
76
>>> random.randrange(0,100,4)
40

>>> random.choice([1,3,6,7,8])
1
>>> random.choice(range(1,50))
8

>>> random.sample([1,3,6,7,8],2)
[7, 8]

>>> a=list(range(1,10))
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> random.shuffle(a)
>>> a
[8, 3, 9, 7, 6, 4, 5, 1, 2]

思考与练习

思考hw3.py:编写程序,生成一个字符串,该字符串由随机生成10个不重复的小写字母组成。输出该字符串。

import random                         
n=0                                   
s=[]                                  
while n<=10:                          
    s.append(random.randint(65,90))   
    n=n+1                             
print(s)                              
h=[]                                  
for i in s:                           
    a=chr(i).lower()                  
    h.append(a)                       
print(h)                              

结果:

[88, 68, 72, 65, 66, 78, 80, 78, 80, 87, 87]
['x', 'd', 'h', 'a', 'b', 'n', 'p', 'n', 'p', 'w', 'w']
import random
z=""
for i in range(0,26):
    z += chr(ord("a")+i)
print(''.join(random.sample(z,10)))

结果:

xnkfrscvuq
import random
list1="";i=0
while i<10:
    c=chr(random.randint(ord('a'),ord('z')))
    if c not in list1:
        i += 1
        list1=list1+c
print(list1)

4.7 程序的异常处理

要点:Python通过try、except等保留字提供异常处理功能

4.7.1 异常处理:try-except语句
num = eval(input("请输入一个整数:"))
print(num**2)

结果:

请输入一个整数:3
9

请输入一个整数:NO
Traceback (most recent call last):           # Traceback 异常回溯标记
  File "/Users/eve/Desktop/PYTHON/SchoolCourse/第4章 程序控制结构/code/eg444.py", line 1, in <module>     # “/Users...py”异常文件路径   line 1 异常发生的代码行数
    num = eval(input("请输入一个整数:"))
  File "<string>", line 1, in <module>
NameError: name 'NO' is not defined    # NameError异常类型  name...defined 异常内容提示

  • 异常是在程序执行过程中发生的影响程序执行的一个事件。
  • 异常是Python对象,当Python无法正常处理程序时就会抛出一个异常
  • 一旦发生异常,程序需要捕获并处理它,否则程序会终止执行
  • 异常处理使程序能够处理完异常后继续它的正常执行,不至于使程序因异常导致退出或崩溃

异常处理基本语法如下:

try:
  <可能出现异常的语句块>               # 正常执行的程序内容
except <异常类name1>[as 原因变量]:    # 当发生异常时执行except保留字后面的语句块
  <异常处理语句块1>
# 如果try中的代码抛出异常类name1
# 并被except捕捉,就执行这里的代码

[例]

try:
    1+"1"
except TypeError as t:
    print("数据类型不一致",t)

结果:

数据类型不一致 unsupported operand type(s) for +: 'int' and 'str'

拓展:异常和错误

编程语言的异常和错误是两个相似但不同的概念。异常和错误都可能引起程序执行错误而退出,它们属于程序没有考虑到的例外情况(exception)。然而,绝大多数不可控因素是可以预见的,例如,程序期望获得数字输入却得到了其他字符输入、打开一个不存在的文件等。这种可以预见的例外情况称为”异常“(checked exception),异常发生后经过妥善处理可以继续执行。另外一些因为程序编码逻辑产生的不可预见的例外情况称为”错误“(unchecked exception),错误发生后程序无法恢复执行,而且程序本不该处理这类可能的例外,例如,对于一个包含5个字符的字符串,程序去索引其中第6个元素,这种错误完全可以避免。


思考#si4_5.py: 当输入4、'ab’执行结果分别是什么?

try:
  num = eval(input("请输入一个整数:"))
  print(num**2)
except NameError:
  print("输入错误,请输入一个整数!")

程序结果:

请输入一个整数:4
16

请输入一个整数:ab
输入错误,请输入一个整数!

思考#si4_6.py: 若在执行print(8/0)语句时,要捕捉ZeroDivisionError异常,并输出系统报错的原因

如何实现代码

try:
    print(8/0)
except ZeroDivisionError as t:
    print(t)

结果:

division by zero
  • 矛盾存在于一切事物中,并且贯穿于事物发展过程的始终,即矛盾无处不在,矛盾无时不有
  • 善于全面分析矛盾,防止片面性
4.7.2 异常的高级用法

除了最基本的try-except用法,Python异常还有一些略微高级的用法,这些方法在实际程序设计中也十分常用。

try-except语句可以支持多个except语句,语法格式如下:

try:
  <语句块1>
except <异常类型1>:
  <语句块2>
...
except <异常类型 N>:
  <语句块 N+1>
except:
  <语句块 N+2>
  

其中,第1到第N个except语句后面都指定了异常类型,说明这些except所包含的语句块只处理这些类型的异常。最后一个except语句没有指定任何类型,表示它对应的语句块可以处理所有其他异常。这个过程与if-elif-else语句类似,是分支结构的一种表达方式,例如如下代码:

try:
  alp="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  idx=eval(input("请输入一个整数:"))
  print(alp[idx])
except NameError:       # 当用户输入非整数字符时,except NameError异常被捕获到,提示用户输入类型错误
  print("输入错误,请输入一个整数!")
except:              # 当用户输入数字不在0-25之间时,异常被except捕获,程序打印其他错误信息
  print("其他错误")
>>>
请输入一个整数:No
输入错误,请输入一个整数!
>>>
请输入一个整数:100
其他错误

除了try和except保留字外,异常语句还可以与else和finally保留字配合使用,语法格式如下:

try:
  <语句块1>
except <异常类型1>:
  <语句块2>
else:     #此处的else语句与for循环和while循环中的else一样,当try中的语句块1正常执行结束且没有发生异常时,else中的语句块3执行,可以看作是对try语句块正常执行后的一种追加处理
  <语句块3>
finally:    # 无论try中的语句块1是否发生异常,语句块4都会执行,可以将程序执行语句块1的一些收尾工作放这里,例如关闭、打开文件等
  <语句块4>

采用else和finally修改代码如下:

try:
  alp="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  idx=eval(input("请输入一个整数:"))
  print(alp[idx])
except NameError:       # 当用户输入非整数字符时,except NameError异常被捕获到,提示用户输入类型错误
  print("输入错误,请输入一个整数!")
else:
  print("没有发生异常")
finally:
  print("程序执行完毕,不知道是否发生了异常")

执行结果和结果如下:

>>>
请输入一个整数: 5
F
没有发生异常
程序执行完毕,不知道是否发生了异常
>>>
请输入一个整数:NO
输入错误,请输入一个整数!
程序执行完毕,不知道是否发生了异常
  1. 下面哪个代码不能随机生成100内的1个整数( ) # C

A.random.sample(range(0,100),1) # [82]

B.random.randint(0,100) # 94

C.random.getrandbits(100) # 618015465451243308573761656840 生成一个k比特长度的随机整数

D.random.randrange(0,101,1) # 55

2.下面代码哪个能随机选取0到100间的奇数( ) A

A.random.randrange(1,101,2) # 1到100 间的奇数

B.random.randint (0,100) # 0到99任意整数

C.int(random.uniform(0,100)) # 0到99任意小数

D.random.choice(range(1,100)) # 1到99

3.下面哪个代码能从字符串’abcdefghij’中随机选取4个字符 A

A.random.sample(“abcdefghij”,4)

B.random.choice(“abcdefghij”,4)

C.random.uniform(“abcdefghij”,4)

D.random.random(“abcdefghij”,4)

4.下面哪个代码不能随机选取列表a=[‘apple’, ‘pear’, ‘peach’, ‘orange’]中的1个字符串 B

A. random.choice(a)

B. random.shuffle(a) # 将序列类型中的元素随机排列,返回打乱后的序列

C. random.sample(a,1)

D. t=random.randint(0,3) a[t]

5.下面哪个代码能随机生成【2 , 6】之间的一个小数 C

A.random.random()*4+2 # 1之间 * 4 = 4之间的小数 + 2 6取不到

B.random.randint(2.6)

C.random.uniform(2,6)

D.random.randrange(2,6)

第五章

5.1.1函数的定义

5.1.2函数调用的过程

5.1.3函数返回值

5.2.1默认值参数和可变数量参数 一个*

5.2.2位置参数和关键参数

变量作用域 global

5.1 函数的基本使用

5.1.1 函数的定义

定义:函数是一段具有特定功能的、可重用的语句组,用函数名来表示并通过函数名进行功能调用。

使用函数的目的:降低编程难度和代码重用。

函数也可以看作是一段具有名字的子程序,可以在需要的地方调用执行,不需要在每个执行的地方重复编写这些语句。严格地说,函数一种功能抽象。

有些函数是用户自己编写的,称为自定义函数;Python安装包也自带了一些函数和方法,包括Python内置的函数(如abs()、eval())、Python标准库中的函数(如math库中的sqrt()等)

Python使用def保留字定义一个函数,语法形式如下:

def <函数名>(<参数列表>):
  <函数体>
  return<返回值列表>

函数名:可以是任何有效的Python标识符

参数列表:调用该函数时传递给它的值,可以有零个、一个或多个,当传递多个参数时各参数逗号分隔,当没有参数时也要保留圆括号。

形式参数:函数定义中参数列表里面的参数是形式参数,简称为”形参“。

函数体:函数每次被调用时执行的代码,由一行或多行语句组成。

当需要返回值使,使用保留字return和返回值列表,否则函数可以没有return语句,在函数体技术位置将控制权返回给调用者。

函数调用和执行的一般形式如下:

<函数名>(<参数列表>)

实际参数:此时,参数列表中给出要传入函数内部的参数,简称“实参”。

例5.1 生日歌

过生日时要为朋友唱生日歌,歌词为

Happy birthday to you!

Happy birthday to you!

Happy birthday, dear<名字>

Happy birthday to you!

编写程序为Mike和Lily输出生日歌。最简单的实现方式是重复使用print()语句,对Mike的生日歌输出如下:

print("Happy birthday to you!")
print("Happy birthday to you!")
print("Happy birthday, dear Mike!")
print("Happy birthday to you!")

结果:

Happy birthday to you!
Happy birthday to you!
Happy birthday, dear Mike!
Happy birthday to you!

为了能够复用语句,考虑将代码修改为:

#m5.1HappyBirthday.py
def happy():
	print("Happy birthday to you!")

def happyB(name):
	happy()
	happy()
	print("Happy birthday, dear {}!".format(name))
	happy()

happyB("Mike")
print()
happyB("Lily")

第5行中定义了一个函数happyB(),包括中的name是形参,用来指代要输入函数的实际变量,并参与完成函数内部功能。第11行和第13行调用两次happyB()函数,输入的”Mike“和”Lily“是实参,替换name,用于函数执行。类似执行了如下语句

name = "Mike"

屏幕快照 2020-05-20 17.40.07

程序输出如下:

>>>
Happy birthday to you!
Happy birthday to you!
Happy birthday, dear Mike!
Happy birthday to you!

Happy birthday to you!
Happy birthday to you!
Happy birthday, dear Lily!
Happy birthday to you!
5.1.2 函数的调用过程

程序调用一个函数需要执行以下4个步骤。

(1)调用程序在调用处暂停执行。

(2)在调用时将实参复制给函数的形参。

(3)执行函数体语句。

(4)函数调用结束给出返回值,程序回到调用前的暂停处继续执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJYxtPpt-1593709010936)(https://i.loli.net/2020/05/20/aKz6ilULAwC4oN3.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XcTboVje-1593709010938)(https://i.loli.net/2020/05/20/ilugR9QbWDO2eVN.png)]


拓展:函数式编程

函数式编程是一种编程范式,常见的编程范式还包括命令式编程和面向对象编程等。函数式编程的主要思想是把程序过程尽量写成一系列函数调用,通过函数进一步提高封装级别。函数式编程通过使用一系列函数能够使代码编写更简洁、更易于理解,是中小规模软件项目中最常见的编程方式。


5.1.3 函数返回值
#eg5_2sum.py
def sum(number1,number2):
  total=number1+number2

print(sum(1,2))

运行结果:None

思考5_1:

def circle(r):
  if r<=0:
    print("要求输入正数!")
    return
  area=3.14*r*r
  perimeter=2*3.14*r
  return area,perimeter

r=-3
re=circle(r)

if re!=None:
  print("半径为",r,"的面积为:",re[0])
  print("半径为",r,"的圆周长为:",re[1])

运行结果为:

要求输入正数!

5.2 函数的参数传递

要点:函数可以定义可选参数,使用参数的位置或名称传递参数值,根据函数中变量的不同作用域有不同的函数返回值方式。

5.2.1可选参数和可变数量参数

在定义函数时,如果有些参数存在默认值,即部分参数不一定需要调用程序输入,可以在定义函数时直接为这些参数指定默认值。当函数被调用时,如果没有传入对应的参数值,则使用函数定义时的默认值替代。例如:

def dup(str, times=2):
	print(str*times)

dup("knock~")
dup("knock~",4)

程序输出结果:

knock~knock~
knock~knock~knock~knock~

由于函数调用时需要按顺序输入参数,可选参数必须定义在非可选参数的后面,即dup()函数中带默认值得可选参数times必须定义在str参数后面。

只有在形参表末尾的参数可以有默认参数值,不能先声明有默认值的形参而后声明没有默认值的形参

如:

def func(a,b=5)是有效的
def func(a=5,b)是无效的

==在函数定义时,也可以设计变量参数,通过在参数前增加(*)实现。==带有星号的可变参数只能出现在参数列表的最后。调用时,这些参数被当作元组类型传递到函数中,实例如下:

def vfunc(a,*b):
	print(type(b))
	for n in b:
		a += n
	return a

vfunc(1,2,3,4,5)

vfunc()函数定义了可变参数b,调用vfunc()函数时输入的(2,3,4,5)被当作元组传给b,与a累加后输出。

python的type函数有两个用法,当只有一个参数的时候,返回对象的类型。当有三个参数的时候返回一个类对象。

例:思考下面程序的运行结果:

#coding=utf-8
def Say(s="团结",n=2,m=1):
	for i in range(1,n+1):
		print(s*m)

Say()
print
Say("合作!",3,4)
print
Say("合作!")

结果:

团结
团结
合作!合作!合作!合作!
合作!合作!合作!合作!
合作!合作!合作!合作!
合作!
合作!

可变数量参数:在python中,若形参可以接收不定个数的参数,该形参称为可变数数量参数。

                       可变长度参数在定义函数时主要有两种形式:*parameter和**parameter

*parameter方式:无论调用时传递了多少实参,都放入元组。列如:

def all_1(*args):
	print('有',len(args),'个参数',':',args)

all_1("团结合作","携手应对")
all_1("团结合作","携手应对",'守望相助')

形参args此时为一个元组,结果:

有 2 个参数 : ('团结合作', '携手应对')
有 3 个参数 : ('团结合作', '携手应对', '守望相助')

**parameter方式:自动将接受的参数转换为字典。

def all_2(**args):
	print(args)

all_2(x="a",y="b",z=2)
all_2(m=3,n=4)

结果:

{'x': 'a', 'y': 'b', 'z': 2}
{'m': 3, 'n': 4}

思考5-2(课堂):

编写一个函数sum_all,参数可以接收任意个的数字,返回值为这些参数的和。

#coding=utf-8
# 法一
def sum_all(a,*b):
	for i in b:
		a = a+i     # 也可写成 a += i
	return a
	
print(sum_all(1,2,3))
print(sum_all(1,2,3,4,5,6))

# 法2
def sum_all(*a):
	n=0
	for i in a:
		n=n+i
	return n

print(sum_all(1,2,3))
print(sum_all(1,2,3,4,5,6))

结果:

6
21
5.2.2 参数的位置和名称传递

函数调用时,实参默认采用按照位置顺序的方式传递给函数,但当参数很多时,这种调用参数的方式可读性较差。

假设func()函数有6个参数,它的定义如下,其中参数分别表示两组三维坐标值。

func(x1,y1,z1,x2,y2,z2)
   return
#实际调用如下:
result =func(1,2,3,4,5,6,)

如果仅看实际调用而不看函数定义,很难理解这些输入参数的含义。在规模稍大的程序中,函数定义可能在函数库中,也可能与调用相距很远,带来的可读性较差。

为了解决上述问题,Python提供了按照形参名称输入实参的方式,此时函数调用如下:

result = func(x2=4,y2=5,z2=6,x1=1,y1=2,z1=3)

由于调用函数时指定了参数名称,所以参数之间的顺序可以任意调整。

例:

def SayHello(s,n):
  for i in range(1,n+1):
    print(s)

SayHello("Hello!",3)      #位置参数
SayHello(3,"Hello!")      #error
SayHello(n=3,s="Hello!")  #关键参数

位置参数:”Hello!“对应于s;3对应于n

Error: "Hello!"对应于n,则下面中的n+1无法对应从而出错

关键参数:把形参名直接赋值。

实参有两种类型:位置参数和关键参数,即函数实参是作为位置参数和关键参数被传递的。

当使用位置参数时,实参必须和形参在顺序、个数和类型上一一匹配。

传递参数时的序列解包

序列解包是指实参,同样也有*和**两种形式。

方式1:传递参数时,可以通过在实参序列前加*将其解包,然后传递给多个单变量形参。

def demo(a,b,c):
	print(a+b+c)

seq = [1,2,3]
tup = (1,2,3)
dic = {1:'a',2:'b',3:'c'}
Set = {1,2,3}

demo(*seq)    #把 seq= [1,2,3]打散掉变为 a=1,b=2,c=3
demo(*tup)
demo(*dic)    # 把字典的键传过去
demo(*dic.values())  # a='a',b='b',c='c' 字典打散掉
demo(*Set)

结果:

6
6
6
abc
6

方式2:如果函数实参是字典,可以在前面加**进行解包,等价于关键参数。

def demo(a,b,c):
	print(a+b+c)

dic = {'a':1,'b':2,'c':3}
demo(**dic)      #传递字典的值
demo(a=1,b=2,c=3)   # 关键参数
demo(*dic.values())  #传递字典的值
demo(*dic)    #字典的键

结果:

6
6
6
abc

总结:

实参

  • 位置参数
  • 关键参数 f(b=4,a=3)
  • 实参为序列、字典,传递参数时解包

形参

  • 默认参数def函数名(形参=值)

  • 可变参数def函数名(*形参)

  • 引用字典def函数名(**形参)

全局变量:global

5.2.3 函数的返回值

函数返回值:

  • 函数不一定要有return语句
  • 即使函数无返回值,依旧可以获得返回值None
  • return不带任何参数时,也返回None
  • 如果函数有返回值,使用return来返回值
  • 执行return语句意味着函数的终止
  • Python的return语句可以返回多个值

例:

#eg5_1sort.py
def sort(number1,number2):
	if number1<number2:
		return number1,number2
	else:
		return number2,number1

n1,n2 = sort(3,2)
print("n1 is",n1)
print("n2 is",n2)

程序结果:

n1 is 2
n2 is 3

return语句用来退出函数并将程序返回到函数被调用的位置继续执行。return语句可以同时将0个、1个或多个函数运算后的结果返回给函数被调用处的变量。

例如:

def func(a, b):
	return a*b

s = func("knock~",2)
print(s)

程序结果:

knock~knock~

函数也可以用return返回多个值,多个值以元组类型保存,如:

def func(a,b):
	return b,a

s = func("knock",2)
print(s,type(s))

程序结果:

(2, 'knock') <class 'tuple'>

若没有return,例如:

def sum(number1,number2):
	total = number1+number2

print(sum(1,2))

程序结果:

None

加上return,则:

def sum(number1,number2):
	total = number1+number2
  return total

print(sum(1,2))

程序结果:

3

def circle(r):
	if r<=0:
		print("要求输入整数!")
		return                  # 类似return None ,其中None可省略
	area = 3.14*r*r
	perimeter=2*3.14*r
	return area, perimeter    #返回一个元组

r=-3
re=circle(r)
if re!=None:
	print("半径为",r,"的圆面积为:",re[0])
	print("半径为",r,"的圆周长为:",re[1])

r=3 
re=circle(r)
if re!=None:
	print("\n半径为",r,"的圆面积为:",re[0])
	print("半径为",r,"的圆周长为:",re[1])

程序结果:

要求输入整数!

半径为 3 的圆面积为: 28.259999999999998
半径为 3 的圆周长为: 18.84
5.2.4 函数对变量的作用

一个程序中的变量包括两类:全局变量和局部变量。

全局变量:在函数之外定义的变量,一般没有缩进,在程序执行全过程有效。

局部变量:在函数内部使用的变量,仅在函数内部有效,当函数退出时变量将不存在。

以下例子说明,当函数执行完退出后,其内部变量将被释放:

n = 1		#n 是全局变量
def func(a, b):
	c = a * b		# c是局部变量,a和b作为函数参数也是局部变量
	return c

s = func("knock~",2)
print(c)

程序结果:

NameError: name 'c' is not defined

若函数使用全局变量时:

>>> n = 1
>>> def func(a,b):
	n = a * b
	return n

>>> s =func("knock~",2)
>>> print(s,n)   #测试一下n值是否改变
('knock~knock~', 1)

函数func()内部使用了变量n,并且将变量参数b赋值给变量n,为何 n值没有改变?因为函数func()有自己的内存空间,它将n=b语句理解为生成一个局部变量n,并将参数b赋值给它,此时func()函数没有将n当作全局变量。所以,函数退出后,局部变量n被释放,全局变量n的值没有改变。

如果希望让func()函数将n当作全局变量,需要在变量n使用前用global显示声明该变量为全局变量,代码如下:

>>> n = 1  # n是全局变量
>>> def func(a,b):
	global n
	n = b #将局部变量b赋值给全局变量n
	return a*b

>>> s = func("knock~",2)
>>> print(s,n) #测试一下n值是否改变
knock~knock~ 2

倘若全局变量不是整数n,而是列表类型ls则:

>>>ls = []    #ls是全局列表变量
>>>def func(a,b):
	ls.append(b)   #将局部变量b增加到全局列表变量ls中
	return a*b

>>>s = func("knock~",2)
>>>print(s,ls)   # 测试一下ls值是否改变
knock~knock~ [2]

列表全局变量在函数func()调用后竟然发生了改变,与整数变量n不同。

列表等组合数据类型由于操作多个数据,所以它们在使用中有创建和引用的分别。当列表变量被方括号([],无论是否为空)赋值时,这个列表才被真是穿件,否则只是对之前创建列表的一次引用。

上述代码func()函数的ls.append(b)语句执行时需要一个真是创建过的列表,此时func()函数专属的内存空间中没有已经创建过且名称为ls的列表,因此,func()函数进一步去寻找全局内存空间,自动关联全局ls列表,并修改其内容。当func()函数退出后,全局列表ls中的内容被修改。简单地说,对于列表类型,函数可以直接使用全局列表而不需要采用global进行声明。

但如果func()函数内部存在一个真实创建过且名称为ls的列表,则func()函数将操作该列表而不会修改全局变量,例如:

>>>ls = []  #ls是全局列表变量
>>>def func(a,b):
	ls = []   #创建了名称为ls的局部列表变量
	ls.append(b)    #将局部变量b增加到局部列表变量ls中
	return a*b

>>>s = func("knock~",2)
>>>print(s,ls)
knock~knock~ []

例:

def f(s):
	s[0]="hello"

a=[1,2,3,4]
f(a)      # s=a 指向位置是一样 s=[1,2,3,4] 改变s[0]即列表里第一个数字1变为”hello“
print(a)  # f()函数内部并没有存在一个真实创建国的列表

b=[1,2,3,4]
f(b[:])  # s=b[:] 拷贝 指向是不同的位置,不同地址空间 原本的b并未改变 此处创建了b[:]这个列表
print(b)  #

结果:

['hello', 2, 3, 4]
[1, 2, 3, 4]

总结 python函数对变量的作用遵守如下原则

(1)简单数据类型变量无论是否与全局变量重名,仅在函数内部创建和使用,函数退出后变量被释放,如有全局同名变量,其值不变。

(2)简单数据类型变量在用global保留字声明后,作为全局变量使用,函数退出后该变量保留且值被函数改变。

(3)对于组合数据类型的全局变量,如果在函数内部没有被真实创建的同名变量,则函数内部可以直接使用并修改全局变量的值。

(4)如果函数内部真实创建了组合数据类型变量,无论是否有 同名全局变量,函数仅对局部变量进行操作,函数退出后局部变量被释放,全局变量值不变。


拓展:指针和引用

指针:保存内存地址的变量,一般出现在比较底层的 程序设计语言中,如C语言。

引用:某一变量的别名,用这个名字可以对变量进行操作,如python列表类型的引用。

两者主要区别:指针直接指向内存地址,说明对象已经生成,而引用只是别名,需要真实创建对象才能操作对象。由于列表类型在Python中十分常用,要格外注意该类型真实创建和引用的区别。

  1. Python中定义函数的关键字是( ) A.

A) def B) define C) function D) defunc

  1. 如果函数中没有return语句或return语句不带任何返回值,那么该函数( ) B

A)没有返回值 B)返回值为None C)返回值为Nun D)返回值为Null

  1. 判断题:函数在调用前不需要定义,直接拿来用就行 x

  2. x = [‘train’, ‘bus’, ‘car’, ‘ship’] 下面哪个选项的值是’car’ A.

(A)x[-2] (B) x[3] ©x[2:3] (D)x[-1]

  1. x = [‘train’, ‘bus’, ‘car’, ‘ship’] 下面哪个选项的值不是[‘train’, ‘bus’, ‘car’, ‘ship’] C.

(A)x[:4] (B) x[:] ©x[1:] (D)x

  1. x = [‘train’, ‘bus’, ‘car’, ‘ship’] 下面哪个选项的值是[‘car’, ‘ship’] C.

(A)x[-2:-1] (B) x[-2:0] ©x[-2:] (D)x[2:3] A=[‘car’] B=[] 步长错误 D=[‘car’]

  1. x=[[‘IBM’,‘Apple’,‘Lenovo’],[‘America’,1]] 下面哪个选项的值不是‘America’ D

(A)x[-1][-2] (B) x[1][0] ©x[-1][0] (D)x[-1][1]

  1. x=[[‘IBM’,‘Apple’,‘Lenovo’],[‘America’,1]] 下面哪个选项的值不是 ‘Am’ D.

(A)x[1][0][0:2] (B) x[1][0][:2:1] ©x[1][0][:-5:1] (D)x[1][0][:2:-1]

第6章

列表的操作

字典的操作

6.2.2 列表类型的操作

表6.4 列表类型特有的函数或方法(共14个)

函数或方法描述
ls[i]=x替换列表ls第i数据项为x
ls[i:j]=lt用列表lt替换列表ls中第i到第j项数据**(不含第j项,下同)**
ls[i:j:k]=lt用列表lt替换列表ls中第i到第j项以k为步数的数据
del ls[i:j]删除列表ls第i到第j项数据,等价于ls[i:j]=[]
del ls[i:j:k]删除列表ls第i到第j项以k为步数的数据
ls+=lt 或 ls.extend(lt)将列表lt元素增加到列表ls中
ls * = n更新列表ls,其元素重复n次
ls.append(x)在列表ls最后增加一个元素x
ls.clear()删除ls中的所有元素
ls.copy()生成一个新列表,复制ls中的所有元素
ls.insert(i.x)在列表ls的第i位置增加元素x
ls.pop(i)将列表ls中的第i项元素取出并删除该元素
ls.remove(x)将列表中出现的第一个元素x删除
ls.reverse()列表ls中的元素反转
>>> vlist = list(range(5))
>>> vlist
[0, 1, 2, 3, 4]
>>> len(vlist[2:])       # 计算从第3个位置开始到结尾的子串长度
3
>>> 2 in vlist           # 判断2是否在列表vlist中 
True
>>> vlist[3]="PYTHON"    # 修改序号3的元素值和类型
>>> vlist
[0, 1, 2, 'PYTHON', 4]
>>> vlist[1:3]=["bit","computer"]    
>>> vlist
[0, 'bit', 'computer', 'PYTHON', 4]

# 当使用一个列表改变另一个列表值时,python不要求两个列表长度一样,但遵循”多增少减“的原则
>>> vlist[1:3]=["new_bit","new_computer",123]
>>> vlist
[0, 'new_bit', 'new_computer', 123, 'PYTHON', 4]
>>> vlist[1:3]=["fewer"]
>>> vlist
[0, 'fewer', 123, 'PYTHON', 4]

与元组一样,列表可以通过for-in语句对其元素进行遍历,基本语法结构如下:

for <任意变量名> in <列表名>:
  <语句块>
>>>for e in vlist:
       print(e,end="")
0 fewer 123 python 4

6.4 字典类型和操作

要点: 字典是包含0个或多个键值对的集合,没有长度限制,可以根据检索引值的内容。

6.4.1 字典类型的概念
  • 字典是Python中唯一内建的映射类型,可以用来实现通过数据查找关联数据的功能。
  • Python字典中的值没有特殊的顺序,是无序集合,不能像序列那样通过位置索引来查找成员数据。
  • 字典的显示次序由字典在内部的存储结构决定
  • 字典每一值都有一个对应的键。字典的用法是通过键key来访问相应的值value。

列表是存储和检索数据的有序序列。当访问列表中的元素时,可以通过整数索引来查找它,这个索引是元素在列表中的序号,列表的索引模式是“<整数序号>查找<被索引内容>”。

在编程术语中,根据一个信息查找另一个信息的方式构成了“键值对”,它表示索引用的键和对应的值构成的成对关系,即通过一个特定的键(身份证号码)来访问值(学生信息)。实际应用中有很多“键值对”的例子,例如,姓名和电话号码、用户名和密码、邮政编码和运输成本、国家名称和首都等。由于键不是序号,无法使用列表类型进行有效存储和索引。

通过任意键信息查找一组数据中值信息的过程叫映射,Python语言中通过字典实现映射。Python语言中的字典可以通过大括号({})建立,建立模式如下:

{<键1>:<值1>, <键2>: <值2>, ..., <键n>: <值n>}

键和值通过冒号连接,不同键值对通过逗号隔开。从Python设计角度考虑,由于大括号{}可以表示集合,因此字典类型也具有和集合类似的性质,即键值对之间没有顺序且不能重复。简单说,可以吧字典看成元素是键值对的集合。

  • 键可以是任何不可修改类型的数据,如数值、字符串和元组等,键要唯一;
  • 键对应的值,可以是任何类型的数据。
>>>Dcountry={"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>>print(Dcountry)
{'中国':'北京','美国':'华盛顿','法国':'巴黎'}

字典打印出来的顺序与创作之初的顺序不同,这不是错误。字典是集合类型的延续,所以各个元素并没有顺序之分。如果想要保持一个集合元素的顺序,需要使用列表,而不是字典。

字典最主要的用法是查找与特定键相对应的值,这通过索引符号来实现。例如:

>>>Dcountry["中国"]
'北京'

一般来说,字典中键值对的访问模式如下,采用中括号格式:

<值>=<字典变量>[<键>]

>>>Dcountry["中国"]='大北京'
>>>print(Dcountry)
{'中国': '大北京','法国': '巴黎','美国': '华盛顿'}

Python语言中,字符串、列表、元组等都采用数字索引,字典采用字符索引。

>>> country={12:'Australia',(2,3):'China','DE':'Germany','SG':"Singapore"}
>>> country
{12: 'Australia', (2, 3): 'China', 'DE': 'Germany', 'SG': 'Singapore'}
>>> country={}
>>> country
{}

用dict函数创建

dict([(键1,值1),(键2,值2),...])

>>> a=dict([("name","limin"),("age",18)])
>>> a
{'name': 'limin', 'age': 18}
6.4.2 字典类型的操作
  • 字典最主要的用法是查找与特定键相对应的值,这通过索引符号来实现。
  • 变量[键]:查找与特定键相关联的值。如果指定的键在字典中不存在,则报错。
  • 对变量[键]赋值,修改字典中的数据,若指定的键不存在,相当于向字典中添加新的键值对。

与列表相似,Python字典也有非常灵活的操作方法。使用大括号可以创建字典,并指定初始值,通过中括号可以增加新的元素,例如:

>>>Dcountry=["中国":"北京", "美国": "华盛顿", "法国": "巴黎"]
>>>Dcountry=["英国"]="伦敦"
print(Dcountry)
{"中国":"北京","法国": "巴黎","美国": "华盛顿", '英国',"伦敦"}
>>>Dcounty["日本"]
报错

直接使用大括号({})可以创建一个空的字典,并通过中括号([])向其增加元素,例如:

>>>Dp={}
>>>Dp['2^10']=1024
>>>print(Dp)
{'2^10': 1024}

需要注意的是,尽管集合类型也是有用大括号表示,直接使用大括号({})生成一个空的字典,而不是集合。生成空集合需要使用函数set()。

表6.5 字典类型的函数和方法

函数和方法描述
<d>.keys()返回所有的键信息
<d>.values()返回所有的值信息
<d>.items()返回所有键值对
<d>.get(<key>,<default>)键存在则返回相应值,否则返回默认值
<d>.setdefault(<key>,<value>)键存在返回相应值,否则添加元素
<d>.pop(<key>,<default>)键存在则返回相应值,同时删除键值对,否则返回默认值
<d>.popitem()随机从字典中取出一个键值对,以元组(key,value)形式返回
<d>.clear()删除所有的键值对
del <d>[<key>]删除字典中某个键值对
<key> in <d>如果键在字典中则返回True,否则返回False

如果希望keys()、values()、items()方法返回列表类型,可以采用list()函数将返回值转换成列表:

>>>Dcountry={"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>>Dcountry.keys()
dict_keys(['中国', '美国', '法国'])
>>> list(Dcountry.values())
['北京', '华盛顿', '巴黎']
>>> Dcountry.items()
dict_items([('中国', '北京'), ('美国', '华盛顿'), ('法国', '巴黎')])
>>> '中国' in Dcountry #只对键进行判断
True
>>> Dcountry.get('美国','悉尼')  #'美国'在字典中存在
'华盛顿'
>>> Dcountry.get('澳大利亚','悉尼')  # '澳大利亚'在字典中不存在则返回后面那个
'悉尼'
>>> Dcountry.setdefault('英国','伦敦')  # 键存在返回相应值,否则添加元素
'伦敦'
>>> Dcountry
{'中国': '北京', '美国': '华盛顿', '法国': '巴黎', '英国': '伦敦'}
>>> Dcountry.pop('英国')
'伦敦'
>>> Dcountry.popitem()
('法国', '巴黎')
>>> Dcountry
{'中国': '北京', '美国': '华盛顿'}
>>> del Dcountry['美国']
>>> Dcountry
{'中国': '北京'}
>>> Dcountry.clear()
>>> Dcountry
{}
>>> del Dcountry

于其他组合数类型一样,字典可以通过for...in语句对其元素进行遍历,基本语法结构如下:

for <变量名> in <字典名>:
  语句块
  

例如:

a={"中国":"北京","美国":"华盛顿","法国":"巴黎"}
for i in a:
  print(i)
###运行结果:
中国
美国
法国

思考:si6_4:

编写程序,输入两个分别包含若干整数的列表list1和list2。用list1元素作为键,用list2作为值,产生一个字典。该字典的元素个数为list1和list2元素较少的那个列表长度,输出该字典。

请输入list1:3,5,6,2,7,346
请输入list2:4,6,345,65,54,5,2,7
{3:4,5:6,6:345,2:65,7:54,346:5}

解:

list1=eval(input("请输入list1:"))
list2=eval(input("请输入list2:"))
c=dict(zip(list1,list2))
print(c)

思考si6_5.py

文件里dict1变量保存的是学生健康打卡信息,请在##==之间输入代码。

dict1={'张三三':[{'日期':'4月30日','省份':'福建','城市':'福州','是否健康':'是','是否接触过疑似病例':'否'},\
                            {'日期':'5月1日','省份':'福建','城市':'福州','是否健康':'是','是否接触过疑似病例':'否'}], \
            '李四四':[{'日期':'4月30日','省份':'福建','城市':'三明','是否健康':'是','是否接触过疑似病例':'否'},\
                            {'日期':'5月1日','省份':'福建','城市':'三明','是否健康':'是','是否接触过疑似病例':'否'}],
            '王五五':[{'日期':'4月30日','省份':'福建','城市':'泉州','是否健康':'是','是否接触过疑似病例':'否'},\
                            {'日期':'5月1日','省份':'福建','城市':'泉州','是否健康':'是','是否接触过疑似病例':'否'}], \
         }
name=input('请输入姓名:')
date=input('请输入日期:')
tempdata=dict1.get(name,'不存在')
if  tempdata=='不存在':
     print(name+'不存在')
else:
     for i in tempdata:
          if i['日期']==date:
               print(i)
               break
     else:
          print("今日未打卡")
     

第7章

open() 打开模式
f.close()
read()
readline()
readlines()
write()
writelines()
seek()

7.1 文件的使用

要点:Python能够以文本和二进制两种方式处理文件

7.1.1 文件概述

文件是一个存储在辅助存储器上的数据序列,可以包含任何数据内容。概念上,文件是数据的集合和抽象,类似地,函数是程序的集合和抽象。用文件形式组织和表达数据更有效也更为灵活。文件包括两种类型:文本文件二进制文件。

文本文件:一般由单一特定编码的字符组成,如UTF-8编码,内容容易统一展示和阅读。大部分文本文件都可以通过文本编辑软件或文字处理软件创建、修改和阅读。由于文本文件存在编码,因此它也可以被看作是存储在磁盘上的长字符串,例如一个txt格式的文本文件。

二进制文件:直接由比特0和比特1组成,没有统一字符编码,文件内部数据的组织格式与文件用途有关。二进制是信息按照非字符但特定格式形成的文件,例如png格式的图片文件、avi格式的视频文件。

区别:二进制文件和文本文件最主要的区别在于是否有统一的字符编码。二进制文件由于没有统一字符编码,只能当作字节流,而不能看作是字符串。

例:

首先用文本编辑器生成一个包含“中国是个伟大的国家!”的txt格式文本文件,命名为7.1.txt。分别用文本文件方式和二进制文件方式读入,并打印输出效果代码如下:

textFile = open("7.1.txt","rt",encoding='utf8')   # t表示文本文件方式 rt:文本只读模式,读入程序算哦在目录中7.1.txt文件 或 textfile = open('7.1.txt') 有时出现汉字显示不出来时使用encoding可不用
print(textFile.readline())
textFile.close()
binFile = open("7.1.txt","rb")   # b 表示二进制文件方式 
print(binFile.readline())
binFile.close()

输出结果:

中国是一个伟大的国家!
b'\xe4\xb8\xad\xe5\x9b\xbd\xe6\x98\xaf\xe4\xb8\x80\xe4\xb8\xaa\xe4\xbc\x9f\xe5\xa4\xa7\xe7\x9a\x84\xe5\x9b\xbd\xe5\xae\xb6\xef\xbc\x81'

采用文本方式读入文件,文件经过编码形成字串符,打印出有含义的字符

采用二进制方式打开文件,文件被解析为字节(Byte)流。由于存在编码,字串符中的一个字符由两个字节表示。

7.1.2 文件的打开关闭
  • Python对文本文件和二进制文件采用统一的操作步骤,即“打开—操作—关闭”。即使用文件之前,必须先打开文件,然后进行引读、写、添加等操作。

  • Python通过解释器内置的open()函数打开一个文件,并实现该文件与一个程序变量的关联,open()函数格式如下:

<变量名>=open(<文件名>,<打开模式>)

文件名可以是文件的实际名字,也可以是包含完整路径的名字。

打开模式用于控制使用何种方式打开文件。

或:

open(name[,mode,buffering,encoding])

name:必须提供的参数,文件的路径

  • name参数:文件的路径可以是绝对路径也可以是相对路径:
f=open("d:\\1.txt")
f=open("d:/1.txt")
f=open("1.txt")  # 当前目录下

只提供给open函数一个参数“name”,将范围一个只读的文件对象

mode:打开的模式

buffering:是否缓冲

  • buffering参数:控制文件读或写时是否需要缓冲。
    • 若取0(或false),则无缓冲
    • 若取1(或true),则有缓冲
    • 若>1的数,该数则为所取缓存区中的字节大小;若取负数,则表示使用默认缓存区的大小。
    • buffering的默认参数值为1

encoding:编码模式

  • encoding参数:当文件以文本方式打开时,文件内容汉字,一般设置为“utf8”。若是没有汉字或是以二进制方式打开文件,encoding不需要设置。

open()函数提供7种基本的打开模式

文件的打开模式含义
‘r’只读模式,如果文件不存在,返回异常FileNotFoundError,默认值
‘w‘覆盖写模式,文件不存在则创建,存在则完全覆
’x‘创建写模式,文件不存在则创建,存在则返回异常值FileNotFoundError
’a‘追加写模式,文件不存在则创建,存在则在文件最后追加内容
’b‘二进制文件模式
’t‘文本文件模式,默认值
’+‘与r/w/x/a一同使用,在原功能基础上增加同时读写功能

打开模式使用字符串方式表示,根据字符串定义,单引号或者双引号均可。上述打开模式中,’r‘、’w‘、’x‘、’a‘和’b‘、’t‘、’+‘组合使用,形成既表达读写又表达文件模式的方式。

例如,open()函数默认采用’rt‘(文本只读)模式。

读取一个二进制文件,如一张图片、一段视频或一段音乐,需要使用文件打开模式’rb‘。

例如,打开一个名为"music.mp3"的音频文件:

binfile = open('music.mp3','rb')
文件的关闭

文件使用结束后要用close()方法关闭,释放文件的使用授权,该方法的使用方式如下:

<变量名>.close()
  • 关闭文件
  • 把缓存区的数据写入磁盘,释放文件对象
  • 当对文件操作完后,一定要关闭文件对象,这样才能保证所做的任何修改都确实被保存到文件中。
属性含义
closed用于判断文件是否关闭,若文件处于打开状体,则返回False
mode返回文件的打开模式
name返回文件的名称
>>> f = open("1.txt")  # f是一个文件的对象
>>> f.closed
False
>>> f.mode
'r'
>>> f.name
'1.txt'
7.1.3 文件的读写

当文件以文本文件方式打开时,读写按照字符串方式,采用当前计算机使用的编码或指定编码;

当文件以二进制文件方式打开时,读写按照字节流方式。

Python提供4个常用的文件内容读取方法(文件打开模式含有“r”“+”):

操作方法含义
.readall()读取整个文件内容,返回一个字符串或字节流*
.read(size=-1)从文件中读入整个文件内容,如果给出参数,读入前size长度的字符串或字节流
.readline(size=-1)从文件中读入一行内容,如果给出参数,读入该行前size长度的字符串或字节流
.readlines(hint=-1)从文件中读入所有行,以每行为元素形成一个列表,如果给出参数,读入hint行

*:字符串或字节流取决于文件打开模式,如果是文本方式打开,返回字符串;否则返回字节流。下同。

>>> f = open("fy.txt","r")
>>> f.read(3)
'1.T'
>>> f.read()
"he China Manned Space Agency said the flight successfully verified \n2.the overall design and technologies of the new rocket and also marked\n3.the beginning of the third stage in China's manned space program, \n4.which aims to put a manned space station into orbit."
>>> f.close()

>>> f = open("fy.txt")
>>> f.readline(3)
'1.T'
>>> f.readline()
'he China Manned Space Agency said the flight successfully verified \n'
>>> f.close()

>>> f = open("fy.txt","r")
>>> f.readlines()
['1.The China Manned Space Agency said the flight successfully verified \n', '2.the overall design and technologies of the new rocket and also marked\n', "3.the beginning of the third stage in China's manned space program, \n", '4.which aims to put a manned space station into orbit.']

例:文本文件逐行打印

用户输入文件路径,以文本文件 方式读入文件内容并逐行打印,代码如下:

fname = input("请输入要打开的文件:")    # 提示用户输入一个文件名
fo = open(fname, "r")                 # 打开文件并赋值给文件对象变量fo
for line in fo.readlines():           # 文件的全部内容通过fo.readline()方法读入到一个列表中,
	print(line)             # 列表的每个元素是文件一行的内容,然后通过for-in方式历遍列表,处理每行内容
fo.close()

当读入文件非常大时,一次性将内容读取到列表中会占很多内存,影响程序执行速度。一个合理的方法时逐行读入内容到内存,并逐行处理:

python将文件本身作为一个行序列,历遍文件的所有行可以直接这样完成:

fname = input("请输入要打开的文件:")
fo = open(fname, "r")
for line in fo:
  print(line)        # 处理一行数据
fo.close

拓展:文件的换行符

如果采用二进制方式打开文件,换行符只是一个符号,对应一个字节,表示为“\n”;如果采用文本方式打开文件,换行符表示一行的结束,辅助程序对文件的处理。文件的换行符是真实存在的一个字符。


Python提供3个与文件内容写入有关的方法,如下所示(文件打开模式含有w、a、x、+):

方法含义
.write(s)向文件写入一个字符串或字节流
.writelines(lines)将一个元素全为字符串的列表写入文件
.seek(offset)改变当前文件操作指针的位置,offset的值:0—文件开头;1—当前位置;2—文件结尾
>>> f = open("1.txt","a+")
>>> f.write("hello")
5
# 代码到此,文件1.txt还没“hello”因为它还在缓存区

>>>f.close()   # 此时文件1.txt在后面加上“hello”


>>> f = open("1.txt","a+")
>>> f.write("2a")     # 在文件1.txt后面加上2a
2
>>> a = ['1','1','2']
>>> f.writelines(a)
>>> f.close()    # 文件1.txt在文本后面加上了112  

P.S. 注意写入后的元素间是没有分隔符的

例:向文件写入一个列表

向文件写一个列表类型,并打印输出结果,代码如下:

fname = input("请输入要写入的文件")
fo = open(fname,"w+")
ls = ['唐诗','宋词','元曲']
fo.writelines(ls)
for line in fo:
	print(line)
fo.close()

程序执行结果如下:

>>>请输入要写入的文件test.txt
>>> 

在WriteListFile.py程序的目录中找到text.txt文件,打开可以看到其中的内容如下:

唐诗宋词元曲

列表ls内容被写入文件,但为何

for line in fo:
	print(line)
fo.close()

没有将这些内容打印出来呢?

因为文件写入内容后,当前文件操作指正在写入内容的后面,此处的代码从指针开始向后读入并打印内容,被写入的内容却在指针前面,因此未能被打印出来。

所以为了可以在写入文件后增加一条代码fo.seek(0)将文件操作指针返回到文件开始,即可显示写入的内容,代码如下:

fname = input("请输入要写入的文件:")
fo = open(fname, "+w")
ls = ["唐诗", "宋词", "元曲"]
fo.writelines(ls)
fo.seek(0)
for line in fo:
	print(line)
fo.close()

程序执行结果如下

请输入要写入的文件:test.txt
唐诗宋词元曲

fo.writelines()方法并不在列表后面增加换行,只是将列表内容直接排列输出。

<file>.seek(offset[,where])
  • seek方法可以移动指针的位置

  • where定义指针位置的参照点:

    • 0:文件开头(默认)
    • 1:当前位置(文件要以b方式打开)
    • 2:文件结尾(文件要以b方式打开)
  • offset参数:定义了指针相对于参照点where的具体位置,取整数值。

例:文件起始位置

f.seek(0)

例:文件其实位置,往文件为方向移动3个字节

f.seek(3)或f.seek(3,0)  # 3 往文件方向移动3个字节, 0为文件开头

例:从当前位置开始,往文件头方向移动2个字节

f.seek(-2,1)    # -2 往文件头方向移动2个字节,1 当前位置

f.tell(): 返回文件操作标记的当前位置,以文件的开头为原点

>>> f = open("1.txt","ab+")
>>> f.tell()
42

上下文管理语句with

在实际开发中,读写文件应优先考虑使用上下文管理语句with,关键字with可以自动管理资源,不论因为什么原因(哪怕是代码引发了异常)跳出了with块,总能保证文件被正确关闭。简而言之,就是使用with语句可以不用加close()

with open(filename,mode,encoding)as fp:    #这里写ton过文件对象fp读写文件内容的语句

上下文管理语句with还支持下面的用法:

with open('1.txt','r')as src, open('1_new.txt','w') as dst:
  dst.write(src.read())

例:向文本文件中写入内容,然后读出:

>>> s = "Hello world\n文本文件的读取方法\n文本文件的写入方法\n"
>>> with open('1.txt','w')as fp:
	    fp.write(s)    
>>> with open('1.txt')as fp:
	    print(fp.read())
    
Hello world
文本文件的读取方法
文本文件的写入方法

课堂:

思考7_1:下面的代码

f = open("text.txt",'wb+')     # 打开text.txt文件以覆盖写模式,二进制文件模式以及在此基础上同时增加读写功能
f.write(b"python")       # 二进制的python写入
f.seek(2,0)             # 光标为文件方向的第2个字节,光标在文件开头
print(f.read(3))        # 读取光标位置向后数3个字节 光标移动到第5个字节
f.seek(-3,1)            # 光标移到方向头为开头3个字节,光标在当前位置 从第5个字节移到第2个字节
print(f.read(1))       # 读取文件光标位置向后数1个字节
f.close()

结果为:

b'tho'
b't'

思考7_2:复制1.txt文件,生成一个名为1_1.txt新的文本文件

答:

f1 = open("1.txt","r",encoding='utf-8')
f2 = open("1_1.txt","w")
a = f1.read()
f2.write(a)
f1.close()
f2.close()

或:

f1 = open("1.txt","r",encoding='utf-8')
f2 = open("1_1.txt","w")
for i in f1:
  f2.write(i)
  
f1.close()
f2.close()

思考7_3:生成1至122之间的随机整数数,转成对应的字符,然后将满足以下条件(大写字母、小写字母、数字和一些特殊符号’*‘,’&‘,’^‘,’$‘)的字符逐一输入写入文本test.txt中,当光标位置达到101时停止写入。

判断是否小写字母的方法:字符串.islower()

判断是否大写字母的方法:字符串.isupper()

判断是否数字的方法:字符串.isdigit()

答:

产生随机整数 randint()

转成对应的字符 chr()

chr() in [’*‘,’&‘,’^‘,’$‘]

达到101个字节 f.tell()

import random
f1=open("test.txt",'w+')
while f1.tell() <= 101:
  a=chr(random.randint(1,122))
  if a.islower() or a.isupper() or a.isdigit() or a in['*','&','^','$']:
    f1.write(a)

f1.close()

输出结果:

打开text.txt文件

ln7KSuL5qRzQ7LJRmH5O6FOiyrKHCL$^mHwlYoVJo*DmP8MPKQKpH4uun*L*ZE91lEEs&tdtEKTSrMqxI9BwHb63fefiapy9J^VY1t

思考7_4:

逐个字节读取:'fy.txt’文件,输出该文件前10个字节字符和后10个字节字符

fy = open("fy.txt",'rb')    # 注意要使用rb方式打开,下面才可进行读写 不然会报错.UnsupportedOperation: can't do nonzero end-relative seeks
fy.seek(0)
print(fy.read(10))
fy.seek(-10,2)
print(fy.read(10))
fy.close()

程序结果:

b'1.The Chin'
b'nto orbit.'

思考7_5:

统计‘fy.txt’文件中大写字母、小写字母和数字的个数。可以利用字符串的isupper()、islower()和isdigit()方法。

输入如下所示:

大写有6个,小写有205个,数字有4个

答:

f=open("fy.txt","r")
a=f.read()
s=0
y=0
c=0
for i in a:
    if i.isupper():
        s=s+1
    elif i.islower():
        y=y+1
    elif i.isdigit():
        c=c+1
    else:
        pass
f.close()
print("大写有"+str(s)+"个, "+"小写有"+str(y)+"个, 数字有"+str(c)+"个")

程序结果:

大写有6个, 小写有205个, 数字有4个

代码简化

f = open("fy.txt").read()    # 字符串
s,y,c=0,0,0
while 1:
    if f.isupper():
        s+=1
    elif f.islower():
        i+=1
    elif f.isdigit():
        d+=1
    if not f:
        break
f.close()
print('大写有{}个,小写有{}个,数字有{}个',format(s,y,c))

思考与练习

7.1 读写文件需要采用open()函数,采用绝对路径打开操作系统中的一个文件。

答:

向文件中读写数据的方法:

  • read()
  • readline()
  • readlines()
  • write()
  • writelines()
  • seek()
  • tell()

第八章

8.1 类的定义与使用
8.2 构造函数
8.3 类的属性
8.4 类的方法:公有方法、私有方法
8.7 继承
8.9 运算符的重载
raise抛出自己异常

类的定义与使用

类的定义:

类是由3部分组成的:

  • 类的名称:类名,比如Cartoon_sheep
  • 类的属性:一组数据,比如姓名
  • 类的方法:允许进行操作的方法,比如说话

类的使用:

使用class关键字来声明一个类,基本格式如下:

本章学习目标:

  • 熟练掌握类的设计和使用
  • 深入了解类和对象、面向过程和面向对象的方法
  • 掌握类的属性、类的方法、构造函数和析构函数、可变对象和不可变对象
  • 理解运算符的重载

(考大题比较多)

8.1 类的定义与使用

1、面向过程的程序设计方法:将数据与数据操作相独立,其中的数据操作通过函数或代码块来描述

2、面向对象程序设计方法:将数据与操作封装为一个混合整体——,通过类进行数据的整体操作并且可以保证数据的完整性和一致性。

在面向对象编程中,编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,定义一大类对象都有的通用行为。基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。

类的定义:

类:是抽象的,具有相似特征和行为的事物的集合统称为类

对象:是具体的,是根据类创建的,一个类可以对应多个对象

每一个对象都是以某一个类的实例,类是生成对象的模板。

类和对象的关系

  • 具有相似特征和行为的事物的集合统称为类
  • 对象是根据类创建的,一个类可以对应多个对象
  • 类是抽象的,而对象是具体的
  • 每一个对象都是某一个类的实例
  • 类是生成对象的模板

类是由3部分组成的:

  • 类的名称:类名,比如Cartoon_sheep
  • 类的属性:一组数据,比如姓名
  • 类的方法:允许进行操作的方法,比如说话
类的使用:
  • 类是在执行class语句时创建的,而对象是在调用类的时候创建的
  • 每调用一次类,就创建一个对象。
  • 类只有一个,而对象可以有多个。
  • 类和每个对象都分别拥有自己的内存空间,在各自的内存空间存属于自己的数据。

使用class关键字来声明一个类,基本格式如下

class类名:
   类的属性
   类的方法
class类名:
   赋值语句
   赋值语句
   ……
   def语句定义函数
   def语句定义函数
   ……
class Cartoon_sheep:
  race='sheep'       # 类属性
  def eat(self):     # 方法
    print("我正在享受美食!")
  • 类名的首字母一般要大写

  • 在类中,用赋值语句创建类属性,用def定义函数

  • 类属性是在类中方法之外定义的

根据类创建对象的语法格式如下

对象名=类名() a=Cartoon_sheep()

对象要调用类的属性和方法格式如下

对象名.属性 a.race

对象名.方法() a.eat()

思考eg8_1_1下面注释行的语句如何写:

class Cartoon_sheep:
    race='sheep'
    def eat(self,food):
        print("我正在享受美食!",food)
    def speak(self):
        # 打印race属性

# 创建一个对象sheep1
# 调用speak方法

答:

class Cartoon_sheep:
    race='sheep'
    def eat(self,food):
        print("我正在享受美食!",food)
    def speak(self):
        print(self.race) # 打印race属性

sheep1 = Cartoon_sheep() # 创建一个对象sheep1
sheep1.speak()  # 调用speak方法

类的方法定义与普通函数的差别

  • 类的方法的第一个参数都是self,self代表将来要创建的对象本身
  • 在类的方法里,访问类的实例属性时,需要以self为前缀;
  • 类的方法是通过对象来调用,即object.method()

思考8_1:定义鸟类Bird,鸟类的共同属性feather = True和reproduction = ‘egg’。

该类有一个方法移动move(),该方法执行print(‘飞飞飞飞’)

假设养了一只鹦鹉交spring,它是Bird的一个对象,输出鹦鹉的两个属性,并调用move方法

class Bird():
    feather = True
    reproduction ='egg'
    def __init__(self,name):
        self.name = name
    def move(self):
        print("飞飞飞飞")
bird = Bird('spring')
print(bird.feather)
print(bird.reproduction)
bird.move()

程序结果:

True
egg
飞飞飞飞

在Python中,所有的数据(包括数字和字符串)都是对象,同一类型的对象都有相同的类型。

内置函数isinstance()来测试一个对象是否为某个类的实例或type()来获取关于对象的类型信息。

>>>type(sheep1)
<class'__main__.Cartoon_sheep'>
>>>isinstance(sheep1,Cartoon_sheep)
True

8.2 构造函数

__init__, 称为构造函数或初始化方法,用来为属性设置初值,在建立对象时自动执行。

当创建对象的时候,系统会自动调用构造方法,从而实现为实例属性设置初值。

如果用户未设计构造函数,Python将提供一个默认的构造函数。

[例]

class Cartoon_sheep:
    race='sheep'
    def __init__(self,namevalue,sexvalue,birthdayvalue):
        self.name=namevalue
        self.sex=sexvalue
        self.birthday=birthdayvalue
        self_energy=0

    def eat(self):
        print("我正在享受美食!")
    def speak(self):
        print(self.name,self.birthday)

sheep1 = Cartoon_sheep('喜洋洋','男','羊历3505年5月25日') # 在对象被建立之后,self被用来指向对象。
print(sheep1.name,sheep1.sex,sheep1.birthday)
# sheep1对象,sheep1.name="喜洋洋",sheep1.sex='男',sheep1.birthday='羊历3505年5月25日'
sheep1.speak()

程序结果:

喜洋洋 男 羊历3505年5月25日
喜洋洋 羊历3505年5月25日

思考si8_2: 定义Rectangle类表示矩形。该类有两个属性width和height,均在构造函数中创建,定义方法getArea和getPerimeter计算矩形的面积和周长。

class Rectangle():
    def __init__(self,width,height):
        self.width = width
        self.height = height

    def getArea(self):
        a = (int(self.width))*(int(self.height))
        return a
    def getPerimeter(self):
        b = (int(self.width))+(int(self.height))
        B = 2*b
        return B

t1 = Rectangle(15,6)
print(t1.getArea())
print(t1.getPerimeter())

程序结果:

90
42
class 类名:
   属性=值
   def __init__(self,形参,形参...):
    
   def 方法(self,形参):
       self.属性
     
对象=类名(形参1,形参2,...)
对象.属性
对象.方法(形参)

8.3 类的属性

属性有两种:类属性和对象属性

  • 类属性:是该类所有对象共享,不属于任何一个对象。它在类方法之外定义,一般通过类.属性访问
  • 对象属性通过对象名.属性通过对象名.属性访问,一般在构造函数__init__中进行初始化的,当然也可以在其他成员方法中定义。同一个类的不同对象的属性之间互不影响。
class Cartoon_sheep:
    race='sheep'     # 类属性
    energy=1         # 类属性

    def __init__(self,namevalue,sexvalue,birthdayvalue):
        self.name=namevalue             # 实例属性
        self.sex=sexvalue               # 实例属性
        self.birthday=birthdayvalue     # 实例属性
    def study(self):
        Cartoon_sheep.energy=Cartoon_sheep.energy+1   # 类属性
    
sheep1 = Cartoon_sheep('喜洋洋','男','羊历3505年5月25日')
sheep1.study()
print(sheep1.energy, Cartoon_sheep.energy)  # 此处对sheep1的energy进行赋值,它是对象属性,自身本身energy 后续不会改变

程序结果:

2 2

修改和增加属性

  • 对于类或对象而言,对属性进行赋值,修改该属性;当给不存在的属性赋值时,Python为其创建属性。
对象名.新的属性名 = 值
类.新的属性名 = 值
class Cartoon_sheep:
    race='sheep'

    def __init__(self,namevalue,sexvalue,birthdayvalue):
        self.name = namevalue
        self.sex = sexvalue
        self.birthday = birthdayvalue

    def study(self):
        Cartoon_sheep.energy=Cartoon_sheep.energy + 1

sheep1 = Cartoon_sheep('喜洋洋','男','羊历3505年5月25日')
Cartoon_sheep.energy=0     # 创建类属性energy
sheep1.study()
print(sheep1.energy)  # 此处对sheep1的energy没有进行赋值操作 它访问的是类属性,后续会改变

程序结果为:

1
  • 若要修改类属性的值,必须对类.属性进行赋值
  • 若是通过对象.属性,会产生一个同名的对象属性,这种方式修改的是对象属性,这种方式修改的是对象属性,不会影响到类属性,并且之后如果通过对象.属性访问时,对象.属性会强制屏蔽掉类属性,即访问的是对象.属性, 除非del 对象.属性
class Cartoon_sheep:
    race='sheep'
    energy=1
    def __init__(self,namevalue,sexvalue,birthdayvalue):
        self.name=namevalue
        self.sex=sexvalue
        self.brithday=birthdayvalue

    def study(self):
        Cartoon_sheep.energy=Cartoon_sheep.energy+1   # 内属性
        self.energy=self.energy+1           # 对象属性  创建了对象属性 self.energy+1中的self.energy为上述Cartoon_sheep.energy=2

sheep1 = Cartoon_sheep('喜羊羊','男','羊历3505年5月25日')  # Cartoon_sheep.energy=1
sheep1.study()       #  Cartoon_sheep.energy=1+1=2; self.energy=Cartoon_sheep.energy=2 self.energy = self.energy+1=2+1=3
print(sheep1.energy,Cartoon_sheep.energy)  # 3 2

程序结果:

3 2

思考8_3:下面代码的运行结果是什么?

class Testclass:
    data=100    # 类属性

    def setpdata(self,value):
        self.pdata=value

    def showpdata(self):
        print("self.pdata=",self.pdata)

x = Testclass()
x.setpdata("与时俱进")
x.showpdata()

y = Testclass()
y.setpdata("勇于创新")
y.showpdata()
print(y.data) 

程序运行结果:

self.pdata= 与时俱进
self.pdata= 勇于创新
100

思考8_4: 下面代码的运行结果是什么?

class Testclass:
    data= "有信念、有梦想"    # 类属性
    def setdata(self,value):
        self.data=value   # 创建对象属性
    def showdata(self):
        print(self.data)  # 打印对象属性

x=Testclass()
x.data="勇于创新"
y=Testclass()
Testclass.data="有奋斗、有奉献"  # 更改了类属性
print(x.data)    # 对象属性
print(y.data)    # 没有对y.data赋值 没有创建对象属性,还是修改类属性
print(Testclass.data)

程序运行结果:

勇于创新
有奋斗、有奉献
有奋斗、有奉献

思考8_5:下面代码有1处出错,如何修改

class Rectangle:
    def __init__(self,w,h):
        self.width=w
        self.height=h
    
    def getArea(self):
        return self.width*self.height
    def getPerimeter(self):
        return (self.width+self.height)*2

t1=Rectangle(2,3)
print(Rectangle.width)    # 内属性

答:

print(t1.width)

类的属性分为:公有属性和私有属性

公有属性:可以在类的外部方位,它是类与用户之间交流的接口。用户可以通过公有变量向类中传递数据,也可以通过公有变量获取类中的数据。

私有属性:以__(两个下划线)开头,不能在类的外部被使用或直接访问。在类内部的方法中使用时的格式为self.__私有属性

Python使用下划线作为变量前缀和后缀来指定特殊变量,规则如下:

__xxx__:表示系统定义名字

__xxx:表示类中的私有变量名

私有属性在类外面虽然可以通过如下形式访问,但不建议这样访问:

对象名._类名__私有属性

class Cartoon_sheep:
    race = 'sheep'   # 类属性
    def __init__(self,namevalue,sexvalue,birthdayvalue):
        self.name=namevalue
        self.sex=sexvalue
        self.__birthday = birthdayvalue  ## 私有对象属性
        self.__energy = 0       ## 私有对象属性

    def study(self):
        self.__energy = self.__energy+3
        return self.__energy

sheep1 = Cartoon_sheep('喜羊羊','男','羊历3505年5月25日')
print(sheep1.study())   # self.__energy = self.__energy+3=0+3=3
print(sheep1.__energy)  #   print(sheep1.__energy) AttributeError: 'Cartoon_sheep' object has no attribute '__energy' 出错,私有属性不能在类外部访问
print(sheep1._Cartoon_sheep__energy) # 私有属性在类外面可以通过这种形式访问但不建议

程序结果:

3
3

8.4 类的方法

  • 类中定义的方法都以self作为第一个参数,这个参数表示当前是哪一个对象要执行类的方法,这个实参由Python隐含地传递给self
  • 当对象调用方法时,Python解释器会把对象自身作为第1个参数传给self,开发者只需传递后面的参数就可以了

类的方法分类

  • 公有方法:对象名.公有方法(<实参>)
    • 在类的内部,使用def可为类定义一个方法
    • 与一般函数定义不同,类方法必须包含参数self,且为第一个参数
    • self在Python里不是关键字,self代表当前对象调用方式:对象名.公有方法(<实参>)
    • 如果在外部通过类名调用属于对象的公有方法,需要显式为该方法的self参数传递一个对象名,用来明确指定访问哪个对象。
  • 私有方法:只能在属于对象的方法中通过self调用,不能像公有方法一样通过对象名调用。
  • 静态方法:使用修饰器@staticmethod来标识
  • 类方法:使用修饰器@classmethod来标识

思考8_6:

class Cartoon_sheep:
    race='sheep'
    def __init__(self,namevalue,sexvalue,birthdayvalue):
        self.name=namevalue
        self.sex=sexvalue
        self.__birthday=birthdayvalue
        self._energy=0

    def eat(self,food):
        print("我正在吃",food)
  sheep1= Cartoon_sheep('喜羊羊','男','羊历3505年5月25日')

下面哪些调用是正确的?

a) sheep1.eat(‘草’) # sheep1–>self 草–>food
b) sheep1.eat(sheep1,“草”)
c) Cartoon_sheep.eat(‘草’)
d) Cartoon_sheep.eat(sheep1,‘草’) # sheep1–>self 草–>food

a) d)

私有方法

  • 由两个下划线__开头,声明该方法为私有方法

  • 在类的内部方法调用时格式为:

    self.__私有方法(<实参>)

  • 一般不能在类的外部调用,但是与私有属性一样,在类外面访问方式如下

    对象名._类名__私有方法(不建议)

class Person:
    pre_name=""                  # 类属性
    def __init__(self,n,y,w,h):    # 申明了构造函数
        self.name=n             # 公有属性
        self.year=y            # 公有属性
        self.__weight=w         # 私有属性
        self.__height=h         # 私有属性

    def __getBMI(self):       # 私有方法
        bmi=1.0*self.__weight/self.__height**2   # 调用了私有属性
        return bmi

    def myBMI(self):                 # 公有方法
        if 19<=self.__getBMI()<25:   # 调用私有方法
            print("身体质量指数正常")
        else:
            print("身体质量指数不正常")

pb=Person("Rose",1995,60,1.65)
pb.myBMI()

运行结果:

身体质量指数正常

思考8_7:下面Site的定义共有4处错,如何修改

class Site:
    __number=0    # 私有类属性

    def __init__(namevalue,urlvalue):
        self.name=namevalue
        self.__url=urlvalue       # 私有对象属性
        self.number=self.number+1  # 由下文可知应为私有属性

    def printme(self):
        __privateme(self)              # 利用类属性的方法错误
        print('name:',self.name)
        print('url:',self.url)           # 利用私有对象的方法错误

    def __privateme(self):      # 私有方法
        print(Site.__number)    

wz1 = Site("福建农林大学","wwww.fafu.edu.cn")
wz1.printme()
wz2 = Site("学习强国","www.xuexi.cn")
wz2.printme()

修改

class Site:
    __number=0

    def __init__(self,namevalue,urlvalue):  #4
        self.name=namevalue
        self.__url=urlvalue
        Site.__number=Site.__number+1      # 1

    def printme(self):
        Site.__privateme(self)     # 2
        print('name:',self.name)   
        print('url:',self.__url)   # 3

    def __privateme(self):     
        print(Site.__number)

wz1 = Site("福建农林大学","wwww.fafu.edu.cn")
wz1.printme()
wz2 = Site("学习强国","www.xuexi.cn")
wz2.printme()

程序结果:

1
name: 福建农林大学
url: wwww.fafu.edu.cn
2
name: 学习强国
url: www.xuexi.cn

8.7 继承(考一道拉开成绩)

  • 继承是用来实现代码复用和设计复用的机制。设计一个新类时,如果继承一个己有的设计良好的类然后进行二次开发,无疑会大幅度减少开发工作量。
  • 在继承关系中,已有的、设计好的类称为父类或基类,新设计的类称为子类或派生类

python程序中,继承使用如下语法格式标注:

class 子类名(父类名):

假设有一个类为A,A派生出了子类B,示例如下:

class B(A):
class A(object):    # 默认是继承自object的

例:

class Dog:
  food="骨头"
  def __init__(self,n,p):
      self.species=n
      self.__price = p
  def shout(self):
      print("汪汪")
      
class Spotty_dog(Dog):
     pass                

a=Spotty_dog("斑点狗",2000)
a.shout()

程序结果:

汪汪
  • 在Python语言中,object类是所有类的最终父类,所有类最顶层的根都是object类。
  • 在程序中创建一个类时,除非明确指定父类,否侧默认从python的根类object继承。
  • 子类自动继承父类中的公共属性和方法
  • 子类不能继承父类的私有属性,也无法在子类中访问父类的私有属性。
  • 子类可以增加新的属性
  • 父类与子类如果同时定义了名称相同的属性名称,父类中的属性在子类中将被覆盖。
class Dog:
     food="骨头"
     def __init__(self,n,p):
          self.species=n
          self.__price = p
     def shout(self):
          print("汪汪")
      
class Spotty_dog(Dog):
     color="白色" #增加新的属性
     food="狗粮"
     
a=Spotty_dog("斑点狗",2000)
a.shout()
print(a.food,a.color)
print(a.__price)     # 出错 无法在子类中访问父类的私有属性
class Dog:
     food="骨头"
     def __init__(self,n,p):
          self.species=n
          self.__price = p
     def shout(self):
          print("汪汪")
                 
class Spotty_dog(Dog):
     def __init__(self,h):    # 重新写属性
          self.color="白色"    #增加新的属性
          self.food="狗粮"
a=Spotty_dog(200)
print(a.color)
b=Spotty_dog('斑点狗',200)   # 重写了属性 不会调用父类的属性
print(a.species)

程序结果:

白色
Traceback (most recent call last):
  File "/Users/eve/Desktop/PYTHON/SchoolCourse/第8章类/代码/2020-06-11/eg8_7_2.py", line 15, in <module>
    b=Spotty_dog('斑点狗',200)
TypeError: __init__() takes 2 positional arguments but 3 were given

思考8-12:子类Shark,继承Fish类;产生Shark对象时,能初始化其hungry属性为True,请写Shark类代码。

import random
class Fish:
     def __init__(self):
          self.x=random.randint(0,10)
          self.y=random.randint(0,10)
     def move(self):
          self.x-=1
          print("我的位置是",self.x,self.y)

答:

import random
class Fish:
     def __init__(self):
          self.x=random.randint(0,10)
          self.y=random.randint(0,10)
     def move(self):
          self.x-=1
          print("我的位置是",self.x,self.y)
class Shark(Fish):
     def __init__(self):
          self.hungry=True

a=Shark()
print(a.hungry)
super()函数

若Shark在产生对象时,除了能有自己的hungry属性,也想具有Fish类的x和y属性,那该如何操作?

super()函数:能够自动找到基类的方法,而且还传递了self参数。调用方式:

super().方法名称(参数)

super().__init__()可以调用父类中的构造函数,这样子类也具有父类中构造函数里面的属性。

思考8-13:

若Shark在产生对象时,除了能有自己的hungry属性,也想具有Fish类的x和y属性,那该如何操作?改进后的代码:

import random as ran
class Fish:
     def __init__(self):
          self.x=ran.randint(0,10)
          self.y=ran.randint(0,10)
     def move(self):
          self.x-=1
          print("我的位置是{},{}".format(self.x,self.y))
class Shark(Fish):
     def __init__(self):
          self.hungry=True
          super().__init__()
s=Shark()
s.move()

程序结果:

我的位置是0,5

思考8_14:下面代码的运行结果是什么?

class Foo(object):
  def __init__(self, a, b):
    self.a = a
    self.b = b
class Bar(Foo):
  def __init__(self, a, c):     
    super().__init__(a,"有担当")   # 创建了a,b属性
    self.c = c
n = Bar("有理想","有本领")
print (n.a)
print (n.b)
print (n.c)

程序运行结果:

有理想
有担当
有本领

思考8-15:下面红色代码哪些是错误的

class Product( ):
    id = 0
    def __init__(self,name,price):
        Product.id=Product.id+1
        self.name=name
        self.__price=price     
    def getPrice(self):       
        return self.__price    
    def __setPrice(self,value):
        self.__price=value
class MobilePhone(Product):
    def __init__(self,name,price,standard):
      ####### 一下错误的地方有哪些
        super().__init__(name,price)
        self.netstandard=standard
        print(self.name)
        print(self.id)
        print(self.__price)    
        print(self.getPrice())
        print(super().__setPrice())  
     #######   
class Product( ):
    id = 0
    def __init__(self,name,price):
        Product.id=Product.id+1
        self.name=name
        self.__price=price     
    def getPrice(self):       
        return self.__price    # 返回数值
    def __setPrice(self,value):
        self.__price=value
class MobilePhone(Product):
    def __init__(self,name,price,standard):
        super().__init__(name,price)
        self.netstandard=standard
        print(self.name)
        print(self.id)
        print(self.__price)    # 错误 在类的外面
        print(self.getPrice())
        print(super().__setPrice())     # 错误  私有方法在外面都不能访问它

a=MobilePhone("iphone",2000,"large")

程序运行

iphone
1
Traceback (most recent call last):
  File "/Users/eve/Desktop/PYTHON/SchoolCourse/第8章类/代码/2020-06-11/si8_15.py", line 21, in <module>
    a=MobilePhone("iphone",2000,"large")
  File "/Users/eve/Desktop/PYTHON/SchoolCourse/第8章类/代码/2020-06-11/si8_15.py", line 17, in __init__
    print(self.__price)    # 错误
AttributeError: 'MobilePhone' object has no attribute '_MobilePhone__price'
  • 子类继承父类中的非私有属性和非私有方法
  • 子类不能继承父类的私有属性和私有方法,也无法在子类中访问父亲的私有属性和私有方法。
  • 子类可添加自己的属性和方法
  • 子类可重新定义继承父类的方法
  • super()函数可以调用父类的公有属性和方法

Python支持多继承,多继承就是子类拥有多个父类,并且具有它们共同的特征,即子类继承了父类公有的方法和属性

多继承

多继承可以看做是单继承的扩展,语法格式如下:

class 子类名(父类1,父类2,...):

父类里的方法名相同,默认从左到右调用括号里的父类

class Person:
     def __init__(self,myhair,myage):
          self.hair=myhair
          self.hand=2
          self.__age=myage
     def  move(self):
          print('走路')
     
class Fish:
     tail=1
     def   move(self):
          print('游泳')
     
class Mermaid(Person,Fish):
     pass

a=Mermaid("长头发",20)
a.move()
print(a.tail)

程序结果:

走路
1

思考 si8_16.py:下面代码的运行结果是什么?


class Product(): 
    def testClassicalClass(self):
        print('执行Product类')
class Computer(Product):
    def testMethod(self):
        print('执行Computer类')
class MobilePhone(Product):
    def testClassicalClass(self):
        print('执行MobilePhone类')
class SmartMobile (Computer,MobilePhone):
    def testMethod(self):
        print('执行SmartMobile类')
s = SmartMobile()    # Computer,MobilePhone
s.testClassicalClass()  # Computer->MobilePhone->testClassicalClass->"执行MobilePhone类"
s.testMethod()    # 父类与子类如果同时定义了名称相同的属性名称,父类中的属性在子类中将被覆盖。

程序结果:

执行MobilePhone类
执行SmartMobile类

8.9 运算符的重载

运算符重载,对某种方法进行冲写,如:

>>> 2+3
5
#这边的加号两边是两个数值,计算二者的和
>>> "ab"+"cd"
'abcd'
#这边的加法运算在字符串类中被赋予了新的功能,这就是运算符重载

为运算符定义方法被称为运算符的重载,每个运算符都对应着一个函数,因此重载运算符就是实现函数。

例如:“+”运算符是类里提供的__add__这个函数(并不是私有方法),当调用”+“实现加法运算的时候,实际上是调用了__add__方法

>>> "ab".__add__("cd")
'abcd'
# __add__方法重载了运算符“+”
# 即m.__add__(n)与m+n是一致的

常用的运算符与函数的对应关系

运算符关系型运算符
+__add__(self,other)
-__sub__(self,other)
*__mul__(self,other)
/__truediv__(self,other)
//__floordiv__(self,other)
%__mod__(self,other)
**__pow__(self,other)
<__lt__(self,other)
<=__le__(self,other)
======__eq__(self,other)
>__gt__(self,other)
>=__ge__(self,other)
!=__ne__(self,other)

[例] 定义Number类,使得该类的对象x能与数值进行加法运算。如x=Number(5);x+2结果为7

#eg8_10
class Number:
    def __init__(self,start):  # start=5
        self.data=start        # self.data=5
    def __add__(self,other):   # _add_   +
        return self.data+other  # self.data+other = 5+2

x=Number(5)
print(x+2)

程序结果:

7

倘若想要实现x=Number()5,y=Number(7),print(x+y)

class Number:
    def __init__(self,start):  # start=5    start=7
        self.data=start        # x=self.data=5   y=self.data=7
    def __add__(self,other):    
        return self.data+other.data   # x.data+y.data=5+7

x=Number(5)   # 传递给self
#print(x+2) 
y=Number(7)   # other的data
print(x+y)    # x传给self,y传给other

程序结果:

12
#eg8_11
class Number:
    def __init__(self,a):   # a="ab"     a="ab"
        self.data=a         # x.data="ab"  y.data="ab"   
    def __lt__(self,other):   # x=self  y=other 
        return self.data<other.data    # x.data < y.data ab<ab
         
x=Number("ab")
y=Number("ab")
print(x<y)

程序结果:

False
class Number:
    def __init__(self,a):
        self.data=a
    def __lt__(self,other):
        return self.data<other.data
         
#x=Number("ab")
#y=Number("ab")
x=Number(2)
y=Number(4)
print(x<y)

程序结果:

True

常用的运算符与函数的对应关系

运算符方法说明
[index]__getitem__(self,index)按照索引取值
__setitem__()按照索引赋值
in__contains__(self,value)是否为成员
len__len__(self)元素个数
str__str__(self)与str()\print()对应,要求该方法必须返回str类型的数据

[例]:定义Number类,类的对象x可以进行分片和修改元素的操作。

如:x=Number([1,2,3,4,5]);x=[2:4]=[6]

class Number:
    def __init__(self,a):             # a=[1,2,3,4,5]
        self.data=a[:]                # 对a进行拷贝  self.data=[1,2,3,4,5]
    def __getitem__(self,index):      # 按照索引取值
        return self.data[index]       # x=[1,2,6,5]
    def __setitem__(self,index,value):
          self.data[index]=value      #  x.data[2:4]=6 
        
x=Number([1,2,3,4,5])   # a=[1,2,3,4,5]   self.data=[1,2,3,4,5]
x[2:4]=[6]      # x中的3,4被替换成6了    
print(x[:])     # x=[1,2,6,5]

程序结果:

[1, 2, 6, 5]

__str()__重载时:必须返回str类型的数据。当运行str(对象)或是print(对象)时会触发该方法。

class test:
    datal = 10
a=test()
t=str(a)
print(t)

程序结果:

<__main__.test object at 0x10ee26fd0>
class test:
    datal = 10
    def __str__(self):
        return "Hi, I am test"
a=test()
t=str(a)
print(t)

程序结果:

Hi, I am test

思考8_18:下面程序的运行结果是什么?

class test:
   data1=100
   def __init__(self,n):
       self.data2=n
   def __str__(self):
       return "data1={},data2={}".format(self.data1,self.data2)
a=test(20)
print(a)   # print会触发 __str__()这个方法

程序结果:

data1=100,data2=20

思考8_19:补充完整Rectangle类,使得该类的对象可以进行如下运算:

1.a+b:求出两个矩形的面积和。

2.a==b:判断两个面积是否相等;若a==b,表达式的值为”相等“,否则为”不相等“。

3.print(a):打印出该矩形的面积

class Rectangle:###补充完整,使其对象能进行+,==,print操作
    def __init__(self,w,h):
        self.width=w
        self.height=h
    def getArea(self):
        return self.width*self.height

############################
a=Rectangle(2,4)
print(a)
b=Rectangle(3,6)
print(a+b)
print(a==b)

答:

class Rectangle:###补充完整,使其对象能进行+,==,print操作
    def __init__(self,w,h):
        self.width=w
        self.height=h
    def getArea(self):
        return self.width*self.height
    def __add__(self, other):
        return self.getArea()+other.getArea()
    def __eq__(self, other):
        if self.getArea()==other.getArea():
            return "相等"
        else:
            return "不相等"
    def __str__(self):
        return "该矩形的面积为"+str(self.getArea())
############################
a=Rectangle(2,4)
print(a)
b=Rectangle(3,6)
print(a+b)
print(a==b)

程序结果:

该矩形的面积为8
26
不相等

思考8_19_1:

#8_19_1
class Rectangle:
    def __init__(self,w,h):
        self.width=w
        self.height=h
    def getArea(self):
        return self.width*self.height
    def __add__(self,other):
         return "两矩形的面积和是:"+str(self.getArea()+other.getArea())
    def __eq__(self,other):
          if self.getArea()==other.getArea():
               return "相等"
          else:
               return "不相等"
    def __str__(self):
          return "该矩形的面积是:"+str(self.getArea())

if __name__ == '__main__':     # 当作主程序运行
    print('I runs as main')
else: 
    print(__name__,'I runs as a module')    # 当作模块导入另一文件运行

程序结果:

I runs as main

若代码是主程序,__name__值为__main__;若代码作为import模块,__name__值为文件名

当被当作模块被导入其他文件运行

from si8_19_1 import Rectangle  # 代码模块文件导入
a=Rectangle(2,4)
print(a)
b=Rectangle(3,6)
print(a+b)
print(a==b)

程序结果:

si8_19_1 I runs as a module
该矩形的面积是:8
两矩形的面积和是:26
不相等
补充:自定义异常类
  • 有时候需要自定义一些异常类,系统无法识别自定义的异常类,只能在程序中使用raise抛出异常。
  • raise唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是Exception的子类)
#eg8_13:
try:                 # try ... except 捕捉异常语句
    raise NameError   # raise抛出异常类的子类
except NameError:
    print("An exception flew by!")

程序结果:

An exception flew by!

思考8_20:运行该程序时输入15或150的结果是什么?

def get_age():
    age = int(input('请输入年龄(1-140):'))    #15          150
    if age in range(1,141):                 #15 is in     150 is not in
        return age                          # 15         
    raise ValueError                        # 150 抛出异常

try:
    age = get_age()      # 调用这个函数
    print('用户输入的年龄是:', age)           #15
except ValueError:           
    print('用户输入的年龄不在1-140之间!')      # 150
 

程序结果:

请输入年龄(1-140):15
用户输入的年龄是: 15

请输入年龄(1-140):150
用户输入的年龄不在1-140之间!

思考8_21:下面程序的运行结果是什么?

class MyError(Exception):
    def __init__(self,value):   # 4
        self.value=value        # 4
    def  __str__(self):
        return   self.value     
    
try:
    raise MyError(2*2)
except MyError  as e :
    print("An exception flew by!",e.value)

程序结果:

An exception flew by! 4

总结:

  • 类的定义与使用
  • 构造方法与析构方法
  • 属性(公有与私有,类属性与实例属性)
  • 类的方法(公有、私有、静态、类方法、抽象方法)
  • property内置函数与修饰词
  • 继承
  • 多态、运算符的重载

实验

一、 实验目的和要求

(1)类的继承;(2)调用超类的构造方法;(3)运算符重载 (4)异常处理

  1. 【题目描述】

请打开shiyan8_1.py,补充完Vecter3的定义,进行运算符重载,使得该类能进行加法和乘法运算,并能打印。程序另存为学号_1.py。程序运行结果如下:

5,7,9
10,20,30

解:

##请补充完类Vecter3的定义
class Vecter3(object):
    def __init__(self,x,y,z):
        self.X=x
        self.Y=y
        self.Z=z

    def __add__(self,other):
        t=Vecter3(0,0,0)
        t.X=self.X+other.X
        t.Y=self.Y+other.Y
        t.Z=self.Z+other.Z
        return t
    def __mul__(self, n):
        t=Vecter3(0,0,0)
        t.X=self.X*n
        t.Y=self.Y*n
        t.Z=self.Z*n
        return t

    def __str__(self):
        return str(self.X)+","+str(self.Y)+","+str(self.Z)
##下面代码请不要修改   
if __name__=='__main__':
    v1=Vecter3(1,2,3)
    v2=Vecter3(4,5,6)
    print(v1+v2)
    print(v1*10)
   

程序结果:

5,7,9
10,20,30

2.【题目描述】

以r+模式打开用户输入的文件。若文件不存在,系统会产生异常FileNotFoundError,请捕捉该异常类,然后输出“该文件不存在”。若文件存在,让用户输入字符串,保存到该文件中。当用户输入-1,结束输入。当用户输入的字符串长度大于10,要抛出InvalidError类。请捕捉InvalidError类并产生实例t,执行print(t)和fp.close()。请打开shiyan8_2.py文件,补充完代码,程序另存为学号_2.py。

  1. 当输入的文件不存在,程序运行结果如下所示:
输入文件名:ff
文件不存在
  1. 当输入的文件存在时,程序运行结果如下所示:
输入文件名:f1.txt
输入字符串:hello
输入字符串:You are welcome
输入的字符串太长,长度为15

解:

class InvalidError(BaseException):  
    def __init__(self,n):
        super().__init__()
        self.num=n
    def __str__(self):
        return "输入的字符串太长,长度为"+str(self.num)
    
####当文件不存在,要能捕捉FileNotFoundError(系统产生的异常类)
####当文件存在,用户输入数据保存到文件中
####若输入的字符串长度>10,抛出InvalidError(自定义的异常类)
####要能捕捉InvalidError
####当用户输入-1结束输入

try:
    filename = input('输入文件名:')
    fp = open(filename , "r+")
    ch = input("输入字符串:")
    while ch!='-1':
        if len(ch)<=10:
            fp.write(ch)
            ch=input("输入字符串:")
        else:
            raise InvalidError(len(ch))
except FileNotFoundError:
    print("文件不存在")
except InvalidError as t:
    print(t)
    fp.close()

程序结果:

输入文件名:ff
文件不存在
输入文件名:f1.txt
输入字符串:hello
输入字符串:You are welcome
输入的字符串太长,长度为15
  • 31
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值