Python3极简教程(一小时学完)中

异常

在这个实验我们学习 Python 的异常以及如何在你的代码中处理它们。

知识点
  • NameError
  • TypeError
  • 异常处理(try..except)
  • 异常抛出(raise)
  • finally 子句

异常

在程序执行过程中发生的任何错误都是异常。每个异常显示一些相关的错误信息,比如你在 Python3 中使用 Python2 独有的语法就会发生 SyntaxError

此处输入图片的描述

不小心在行首多打了一个空格就会产生 IndentationError

此处输入图片的描述

NameError

当访问一个未定义的变量则会发生 NameError

>>> print(kushal)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
NameError: name 'kushal' is not defined

最后一行包含了错误的详细信息,其余行显示它是如何发生(或什么引起该异常)的详细信息。

TypeError

TypeError 也是一种经常出现的异常。当操作或函数应用于不适当类型的对象时引发,一个常见的例子是对整数和字符串做加法。

>>> print(1 + "kushal")
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

处理异常

我们使用 try...except 块来处理任意异常。基本的语法像这样:

try:statements to be inside try clausestatement2statement3...
except ExceptionName:statements to evaluated in case of ExceptionName happens

它以如下方式工作:

  • 首先,执行  try  子句 (在  try  和  except  关键字之间的部分)。

  • 如果没有异常发生,except  子句 在  try  语句执行完毕后就被忽略了。

  • 如果在 try 子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。

    如果异常匹配于  except  关键字后面指定的异常类型,就执行对应的 except 子句。然后继续执行  try  语句之后的代码。

  • 如果发生了一个异常,在  except  子句中没有与之匹配的分支,它就会传递到上一级  try  语句中。

  • 如果最终仍找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。

下面的例子展示了这些情况:

>>> def get_number():
...     "Returns a float number"
...     number = float(input("Enter a float number: "))
...     return number
...
>>>
>>> while True:
...     try:
...         print(get_number())
...     except ValueError:
...         print("You entered a wrong value.")
...
Enter a float number: 45.0
45.0
Enter a float number: 24,0
You entered a wrong value.
Enter a float number: Traceback (most recent call last):File "<stdin>", line 3, in <module>File "<stdin>", line 3, in get_number
KeyboardInterrupt

首先我输入了一个合适的浮点值,解释器返回输出这个值。

然后我输入以逗号分隔的值,抛出 ValueError 异常,except 子句捕获之,并且打印出错误信息。

第三次我按下 Ctrl + C ,导致了 KeyboardInterrupt 异常发生,这个异常并未在 except 块中捕获,因此程序执行被中止。

一个空的 except 语句能捕获任何异常。阅读下面的代码:

>>> try:
...     input() # 输入的时候按下 Ctrl + C 产生 KeyboardInterrupt
... except:
...     print("Unknown Exception")
...
Unknown Exception

抛出异常

使用 raise 语句抛出一个异常。

>>> raise ValueError("A value error happened.")
Traceback (most recent call last):File "<stdin>", line 1, in <module>
ValueError: A value error happened.

我们可以捕获任何其它普通异常一样,来捕获这些异常。

>>> try:
...     raise ValueError("A value error happened.")
... except ValueError:
...     print("ValueError in our code.")
...
ValueError in our code.

定义清理行为

try 语句还有另一个可选的 finally 子句,目的在于定义在任何情况下都一定要执行的功能。例如:

>>> try:
...     raise KeyboardInterrupt
... finally:
...     print('Goodbye, world!')
...
Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):File "<stdin>", line 2, in ?

不管有没有发生异常,finally 子句 在程序离开 try 后都一定会被执行。当 try 语句中发生了未被 except 捕获的异常(或者它发生在 except 或 else 子句中),在 finally 子句执行完后它会被重新抛出。

在真实场景的应用程序中,finally 子句用于释放外部资源(文件或网络连接之类的),无论它们的使用过程中是否出错。

总结

本实验我们知道了异常是什么,然后怎样处理异常以及抛出异常。记得在前面说过的 with 语句吧,它是 try-finally 块的简写,使用 with 语句能保证文件始终被关闭。

异常是什么?其实异常是一种,而类将会在下一个实验介绍。

挑战:玩转函数

介绍

本次挑战中我们将实现一个程序,将分钟转为小时和分钟。

注意:代码中不要使用 input() 函数,否则挑战测试会卡住,出现 Timeout 的报错。

目标

请在 /home/shiyanlou/Code 创建代码文件 MinutesToHours.py

cd /home/shiyanlou/Code
touch MinutesToHours.py

在 MinutesToHours.py 文件中实现一个函数 Hours(),将用户输入的 分钟数 转化为 小时数和分钟数,并要求小时数尽量大。将结果以 XX H, XX M 的形式打印出来。

要求

  1. 用户能够通过命令行参数输入分钟数,不要使用 input,命令行参数可以使用 sys.argv 来提取。例如程序执行为 python3 MinutesToHours.py 80,传入的参数 80 就是分钟数,程序需要打印出相应的小时数和分钟数,输出为 1 H, 20 M
  2. 如果用户输入的是一个负值,程序需要 raise 来抛出 ValueError 异常。
  3. Hours() 函数调用的时候,需要使用 try...except 处理异常。获取异常后,在屏幕上打印出 Parameter Error 提示用户输入的值有误。

操作实例

python3 /home/shiyanlou/Code/MinutesToHours.py 80
1 H, 20 Mpython3 /home/shiyanlou/Code/MinutesToHours.py 95
1 H, 35 Mpython3 /home/shiyanlou/Code/MinutesToHours.py -10
Parameter Errorpython3 /home/shiyanlou/Code/MinutesToHours.py abcd
Parameter Error

提示语

  • sys.argv 获取命令行参数,注意获取的参数为字符串,可以使用 int() 将字符串转为整数,此处也可能会出现异常情况,例如输入为 "abcd" 是无法转为整数的
  • raise 语句
  • try...except 语句

知识点

  • 异常
  • 文件处理
  • if-else

参考代码

注意:请务必先独立思考获得 PASS 之后再查看参考代码,直接拷贝代码收获不大。

/home/shiyanlou/Code/MinutesToHours.py 参考代码:

参考答案

import sys
# 转换函数
def Hours(minute):# 如果为负数则 raise 异常if minute < 0:raise ValueError("Input number cannot be negative")else:print("{} H, {} M".format(int(minute / 60), minute % 60))# 函数调用及异常处理逻辑
try:Hours(int(sys.argv[1]))
except:print("Parameter Error")

在 Python 中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。

知识点
  • 类的定义
  • 对象初始化

本部分实验中将通过定义一些简单的 Python 类,来学习 Python 面向对象编程的基本概念。

实验安排如下:

  1. 定义简单的类
  2. __init__ 方法
  3. Python 中的继承
  4. 多继承
  5. 删除对象
  6. 属性读取方法
  7. @property 装饰器

定义类

在写你的第一个类之前,你应该知道它的语法。我们以下面这种方式定义类:

class nameoftheclass(parent_class):statement1statement2statement3

在类的声明中你可以写任何 Python 语句,包括定义函数(在类中我们称为方法)。

>>> class MyClass(object):
...     """A simple example class"""
...     i = 12345
...     def f(self):
...         return 'hello world'

__init__ 方法

类的实例化使用函数符号。只要将类对象看作是一个返回新的类实例的无参数函数即可。例如(假设沿用前面的类):

x = MyClass()

以上创建了一个新的类实例并将该对象赋给局部变量  x

这个实例化操作创建一个空的对象。很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为  __init__()  的特殊方法,像下面这样:

def __init__(self):self.data = []

类定义了  __init__()  方法的话,类的实例化操作会自动为新创建的类实例调用  __init__()  方法。所以在下例中,可以这样创建一个新的实例:

x = MyClass()

当然,出于弹性的需要,__init__()  方法可以有参数。事实上,参数通过__init__()  传递到类的实例化操作上。例如:

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

继承

当一个类继承另一个类时,它将继承父类的所有功能(如变量和方法)。这有助于重用代码。

在下一个例子中我们首先创建一个叫做 Person 的类,然后创建两个派生类 Student 和 Teacher。当两个类都从 Person 类继承时,它们的类除了会有 Person 类的所有方法还会有自身用途的新方法和新变量。

student_teacher.py

代码写入文件 /home/shiyanlou/student_teacher.py

#!/usr/bin/env python3class Person(object):"""返回具有给定名称的 Person 对象"""def __init__(self, name):self.name = namedef get_details(self):"""返回包含人名的字符串"""return self.nameclass Student(Person):"""返回 Student 对象,采用 name, branch, year 3 个参数"""def __init__(self, name, branch, year):Person.__init__(self, name)self.branch = branchself.year = yeardef get_details(self):"""返回包含学生具体信息的字符串"""return "{} studies {} and is in {} year.".format(self.name, self.branch, self.year)class Teacher(Person):"""返回 Teacher 对象,采用字符串列表作为参数"""def __init__(self, name, papers):Person.__init__(self, name)self.papers = papersdef get_details(self):return "{} teaches {}".format(self.name, ','.join(self.papers))person1 = Person('Sachin')
student1 = Student('Kushal', 'CSE', 2005)
teacher1 = Teacher('Prashad', ['C', 'C++'])print(person1.get_details())
print(student1.get_details())
print(teacher1.get_details())

运行程序

此处输入图片的描述

在这个例子中你能看到我们是怎样在 Student 类和 Teacher 类中调用 Person 类的 __init__ 方法。

我们也在 Student 类和 Teacher 类中重写了 Person 类的 get_details() 方法。

因此,当我们调用 student1 和 teacher1 的 get_details() 方法时,使用的是各自类(Student 和 Teacher)中定义的方法。

多继承

一个类可以继承自多个类,具有父类的所有变量和方法,语法如下:

class MyClass(Parentclass1, Parentclass2,...):def __init__(self):Parentclass1.__init__(self)Parentclass2.__init__(self)......

这里没有提供额外的实例,将会在其他实验楼的项目实战中用到。

删除对象

现在我们已经知道怎样创建对象,现在我们来看看怎样删除一个对象。我们使用关键字 del 来做到这个。

>>> s = "I love you"
>>> del s
>>> s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 's' is not defined

del 实际上使对象的引用计数减少一,当对象的引用计数变成零的时候,垃圾回收器会删除这个对象。

属性(_attributes_)读取方法

在 Python 里请不要使用属性(attributes_)读取方法(_getters 和 _setters_)。如果你之前学过其它语言(比如 Java),你可能会想要在你的类里面定义属性读取方法。请不要这样做,直接使用属性就可以了,就像下面这样:

>>> class Student(object):
...     def __init__(self, name):
...         self.name = name
...
>>> std = Student("Kushal Das")
>>> print(std.name)
Kushal Das
>>> std.name = "Python"
>>> print(std.name)
Python

装饰器

你可能想要更精确的调整控制属性访问权限,你可以使用 @property 装饰器,@property 装饰器就是负责把一个方法变成属性调用的。

下面有个银行账号的例子,我们要确保没人能设置金额为负,并且有个只读属性 cny 返回换算人民币后的金额。

代码写入文件 /home/shiyanlou/property.py

#!/usr/bin/env python3class Account(object):"""账号类,amount 是美元金额."""def __init__(self, rate):self.__amt = 0self.rate = rate@propertydef amount(self):"""账号余额(美元)"""return self.__amt@propertydef cny(self):"""账号余额(人民币)"""return self.__amt * self.rate@amount.setterdef amount(self, value):if value < 0:print("Sorry, no negative amount in the account.")returnself.__amt = valueif __name__ == '__main__':acc = Account(rate=6.6) # 基于课程编写时的汇率acc.amount = 20print("Dollar amount:", acc.amount)print("In CNY:", acc.cny)acc.amount = -100print("Dollar amount:", acc.amount)

运行程序:

此处输入图片的描述

总结

实验知识点回顾:

  • 类的定义
  • 对象初始化

本实验我们了解了类的定义,类的继承以及多继承,并且最后我们还接触了装饰器这个概念,本质上,装饰器也是一种高阶函数。

模块

在这个实验我们将要学习 Python 模块相关知识。包括模块的概念和导入方法,包的概念和使用,第三方模块的介绍,命令行参数的使用等。

知识点
  • 模块的导入
  • 默认/第三方模块介绍
  • 命令行参数

模块

到目前为止,我们在 Python 解释器中写的所有代码都在我们退出解释器的时候丢失了。但是当人们编写大型程序的时候他们会倾向于将代码分为多个不同的文件以便使用,调试以及拥有更好的可读性。在 Python 中我们使用模块来达到这些目的。模块是包括 Python 定义和声明的文件。文件名就是模块名加上  .py  后缀。

你可以由全局变量 __name__ 得到模块的模块名(一个字符串)。

现在我们来看看模块是怎样工作的。创建一个 bars.py 文件。文件内容如下:

"""
Bars Module
============
这是一个打印不同分割线的示例模块
"""
def starbar(num):"""打印 * 分割线:arg num: 线长"""print('*' * num)def hashbar(num):"""打印 # 分割线:arg num: 线长"""print('#' * num)def simplebar(num):"""打印 - 分割线:arg num: 线长"""print('-' * num)

现在我们启动解释器然后导入我们的模块。

>>> import bars
>>>

我们必须使用模块名来访问模块内的函数。

>>> bars.hashbar(10)
##########
>>> bars.simplebar(10)
----------
>>> bars.starbar(10)
**********

导入模块

有不同的方式导入模块。我们已经看到过一种了。你甚至可以从模块中导入指定的函数。这样做:

>>> from bars import simplebar, starbar
>>> simplebar(20)
--------------------

你也可以使用 from module import * 导入模块中的所有定义,然而这并不是推荐的做法。

含有 __init__.py 文件的目录可以用来作为一个包,目录里的所有 .py 文件都是这个包的子模块。

本节实验将创建下面的 mymodule 目录,目录结构如下:

此处输入图片的描述

在这个例子中,mymodule 是一个包名并且 bars 和 utils 是里面的两个子模块。

首先创建 mymodule 目录:

cd /home/shiyanlou
mkdir mymodule

然后将上一节编写的 bars.py 拷贝到 mymodule 目录下,然后可以使用 touch 创建一个 utils.py 文件。

使用 touch 命令创建一个空的 __init__.py 文件。

touch mymodule/__init__.py

如果 __init__.py 文件内有一个名为 __all__ 的列表,那么只有在列表内列出的名字将会被公开。

因此如果 mymodule 内的 __init__.py 文件含有以下内容:

from mymodule.bars import simplebar
__all__ = [simplebar, ]

那么导入时将只有 simplebar 可用。如果你在 python3 解释器中进行测试,需要确定是在 mymodule 目录同级的目录下执行的 python3,类似下面的操作,否则会出现 ImportError: No module named 'mymodule' 的报错。

cd /home/shiyanlou
python3
>>>

from mymodule import * 只能工作在模块级别的对象上,试图导入函数或类将导致 syntax error。

参考资料

默认模块

现在你安装 Python 的时候会附带安装不同的模块,你可以按需使用它们,也可以为其它特殊用途安装新模块。在下面的几个例子中,我们将要看到同样例子很多。

modules

上面的例子展示了怎样获得你系统中安装的所有模块的列表。在这里就不粘贴它们了,因为这是一个很大的列表。

你也能在解释器里使用 help() 函数查找任何模块/类的文档。如果你想要知道字符串所有可用的方法,你可以像下面这样做:

>>> help(str)

os 模块

os 模块提供了与操作系统相关的功能。你可以使用如下语句导入它:

>>> import os

getuid() 函数返回当前进程的有效用户 id。

>>> os.getuid()
500

getpid() 函数返回当前进程的 id。getppid() 返回父进程的 id。

>>> os.getpid()
16150
>>> os.getppid()
14847

uname() 函数返回识别操作系统的不同信息,在 Linux 中它返回的详细信息可以从 uname -a 命令得到。uname() 返回的对象是一个元组,(sysname, nodename, release, version, machine)

>>> os.uname()
('Linux', 'd80', '2.6.34.7-56.fc13.i686.PAE', '#1 SMP Wed Sep 15 03:27:15 UTC 2010', 'i686')

getcwd() 函数返回当前工作目录。chdir(path) 则是更改当前目录到 path。在例子中我们首先看到当前工作目录是 /home/shiyanlou,然后我们更改当前工作目录到 /Code 并再一次查看当前工作目录。

>>> os.getcwd()
'/home/shiyanlou'
>>> os.chdir('Code')
>>> os.getcwd()
'/home/shiyanlou/Code'

所以现在让我们使用 os 模块提供的另一个函数来创建一个自己的函数,它将列出给定目录下的所有文件和目录。

def view_dir(path='.'):"""这个函数打印给定目录中的所有文件和目录:args path: 指定目录,默认为当前目录"""names = os.listdir(path)names.sort()for name in names:print(name, end =' ')print()

使用例子中的 view_dir() 函数。

>>> view_dir('/')
.bashrc .dockerenv .profile bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

os 模块还有许多非常有用的函数,你可以在这里阅读相关内容。

Requests 模块

Requests 是一个第三方 Python 模块,其官网的介绍如下:

Requests 一个非转基因的 Python HTTP 库,人类可以安全享用。

警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症、冗余代码症、重新发明轮子症、啃文档症、抑郁、头疼、甚至死亡。

第三方模块并不是默认的模块,意味着你需要安装它,我们使用 pip3 安装它。

首先要安装 pip3

sudo apt-get update
sudo apt-get install python3-pip

然后用 pip3 安装 requests

sudo pip3 install requests

上面的命令会在你的系统中安装 Python3 版本的 Requests 模块。

获得一个简单的网页

你可以使用 get() 方法获取任意一个网页。

>>> import requests
>>> req = requests.get('https://github.com')
>>> req.status_code
200

req 的 text 属性存有服务器返回的 HTML 网页,由于 HTML 文本太长就不在这里贴出来了。

使用这个知识,让我们写一个能够从指定的 URL 中下载文件的程序。

代码写入文件 /home/shiyanlou/download.py

#!/usr/bin/env python3
import requestsdef download(url):'''从指定的 URL 中下载文件并存储到当前目录url: 要下载页面内容的网址'''# 检查 URL 是否存在try:req = requests.get(url)except requests.exceptions.MissingSchema:print('Invalid URL "{}"'.format(url))return# 检查是否成功访问了该网站if req.status_code == 403:print('You do not have the authority to access this page.')returnfilename = url.split('/')[-1]with open(filename, 'w') as fobj:fobj.write(req.content.decode('utf-8'))print("Download over.")if __name__ == '__main__':url = input('Enter a URL: ')download(url)

测试一下程序:

此处输入图片的描述

可以看到目录下已经多了一个 sample.txt 文件。

你可能已经注意到了 if __name__ == '__main__': 这条语句,它的作用是,只有在当前模块名为 __main__ 的时候(即作为脚本执行的时候)才会执行此 if 块内的语句。换句话说,当此文件以模块的形式导入到其它文件中时,if 块内的语句并不会执行。

你可以将上面的程序修改的更友好些。举个例子,你可以检查当前目录是否已存在相同的文件名。os.path 模块可以帮助你完成这个。

argparse 命令行参数处理模块

你还记得 ls 命令吗,你可以传递不同的选项作为命令行参数。

这里是用到的模块是 sys,命令行传入的所有参数都可以使用 sys.argv 获取。如果希望对参数进行处理可以使用 argparse 模块,阅读这篇 文档 学习。

TAB 补全

首先创建一个文件:~/.pythonrc ,文件内写入如下内容:

import rlcompleter, readline
readline.parse_and_bind('tab: complete')history_file = os.path.expanduser('~/.python_history')
readline.read_history_file(history_file)import atexit
atexit.register(readline.write_history_file, history_file)

下一步在 ~/.bashrc 文件中设置 PYTHONSTARTUP 环境变量指向这个文件:

export PYTHONSTARTUP=~/.pythonrc

现在,从今以后每当你打开 bash shell,你将会有 TAB 补全和 Python 解释器中代码输入的历史记录。

要在当前 shell 中使用,source 这个 bashrc 文件。

source ~/.bashrc

总结

本实验了解了什么是模块,模块怎样导入,举例了 os 和 Requests 模块的使用。Python 吸引人的一点是其有众多的模块可以使用,对于自带模块,可以看看 Python3 的官方文档,对于第三方模块,可以在 PyPI 上找找。很多时候你都能找到合适的包帮你优雅的完成部分工作。比如 argparse 模块帮你非常容易的编写用户友好的命令行接口。

Collections 模块

collections 是 Python 内建的一个集合模块,提供了许多有用的集合类。

知识点
  • Counter 类
  • defaultdict 类
  • namedtuple 类

Counter

在这个实验我们会学习 Collections 模块。这个模块实现了一些很好的数据结构,它们能帮助你解决各种实际问题。

>>> import collections

这是如何导入这个模块,现在我们来看看其中的一些类。

Counter 是一个有助于 hashable 对象计数的  dict  子类。它是一个无序的集合,其中 hashable  对象的元素存储为字典的键,它们的计数存储为字典的值,计数可以为任意整数,包括零和负数。

我们可以这样查看 Counter 的帮助信息,事实上这些信息来源于 Counter 的文档字符串(collections.Counter.__doc__)。

collections.Counter

此处输入图片的描述

下面我们来看一个例子,例子中我们查看 Python 的 LICENSE 文件中某些单词出现的次数。

Counter 示例
>>> from collections import Counter
>>> import re
>>> path = '/usr/lib/python3.5/LICENSE.txt'
>>> words = re.findall('\w+', open(path).read().lower())
>>> Counter(words).most_common(10)
[('the', 80), ('or', 78), ('1', 66), ('of', 61), ('to', 50), ('and', 48), ('python', 46), ('in', 38), ('license', 37), ('any', 37)]

Counter 对象有一个叫做 elements() 的方法,其返回的序列中,依照计数重复元素相同次数,元素顺序是无序的。

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['b','b','a', 'a', 'a', 'a']

most_common() 方法返回最常见的元素及其计数,顺序为最常见到最少。

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]

defaultdict

defaultdict 是内建 dict 类的子类,它覆写了一个方法并添加了一个可写的实例变量。其余功能与字典相同。

defaultdict() 第一个参数提供了 default_factory 属性的初始值,默认值为 Nonedefault_factory 属性值将作为字典的默认数据类型。所有剩余的参数与字典的构造方法相同,包括关键字参数。

同样的功能使用 defaultdict 比使用 dict.setdefault 方法快。

defaultdict 用例:

>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> d.items()
dict_items([('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])])

在例子中你可以看到,即使 defaultdict 对象不存在某个,它会自动创建一个空列表。

namedtuple

命名元组有助于对元组每个位置赋予意义,并且让我们的代码有更好的可读性和自文档性。你可以在任何使用元组地方使用命名元组。在例子中我们会创建一个命名元组以展示为元组每个位置保存信息。

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])  # 定义命名元组
>>> p = Point(10, y=20)  # 创建一个对象
>>> p
Point(x=10, y=20)
>>> p.x + p.y
30
>>> p[0] + p[1]  # 像普通元组那样访问元素
30
>>> x, y = p     # 元组拆封
>>> x
10
>>> y
20

总结

本节知识点回顾:

  • Counter 类
  • defaultdict 类
  • namedtuple 类

这个实验我们使用了 Collections 中的一些数据结构,可能你目前并用不上他,但希望你以后需要的时候会想起它们。

挑战:类和 Collection

介绍

本次挑战中我们将通过改写之前实验中的 student_teacher.py 程序实现更加丰富的功能。

目标

改写 我们在  这个实验中 继承 部分的 student_teacher.py 脚本,实现以下功能:

  1. 在 Person() 类中增添函数 get_grade()
  2. 对于教师类,get_grade() 函数可以自动统计出老师班上学生的得分情况并按照频率的高低以 A: X, B: X, C: X, D: X 的形式打印出来
  3. 对于学生类,get_grade() 函数则可以以 Pass: X, Fail: X 来统计自己的成绩情况(A,B,C 为 Pass, 如果得了 D 就认为是 Fail)。

student_teacher.py 文件可以通过在 Xfce 终端中输入如下代码来获取

cd /home/shiyanlou/Code
wget https://labfile.oss-internal.aliyuncs.com/courses/790/student_teacher.py

要求:

  1. 请把最终的student_teacher.py 代码文件放在 /home/shiyanlou/Code/ 路径下
  2. 根据命令行中的第一个参数 teacher 或者 student 来判断最终输出的格式。
  3. 命令行中第二个输入的参数是需要统计的字符串

执行实例:

此处输入图片的描述

提示语

  • Teacher 及 Student 类的 __init__() 也要增加 grade 参数
  • import sys
  • collections 中的 Counter 子类
  • format() 以及 join

知识点

  • Collection 模块
  • 注意最终的打印形式

参考代码

注意:请务必先独立思考获得 PASS 之后再查看参考代码,直接拷贝代码收获不大。

/home/shiyanlou/Code/student_teacher.py 参考代码:

参考答案
#!/usr/bin/env python3
import sys
from collections import Counterclass Person(object):"""返回具有给定名称的 Person 对象"""def __init__(self, name):self.name = namedef get_details(self):"""返回包含人名的字符串"""return self.namedef get_grade(self):return 0class Student(Person):"""返回 Student 对象,采用 name, branch, year 3 个参数"""def __init__(self, name, branch, year,grade):Person.__init__(self, name)self.branch = branchself.year = yearself.grade = gradedef get_details(self):"""返回包含学生具体信息的字符串"""return "{} studies {} and is in {} year.".format(self.name, self.branch, self.year)def get_grade(self):common = Counter(self.grade).most_common(4)n1 = 0n2 = 0for item in common:if item[0] != 'D':n1 += item[1]else:n2 += item[1]print("Pass: {}, Fail: {}".format(n1,n2))class Teacher(Person):"""返回 Teacher 对象,采用字符串列表作为参数"""def __init__(self, name, papers, grade):Person.__init__(self, name)self.papers = papersself.grade = gradedef get_details(self):return "{} teaches {}".format(self.name, ','.join(self.papers))def get_grade(self):s = []common = Counter(self.grade).most_common(4)for i,j in common:s.append("{}: {}".format(i,j))print(', '.join(s))person1 = Person('Sachin')
if sys.argv[1] == "student":student1 = Student('Kushal', 'CSE', 2005, sys.argv[2])student1.get_grade()
else:teacher1 = Teacher('Prashad', ['C', 'C++'], sys.argv[2])teacher1.get_grade()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fasttext工具介绍

fastText是由Facebook Research团队于2016年开源的一个词向量计算和文本分类工具。尽管在学术上并未带来巨大创新&#xff0c;但其在实际应用中的表现却非常出色&#xff0c;特别是在文本分类任务中&#xff0c;fastText往往能以浅层网络结构取得与深度网络相媲美的精度&#x…

Maven一键配置阿里云远程仓库,让你的项目依赖飞起来!

文章目录 引言一、为什么选择阿里云Maven仓库&#xff1f;二、如何设置Maven阿里云远程仓库&#xff1f;三、使用阿里云Maven仓库的注意事项总结 引言 在软件开发的世界里&#xff0c;Maven无疑是一个强大的项目管理工具&#xff0c;它能够帮助我们自动化构建、依赖管理和项目…

QT5.14.2与Mysql8.0.16配置笔记

1、前言 我的QT版本为 qt-opensource-windows-x86-5.14.2。这是QT官方能提供的自带安装包的最近版本&#xff0c;更新的版本需要自己编译源代码&#xff0c;可点击此链接进行下载&#xff1a;Index of /archive/qt/5.14/5.14.2&#xff0c;选择下载 qt-opensource-windows-x86…

为什么固定尺寸 AdSense 广告依旧会出现并非指定的尺寸广告?

经常在网站上投放谷歌 AdSense广告的站长应该都碰到过&#xff0c;明明投放的是固定尺寸的广告位里旧会出现并非指定尺寸的AdSense 广告&#xff0c;很诡异的感觉。其实这都是因为你的 AdSense 账号广告优化造成的&#xff0c;其中里面就包含了广告尺寸优化&#xff0c;只需要在…

Spring源码十七:Bean实例化入口探索

上一篇Spring源码十六&#xff1a;Bean名称转化我们讨论doGetBean的第一个方法transformedBeanName方法&#xff0c;了解Spring是如何处理特殊的beanName&#xff08;带&符号前缀&#xff09;与Spring的别名机制。今天我们继续往方法下面看&#xff1a; doGetBean 这个方法…

Vue笔记11-Composition API的优势

Options API存在的问题 使用传统Options API中&#xff0c;新增或者修改一个需求&#xff0c;就需要分别在data&#xff0c;methods&#xff0c;computed里修改&#xff0c;而这些选项分布在代码的各个地方&#xff0c;中间还穿插着其他Optional API&#xff0c;如果代码量上来…

JAVA之(方法的重载与重写、this关键字、super关键字)

方法的重载与重写 一、方法的重载与重写1、回顾方法的定义2、重载的概念3、重写 二、this关键字1、何为this方法2、使用方法&#xff08;1&#xff09;在构造方法中指构造器所创建的新对象&#xff08;2&#xff09; 方法中指调用该方法的对象&#xff08;3&#xff09; 在类本…

centos7.9 rpm包安装mysql8.2.0数据库、root设置客户端登录、配置并发、表名大小写敏感、启动重启指令等记录

centos安装mysql8数据库,下载的是rpm-bundle.tar包,这样可以在内网环境离线安装,工作中医院的服务器很多也是内网的,所以这里记录下rpm-bundle.tar包安装的步骤。 lscpu 查看处理器是x86还是arm 下载对应的版本 bundle tar包 ((mysql-8.2.0-1.el7.x86_64.rpm-bundle.tar))…

2023年了,还在手动px转rem吗?

px-to-rem 使用amfe-flexible和postcss-pxtorem在webpack中配置px转rem npm i amfe-flexible -Snpm i postcss-pxtorem -D在main.js中 import flexible from amfe-flexible Vue.use(flexible);index.html中 <meta name"viewport" content"widthdevice-w…

Web3D引擎,three.js堪称扛把子,Babylon.js差点意思。

涉及到Web3D开发&#xff0c;Three.js和Babylon.js是两个备受推崇的引擎。它们都是基于WebGL的开源3D引擎&#xff0c;用于创建交互式的3D图形应用程序&#xff0c;但要细论起来&#xff0c;three.js普及度远超Babylon .js. 一、二者的介绍 Three.js&#xff1a; Three.js 是一…

Socket编程用到的函数TCP UDP实例

最基本的 Socket 模型 参考这次答应我&#xff0c;一举拿下 I/O 多路复用&#xff01; (qq.com) Socket编程详解-CSDN博客 Socket是一种通信机制&#xff0c;通过它可以在不同主机之间进行数据交换。在Socket编程中&#xff0c;有两种常见的通信模式&#xff1a;客户端-服务…

PIP换源的全面指南

##概述 在Python的世界里&#xff0c;pip是不可或缺的包管理工具&#xff0c;它帮助开发者安装和管理Python软件包。然而&#xff0c;由于网络条件或服务器位置等因素&#xff0c;直接使用默认的pip源有时会遇到下载速度慢或者连接不稳定的问题。这时&#xff0c;更换pip源到一…

在Linux操作系统中去修复/etc/fstab文件引起的系统故障。

如果/etcfstab文件中发生错误&#xff0c;有可能导致系统无法正常启动。 比如&#xff1a;系统里的一块磁盘被删除&#xff0c;但是/etc/fstab中关于这块磁盘的信息依然被保存在文件/etc/fstab中。 主要看倒数后两行&#xff0c;系统提示&#xff0c;敲ctrlD或者是直接输入密码…

Linux muduo 网络库

主要记录示意图和知识点框架&#xff1a; 1、阻塞、非阻塞、同步、异步 在处理IO的时候&#xff0c;阻塞和非阻塞都是同步IO&#xff0c;只有使用了特殊的API才是异步IO。 2、五种IO模型&#xff1a; 阻塞、非阻塞、IO复用、信号驱动、异步IO 3、muduo网络库 muduo网络库给用…

【Java】垃圾回收学习笔记(一):Root Search 根可达算法+垃圾回收的起点

文章目录 1. 引用计数法优点缺点 2. 可达性分析 Root Search2.1 那些对象是GC Roots2.2 引用的分类2.3 回收方法区 3. 实现细节3.1 GC的起点&#xff1a;节点枚举OopMap&#xff1a;帮助高效的根节点枚举 3.2 何时开始GC&#xff1a;安全点与安全区域如何选取安全点如何让程序进…

rocketmq-console可视化界面功能说明

rocketmq-console可视化界面功能说明 登录界面OPS(运维)Dashboard(驾驶舱)Cluster(集群)Topic(主题)Consumer(消费者)Producer(生产者)Message(消息)MessageTrace(消息轨迹) rocketmq-console是rocketmq的一款可视化工具&#xff0c;提供了mq的使用详情等功能。 本章针对于rock…

玫瑰千层烤饼:味蕾的芬芳盛宴

在美食的缤纷世界里&#xff0c;有一种独特的存在&#xff0c;它融合了玫瑰的芬芳与烤饼的酥脆&#xff0c;那便是令人陶醉的甘肃美食玫瑰千层烤饼。食家巷玫瑰千层烤饼&#xff0c;宛如一件精心雕琢的艺术品。每一层薄如纸张的面皮&#xff0c;都承载着制作者的细腻与用心。层…

【qt】TCP 服务端怎么收到信息?

上一节,我已经讲了,TCP的监听,是基于上一节的,不知道的可以看看. 当我们的TCP 服务器 有 客户端请求连接的时候,会发出一个信号newConnection(). 在TCP服务端与客户端的通信中,我们需要使用到套接字 QTcpSocket类. 套接字相当于是网络通信的接口,服务段和客户端都要通过它进行通…

Gitlab Fork Workflow(协作工作流)

Gitlab Fork WorkFlow&#xff08;协作工作流&#xff09; Fork WorkFlow用于团队间的协作开发。在开发过程中&#xff0c;我们都需要将最新修改的代码合并到代码库上&#xff0c;在代码合并之前&#xff0c;为了保证代码符合上传要求&#xff08;符合需求、代码规范等&#xf…

如何在应用运行时定期监控内存使用情况

如何在应用运行时定期监控内存使用情况 在 iOS 应用开发中&#xff0c;实时监控内存使用情况对于优化性能和排查内存泄漏等问题非常重要。本文将介绍如何在应用运行时定期监控内存使用情况&#xff0c;使用 Swift 编写代码并结合必要的工具和库。 1. 创建桥接头文件 首先&…