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.xdnf.cn/news/1474619.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【持续集成_03课_Jenkins生成Allure报告及Sonar静态扫描】

1、 一、构建之后的配置 1、安装allure插件 安装好之后&#xff0c;可以在这里搜到已经安装的 2、配置allure的allure-commandline 正常配置&#xff0c;是要么在工具里配置&#xff0c;要么在系统里配置 allure-commandline是在工具里进行配置 两种方式进行配置 1&#xff…

动手RAG: ocr调研

对于rag应用来说&#xff0c;文档是第一步&#xff0c;对于部分扫描件的文件来讲&#xff0c;主要就需要OCR. OCR tesseractppocrmmocr 还有诸如 chineseocr_litedarknet-ocrhttps://blog.csdn.net/CHYabc123456hh/article/details/107846268easyocr OCR包含几类&#x…

【Unity小技巧】Unity字典序列化

字典序列化 在 Unity 中&#xff0c;标准的 C# 字典&#xff08;Dictionary<TKey, TValue>&#xff09;是不能直接序列化的&#xff0c;因为 Unity 的序列化系统不支持非 Unity 序列化的集合类型。可以通过手写字典实现 效果&#xff1a; 实现步骤&#xff1a; 继承ISe…

基于AOP的数据字典实现:实现前端下拉框的可配置更新

作者&#xff1a;后端小肥肠 创作不易&#xff0c;未经允许严禁转载。 目录 1. 前言 2. 数据字典 2.1. 数据字典简介 2.2. 数据字典如何管理各模块的下拉框 3. 数据字典核心内容解读 3.1. 表结构 3.2. 核心代码 3.2.1. 根据实体类名称获取下属数据字典 3.2.2. 数据字…

HackTheBox----Editorial

Editorial 测试过程 1 信息收集 NMAP端口扫描 nmap -sC -sV 10.10.11.20服务器开启了 22、80 端口 80 端口测试 服务器只开启了 22 和 80 端口&#xff0c;先从 80 端口开始进行测试 echo "10.10.11.20 editorial.htb" | sudo tee -a /etc/hostspublish with us…

电源纹波相关

什么是纹波&#xff1f;什么是噪声&#xff1f; 这种叠加在直流稳定量上的交流分量就称为纹波。 纹波的危害 电源纹波能影响设备性能和稳定性 纹波会导致电器上产生谐波&#xff0c;降低电源的使用效率&#xff1b; 高频电源纹波可能会产生浪涌电压或电流&#xff0c;影响设…

WAWA鱼曲折的大学四年回忆录

声明&#xff1a;本文内容纯属个人主观臆断&#xff0c;如与事实不符&#xff0c;请参考事实 前言&#xff1a; 早想写一下大学四年的总结了&#xff0c;但总是感觉无从下手&#xff0c;不知道从哪里开始写&#xff0c;通过这篇文章主要想做一个记录&#xff0c;并从现在的认…

thingsboard v3.7 win编译相关问题记录

遇到的问题总结 node\yarn 相关版本问题 3.7 开始需要 JDK17 ui-ngx 模块 yarn 相关问题报错 报错信息 [INFO] Downloading https://github.com/yarnpkg/yarn/releases/download/v1.22.10/yarn-v1.22.10.tar.gz to D:\soft\maven\com\github\eirslett\yarn\1.22.10\yarn-1.2…

STM32基础篇:GPIO

GPIO简介 GPIO&#xff1a;即General Purpose Input/Output&#xff0c;通用目的输入/输出。就是一种片上外设&#xff08;内部模块&#xff09;。 对于STM32的芯片来说&#xff0c;周围有一圈引脚&#xff0c;有时需要对引脚进行读写&#xff08;读&#xff1a;从外部输入一…

SLF4J的介绍与使用(有logback和log4j2的具体实现案例)

目录 1.日志门面的介绍 常见的日志门面 &#xff1a; 常见的日志实现&#xff1a; 日志门面和日志实现的关系&#xff1a; 2.SLF4J 的介绍 业务场景&#xff08;问题&#xff09;&#xff1a; SLF4J的作用 SLF4J 的基本介绍 日志框架的绑定&#xff08;重点&#xff09…

线程安全的原因及解决方法

什么是线程安全问题 线程安全问题指的是在多线程编程环境中&#xff0c;由于多个线程共享数据或资源&#xff0c;并且这些线程对共享数据或资源的访问和操作没有正确地同步&#xff0c;导致数据的不一致、脏读、不可重复读、幻读等问题。线程安全问题的出现&#xff0c;通常是…

Mac 系统如何将搜狗输入法设置为默认输入法

Mac 系统默认将自带的ABC输入法作为默认输入法&#xff0c;很不方便中文输入&#xff0c;想设置搜狗输入法为默认输入法如何设置呢&#xff1f;具体步骤如下&#xff1a; 1、打开&#xff1a;系统设置——键盘——文字输入&#xff0c;点击设置 2、点击左下角的 3、选择 其他…

数学系C++(六七)

目录 * &指针与地址 void指针 指针可以等于&#xff1a; const 指向常量的指针 const int *px 常指针 int * const px 指向常量的常指针const 类型标识符 * const 指针名 指针加减&#xff1a; 指针恒等式 函数指针【待续】 指针型函数&#xff1a; 指向函数的…

52-5 内网代理2 - LCX端口转发(不推荐使用LCX)

环境搭建: 本地开3台虚拟机:kali(必须)、windows2012与2008 (可换成其他windows虚拟机) kali - 网络配置成桥接模式 windows2012 - 设置两个网卡,NAT与桥接模式 注意:windows2012要关闭防火墙,要不然其他主机ping不通 关闭防火墙后再开启远程桌面连接 windwos20…

拉曼光谱入门:3.拉曼光谱的特征参数与定量定性分析策略

1.特征参数 1.1 退偏振率 退偏振率&#xff08;p&#xff09;是一个衡量拉曼散射光偏振状态的参数&#xff0c;它描述了拉曼散射光的偏振方向与入射光偏振方向之间的关系。退偏振率定义为垂直偏振方向的拉曼散射强度与平行偏振方向的拉曼散射强度之比。退偏振率&#xff08;p&…

Hi6602 恒压恒流SSR电源方案

Hi6602是一款针对离线式反激电源设计的高性能PWM控制器。Hi6602内集成有通用的原边恒流控制技术&#xff0c;可支持断续模式和连续模式工作&#xff0c;适用于恒流输出的隔离型电源应用中。Hi6602内部具有高精度65kHz开关频率振荡器&#xff0c;且带有抖频功能可优化EMI性能。H…

【全面介绍下如何使用Zoom视频会议软件!】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

WEB自动化框架封装MySQL连接及sql断言教程

为了在Web自动化测试中连接MySQL数据库并进行SQL断言&#xff0c;您可以按照以下步骤&#xff1a; 安装MySQL Connector/Python驱动程序&#xff0c;并导入它。 使用Connector/Python创建一个连接对象&#xff0c;指定所需的主机名、用户名、密码和数据库名。 创建一个游标对…

系统级别的原生弹窗窗口

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>原生的弹出窗口dialog</title><style>…

相见恨晚的《新程序员》 AI 专辑

声明&#xff1a;本文并不什么“软文”&#xff0c;是我的真实感受分享。本人和《新程序员》无任何利益关系&#xff0c;读者购买专栏我不会获得任何分成。 一、前言 前不久有位朋友送我一本 CSDN 出品的 《新程序员 006&#xff1a;人工智能新十年》 的杂志。 说实话&#x…