Object Oriented Python 简明教程

Object Oriented Python - Quick Guide

Object Oriented Python - Introduction

编程语言不断涌现,不同的方法学也是如此。面向对象编程就是这样一种方法,在过去几年中变得非常流行。

本节讲述 Python 编程语言作为面向对象编程语言的特性。

Language Programming Classification Scheme

Python 可归类为面向对象编程方法。下图说明了各种编程语言的特性。观察 Python 中使其成为面向对象的特性。

Langauage Classes

Categories

Langauages

Programming Paradigm

Procedural

C、C ++、C#、Objective-C、Java、Go

Scripting

CoffeeScript、JavaScript、Python、Perl、Php、Ruby

Functional

Clojure, Eralang, Haskell, Scala

Compilation Class

Static

C、C++、C#、Objective-C、Java、Go、Haskell、Scala

Dynamic

CoffeeScript、JavaScript、Python、Perl、Php、Ruby、Clojure、Erlang

Type Class

Strong

C#、Java、Go、Python、Ruby、Clojure、Erlang、Haskell、Scala

Weak

C、C ++、C#、Objective-C、CoffeeScript、JavaScript、Perl、Php

Memory Class

Managed

Others

Unmanaged

What is Object Oriented Programming?

Object Oriented 意味着面向对象。换句话说,这就是对于对对象建模来说在功能上的方向。这是通过描述一组交互对象及其数据和行为对复杂系统建模时所用的众多技术之一。

Python,一种面向对象编程(OOP),是专注于使用对象和类来进行设计和构建应用程序的编程方法。面向对象编程(OOP)的主要支柱是 Inheritance, Polymorphism, Abstraction,Encapsulation

面向对象分析(OOA)是对问题、系统或任务进行检验并识别其对象和交互的过程。

Why to Choose Object Oriented Programming?

Python是在面向对象方法的基础上设计的。OOP具有以下优势-

  1. 提供清晰的程序结构,便于映射现实世界问题及其解决方案。

  2. 方便维护和修改现有代码。

  3. 增强程序模块化,因为每个对象独立存在,并且可以轻松添加新特性,而不会干扰现有特性。

  4. 为代码库提供了良好的框架,程序员可以轻松地对提供的组件进行改编和修改。

  5. Imparts code reusability

Procedural vs. Object Oriented Programming

基于过程的编程源于结构化编程,基于 functions/procedure/routines 的概念。在面向过程的编程中,访问和更改数据非常容易。另一方面,面向对象编程(OOP)允许将问题分解为若干称为 objects 的单元,然后围绕这些对象构建数据和函数。它更强调数据而不是过程或函数。同样,在 OOP 中,数据是隐藏的,外部过程无法访问。

下图中的表格显示了 POP 和 OOP 方法之间的主要区别。

面向过程编程(POP)和面向对象编程(OOP)之间的差异。

Procedural Oriented Programming

ObjectOriented Programming

Based On

在 Pop 中,整个焦点都集中在数据和函数上

Oops 基于一个现实世界的场景。整个程序被划分为称为对象的较小部分

Reusability

Limited Code reuse

Code reuse

Approach

Top down Approach

Object focused Design

Access specifiers

Not any

Public, private and Protected

Data movement

数据可以自由地在系统中的函数与函数之间移动

在 Oops 中,数据可相互移动并通过成员函数进行通信

Data Access

在 pop 中,大多数函数使用全局数据进行共享,这些数据可以从系统中的函数到函数自由访问

在 Oops 中,数据不能在方法与方法之间自由移动,可以将其保存在公共或私有部分,因此我们可以控制对数据的访问

Data Hiding

在 pop 中,有特定的方式来隐藏数据,因此安全性较低

提供数据隐藏,因此安全性更高

Overloading

Not possible

Functions and Operator Overloading

Example-Languages

C, VB, Fortran, Pascal

C++, Python, Java, C#

Abstraction

在过程级别使用抽象

在类和对象级别使用抽象

Principles of Object Oriented Programming

面向对象编程 (OOP) 基于 objects 而不是操作以及 data 而不是逻辑的概念。为了让编程语言面向对象,它应当具备一种机制来实现使用类和对象以及实现和使用基本面向对象原则和概念(即继承、抽象、封装和多态性)。

oops

让我们简要了解面向对象编程的各个支柱 -

Encapsulation

此属性隐藏了不必要详细信息,并让对程序结构的管理变得更轻松。每个对象实现和状态都隐藏在定义明确的界限之后,并提供了一个用于使用它们的清晰而简单的接口。实现此操作的一种方式是使数据私有。

Inheritance

继承也称为泛化,它允许我们捕获类和对象之间的层级关系。例如,“水果”就是“橙子”的一项概括。继承从代码重用角度来看非常有用。

Abstraction

此属性允许我们隐藏详细信息并仅公开某个概念或对象的关键特征。例如,驾驶滑板车的人知道按喇叭会发出声音,但他不知道按喇叭实际上如何产生声音。

Polymorphism

多态性指多种形式。也就是说,一项事物或操作会以不同的形式或方式存在。构造函数类重载就是一个很好的多态性例子。

Object-Oriented Python

Python 编程的核心是 objectOOP ,但您不必将自己限制在通过将代码整理成类来使用 OOP。OOP 增强了 Python 的整体设计理念,并支持以整洁有效的方式编程。OOP 还支持编写更大型且更复杂的程序。

Modules vs. Classes and Objects

Modules are like “Dictionaries”

在使用模块时,注意以下要点 -

  1. Python 模块是一个用于封装可重用代码的程序包。

  2. Modules 驻留在带有 init.py 文件的文件夹中。

  3. Modules 包含函数和类。

  4. 使用 import 关键字导入 modules。

回想一下,字典是一个 key-value 对。这意味着,如果您有一个键为 EmployeID 的字典,并且您想要检索它,那么您将必须使用下列代码行 −

employee = {“EmployeID”: “Employee Unique Identity!”}
print (employee [‘EmployeID])

您将需要按照以下过程处理 modules −

  1. 一个 module 是一个 Python 文件,其中包含一些函数或变量。

  2. 导入您需要的文件。

  3. 现在,您可以使用 “.” (dot) 运算符访问该 module 中的函数或变量。

考虑一个名为 employee.py 的 module,其中有一个名为 employee 的函数。该函数的代码如下所示 −

# this goes in employee.py
def EmployeID():
   print (“Employee Unique Identity!”)

现在导入 module,然后访问函数 EmployeID

import employee
employee. EmployeID()

您可以像所示的那样,在其中插入一个名为 Age 的变量 −

def EmployeID():
   print (“Employee Unique Identity!”)
# just a variable
Age = “Employee age is **”

现在,请以下面的方式访问该变量 −

import employee
employee.EmployeID()
print(employee.Age)

现在,让我们将它与字典进行比较 −

Employee[‘EmployeID’] # get EmployeID from employee
Employee.employeID() # get employeID from the module
Employee.Age # get access to variable

请注意,Python 中有一个通用的模式 −

  1. 采用 key = value 样式容器

  2. 按键名从中取出某些内容

当将 module 与字典进行比较时,两者相似,但有以下几点除外 −

  1. 对于 dictionary ,键是字符串,语法为 [键]。

  2. 对于 module ,键是标识符,语法为 . 键。

Classes are like Modules

模块是可存储 Python 代码的专门词典,你可以用“.”操作符访问它。类是一种将函数和数据分组放置在容器中以便你可以用“.”操作符访问它们的方式。

如果你必须创建一个类似于员工模块的类,可以使用以下代码创建:

class employee(object):
   def __init__(self):
      self. Age = “Employee Age is ##”
   def EmployeID(self):
      print (“This is just employee unique identity”)

Note - 类比模块更受青睐,因为你可以原封不动地重复使用它们,而且不会造成太多干扰。对于模块,你只能将它们与整个程序合二为一。

Objects are like Mini-imports

类类似于 mini-module ,你可以用 instantiate 中提到的概念以类似于导入类的方式导入类。注意,当你实例化一个类时,你可以获得 object

你可以实例化一个对象,类似于像调用函数那样调用一个类,如下所示:

this_obj = employee() # Instantiatethis_obj.EmployeID() # get EmployeId from the class
print(this_obj.Age) # get variable Age

你可以使用以下三种方式中的任何一种:

# dictionary style
Employee[‘EmployeID’]
# module style
Employee.EmployeID()
Print(employee.Age)
# Class style
this_obj = employee()
this_obj.employeID()
Print(this_obj.Age)

Object Oriented Python - Environment Setup

本章将详细解释如何在您的本地计算机上设置 Python 环境。

Prerequisites and Toolkits

在继续学习 Python 之前,我们建议您检查是否满足以下先决条件−

  1. 已在您的计算机上安装了最新版本的 Python

  2. 已安装 IDE 或文本编辑器

  3. 您对用 Python 编写调试熟悉,即您可以在 Python 中执行以下操作−能够编写并运行 Python 程序。调试程序并诊断错误。使用基本数据类型。编写 for 循环、 while 循环和 if 语句编码 functions

如果您没有任何编程语言经验,您可以在

Installing Python

以下步骤详细介绍了如何在本地计算机上安装 Python−

Step 1 − 前往官方 Python 网站 https://www.python.org/ ,单击 Downloads 菜单,然后选择最新或任何稳定的版本。

python website

Step 2 − 保存您正在下载的 Python 安装程序 exe 文件,下载完成后将其打开。单击 Run ,并默认选择 Next 选项,然后完成安装。

python installer

Step 3 − 安装后,您现在应该会看到如下图所示的 Python 菜单。通过选择 IDLE(Python GUI)来启动程序。

idle

这将启动 Python shell。键入简单命令来检查安装。

python shell

Choosing an IDE

集成开发环境是一个面向软件开发的文本编辑器。您必须安装一个 IDE 来控制您的编程流程,并在处理 Python 时对项目分组。以下是网上提供的一些 IDE。您可以根据自己的需要选择一个。

  1. Pycharm IDE

  2. Komodo IDE

  3. Eric Python IDE

Note − Eclipse IDE 主要用于 Java,但它有一个 Python 插件。

Pycharm

pycharm

Pycharm 跨平台 IDE 是目前最流行的 IDE 之一。它通过代码完成、项目和代码导航、集成单元测试、版本控制集成、调试等提供编码辅助和分析

Languages Supported − Python、HTML、CSS、JavaScript、Coffee Script、TypeScript、Cython、AngularJS、Node.js、模板语言。

Screenshot

screenshot

Why to Choose?

PyCharm 为其用户提供以下功能和好处−

  1. 与 Windows、Linux 和 Mac OS 兼容的跨平台 IDE

  2. 包括 Django IDE,以及 CSS 和 JavaScript 支持

  3. 包括数千个插件、集成终端和版本控制

  4. 与 Git、SVN 和 Mercurial 集成

  5. 提供 Python 的智能编辑工具

  6. 与 Virtualenv、Docker 和 Vagrant 轻松集成

  7. 简单的导航和搜索功能

  8. Code analysis and refactoring

  9. Configurable injections

  10. 支持大量的 Python 库

  11. 包含模板和 JavaScript 调试器

  12. Includes Python/Django debuggers

  13. 适用于 Google App Engine、其他框架和库。

  14. 具有可自定义的 UI,提供 VIM 仿真

Komodo IDE

komode

这是一款多语言 IDE,支持 100 多种语言,并且基本适用于动态语言(如 Python、PHP 和 Ruby)。这是一款商业 IDE,可免费试用 21 天,并提供完整功能。ActiveState 是管理 Komodo IDE 开发的软件公司。它还提供 Komodo 的精简版本,称为 Komodo Edit,可用于简单的编程任务。

这款 IDE 包含各种功能,从最基本到高级级别。如果您是学生或自由职业者,则可以购买价格几乎是实际价格一半的产品。但是,对于受认可机构和大学的老师和教授来说,它是完全免费的。

它具有进行 Web 和移动开发所需的所有功能,包括对所有语言和框架的支持。

Komodo Edit(免费版本)和 Komodo IDE(付费版本)的下载链接如下所示 −

Komodo Edit (free)

Komodo IDE (paid)

Screenshot

komodo ide

Why to Choose?

  1. 功能强大的 IDE,支持 Perl、PHP、Python、Ruby 等多种语言。

  2. Cross-Platform IDE.

它包括基本功能,如集成调试器支持、自动完成、文档对象模型 (DOM) 查看器、代码浏览器、交互式 shell、断点配置、代码分析、集成单元测试。简而言之,它是一款专业 IDE,具有大量提高生产力的功能。

Eric Python IDE

eric

这是一款用于 Python 和 Ruby 的开源 IDE。Eric 是一个全功能编辑器和 IDE,用 Python 编写。它基于跨平台 Qt GUI 工具包,集成了高度灵活的 Scintilla 编辑器控件。这款 IDE 非常可配置,用户可以选择使用哪些功能,以及不使用哪些功能。您可以从以下链接下载 Eric IDE:

Why to Choose

  1. Great indentation, error highlighting.

  2. Code assistance

  3. Code completion

  4. Code cleanup with PyLint

  5. Quick search

  6. Integrated Python debugger.

Screenshot

why to choose

Choosing a Text Editor

您可能并不总需要 IDE。例如,学习使用 Python 或 Arduino 进行编码的任务,或者在 shell 脚本中处理快速脚本以帮助您自动执行某些任务时,一款简单且轻量级的以代码为中心的文本编辑器就足够了。此外,许多文本编辑器提供诸如语法高亮显示和程序内脚本执行等功能,类似于 IDE。以下列出了一些文本编辑器 −

  1. Atom

  2. Sublime Text

  3. Notepad++

Atom Text Editor

atom

Atom 是一款由 GitHub 团队开发的可破解文本编辑器。这是一款免费且开放源代码的文本和代码编辑器,这意味着您可以查看所有代码、针对您自己的用途进行修改,甚至还可以提供改进建议。这是一款适用于 macOS、Linux 和 Microsoft Windows 的跨平台文本编辑器,支持以 Node.js 编写的外挂程序和嵌入式 Git 控制。

Screenshot

download link

Languages Supported

C/C++、C#、CSS、CoffeeScript、HTML、JavaScript、Java、JSON、Julia、Objective-C、PHP、Perl、Python、Ruby on Rails、Ruby、Shell 脚本、Scala、SQL、XML、YAML 等多种语言。

Sublime Text Editor

sublime

Sublime Text 是一个专有软件,它提供了免费试用版,让您在购买前进行测试。根据 stackoverflow.com 的说法,它是第四大最受欢迎的开发环境。

它提供的一些优势包括其令人难以置信的速度、易用性和社区支持。它还支持多种编程语言和标记语言,用户可以通过插件添加函数,这些插件通常由社区创建并在自由软件许可下维护。

Screenshot

freesoftware licenses

Language supported

  1. Python, Ruby, JavaScript etc.

Why to Choose?

  1. 自定义键绑定、菜单、片段、宏、补全等。

  2. Auto completion feature

  3. 使用片段、字段标记和占位符,使用 Sublime Text 代码片段快速插入文本和代码

  4. Opens Quickly

  5. 对 Mac、Linux 和 Windows 提供跨平台支持。

  6. 将光标跳转到您希望去的位置

  7. 选择多行、单词和列

Notepad ++

notepad

这是一款免费源代码编辑器,取代记事本,支持多种语言,从汇编语言到 XML,包括 Python。在 MS Windows 环境中运行,其使用受 GPL 许可约束。除语法高亮显示外,Notepad++ 还拥有对编码人员特别有用的某些功能。

Screenshot

notepad plusplus

Key Features

  1. 语法高亮显示和语法折叠

  2. PCRE(Perl 兼容正则表达式)搜索/替换

  3. Entirely customizable GUI

  4. SAuto completion

  5. Tabbed editing

  6. Multi-View

  7. Multi-Language environment

  8. Launchable with different arguments

Language Supported

  1. 几乎所有语言(60 多种语言),如 Python、C、C++、C#、Java 等。

Object Oriented Python - Data Structures

从语法角度来看,Python 数据结构非常直观,它们提供大量操作选择。您需要根据数据的内容、是否需要修改数据、数据是否固定以及需要什么访问类型(例如,开始/结束/随机等)来选择 Python 数据结构。

Lists

在 Python 中,列表代表最通用的数据结构类型。列表是一个容器,它在方括号中保存逗号分隔的值(项或元素)。当我们需要使用多个相关值时,列表会非常有用。由于列表将数据保存在一起,我们可以一次对多个值执行相同的方法和操作。列表索引从零开始,与字符串不同,列表是可变的。

Data Structure - List

>>>
>>> # Any Empty List
>>> empty_list = []
>>>
>>> # A list of String
>>> str_list = ['Life', 'Is', 'Beautiful']
>>> # A list of Integers
>>> int_list = [1, 4, 5, 9, 18]
>>>
>>> #Mixed items list
>>> mixed_list = ['This', 9, 'is', 18, 45.9, 'a', 54, 'mixed', 99, 'list']
>>> # To print the list
>>>
>>> print(empty_list)
[]
>>> print(str_list)
['Life', 'Is', 'Beautiful']
>>> print(type(str_list))
<class 'list'>
>>> print(int_list)
[1, 4, 5, 9, 18]
>>> print(mixed_list)
['This', 9, 'is', 18, 45.9, 'a', 54, 'mixed', 99, 'list']

Accessing Items in Python List

列表的每个项都分配了一个数字,即该数字的索引或位置。索引始终从零开始,第二个索引为一,依此类推。要访问列表中的项,我们可以在方括号内使用这些索引号。例如,观察以下代码:

>>> mixed_list = ['This', 9, 'is', 18, 45.9, 'a', 54, 'mixed', 99, 'list']
>>>
>>> # To access the First Item of the list
>>> mixed_list[0]
'This'
>>> # To access the 4th item
>>> mixed_list[3]
18
>>> # To access the last item of the list
>>> mixed_list[-1]
'list'

Empty Objects

空对象是最简单、最基本的 Python 内置类型。我们已经多次在不知不觉中使用它们,并且已将它们扩展到我们创建的每个类。编写空类的主要目的是暂时阻止某些内容,并在稍后对其进行扩展并添加行为。

向类添加行为意味着用一个对象替换一个数据结构,并更改对它的所有引用。所以在创建任何内容之前,检查数据是否伪装成一个对象非常重要。观察以下代码以增强理解:

>>> #Empty objects
>>>
>>> obj = object()
>>> obj.x = 9
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
obj.x = 9
AttributeError: 'object' object has no attribute 'x'

因此,从上面我们可以看出,不可能对直接实例化的对象设置任何属性。当 Python 允许一个对象拥有任意属性时,它会占用一定数量的系统内存来跟踪每个对象具有的属性,以便同时存储属性名称和属性值。即使没有存储任何属性,也会为潜在的新属性分配一定数量的内存。

所以,Python 默认情况下禁用对象和其他几个内置对象的任意属性。

>>> # Empty Objects
>>>
>>> class EmpObject:
    pass
>>> obj = EmpObject()
>>> obj.x = 'Hello, World!'
>>> obj.x
'Hello, World!'

因此,如果我们要将属性分组在一起,我们可以将它们存储在一个空对象中,如上所示的代码中。但是,并不总是建议使用此方法。请记住,只有当您想要同时指定数据和行为时,才应该使用类和对象。

Tuples

元组与列表类似,可存储元素。但是,它们是不可变的,所以我们无法添加、删除或替换对象。元组提供的不可变性的主要好处是我们可以将其用作字典的键,或在对象需要哈希值的其他位置。

元组用于存储数据,而不是行为。如果您需要行为来操作元组,则需要将元组传递给执行操作的函数(或另一个对象上的方法)。

由于元组可以作为字典键,因此存储的值彼此不同。我们可以通过用逗号分隔值来创建元组。元组用括号括住,但不是强制的。以下代码显示了两个相同的赋值。

>>> stock1 = 'MSFT', 95.00, 97.45, 92.45
>>> stock2 = ('MSFT', 95.00, 97.45, 92.45)
>>> type (stock1)
<class 'tuple'>
>>> type(stock2)
<class 'tuple'>
>>> stock1 == stock2
True
>>>

Defining a Tuple

元组与列表非常相似,除了整套元素用括号括住而不是用方括号括住。

就像切片列表时,你会得到一个新列表,切片元组时,你会得到一个新元组。

>>> tupl = ('Tuple','is', 'an','IMMUTABLE', 'list')
>>> tupl
('Tuple', 'is', 'an', 'IMMUTABLE', 'list')
>>> tupl[0]
'Tuple'
>>> tupl[-1]
'list'
>>> tupl[1:3]
('is', 'an')

Python Tuple Methods

以下代码显示了 Python 元组中的方法:

>>> tupl
('Tuple', 'is', 'an', 'IMMUTABLE', 'list')
>>> tupl.append('new')
Traceback (most recent call last):
   File "<pyshell#148>", line 1, in <module>
      tupl.append('new')
AttributeError: 'tuple' object has no attribute 'append'
>>> tupl.remove('is')
Traceback (most recent call last):
   File "<pyshell#149>", line 1, in <module>
      tupl.remove('is')
AttributeError: 'tuple' object has no attribute 'remove'
>>> tupl.index('list')
4
>>> tupl.index('new')
Traceback (most recent call last):
   File "<pyshell#151>", line 1, in <module>
      tupl.index('new')
ValueError: tuple.index(x): x not in tuple
>>> "is" in tupl
True
>>> tupl.count('is')
1

从上面显示的代码中,我们可以理解元组是不可变的,因此:

  1. cannot 添加元素到元组。

  2. cannot 追加或扩展一个方法。

  3. cannot 从元组中删除元素。

  4. 元组有 no 删除或弹出方法。

  5. 计数和索引是元组中的可用方法。

Dictionary

字典是 Python 的内置数据类型之一,它定义了键和值之间的一对一关系。

Defining Dictionaries

观察以下代码以了解有关定义字典:

>>> # empty dictionary
>>> my_dict = {}
>>>
>>> # dictionary with integer keys
>>> my_dict = { 1:'msft', 2: 'IT'}
>>>
>>> # dictionary with mixed keys
>>> my_dict = {'name': 'Aarav', 1: [ 2, 4, 10]}
>>>
>>> # using built-in function dict()
>>> my_dict = dict({1:'msft', 2:'IT'})
>>>
>>> # From sequence having each item as a pair
>>> my_dict = dict([(1,'msft'), (2,'IT')])
>>>
>>> # Accessing elements of a dictionary
>>> my_dict[1]
'msft'
>>> my_dict[2]
'IT'
>>> my_dict['IT']
Traceback (most recent call last):
   File "<pyshell#177>", line 1, in <module>
   my_dict['IT']
KeyError: 'IT'
>>>

从上面的代码中我们可以观察到:

  1. 首先,我们创建一个包含两个元素的字典,并将其分配给变量 my_dict 。每个元素都是一个键值对,整套元素用大括号括住。

  2. 数字 1 是键, msft 是它的值。类似地, 2 是键, IT 是它的值。

  3. 您可以按键获取值,但不能反过来。因此,当我们尝试 my_dict[‘IT’] 时,它会引发一个异常,因为 IT 不是一个键。

Modifying Dictionaries

观察以下代码以了解有关修改字典:

>>> # Modifying a Dictionary
>>>
>>> my_dict
{1: 'msft', 2: 'IT'}
>>> my_dict[2] = 'Software'
>>> my_dict
{1: 'msft', 2: 'Software'}
>>>
>>> my_dict[3] = 'Microsoft Technologies'
>>> my_dict
{1: 'msft', 2: 'Software', 3: 'Microsoft Technologies'}

从上面的代码中,我们能观察到 -

  1. 在一个字典中,你不能有重复的键。更改现有键的值将删除旧值。

  2. 你可以随时添加新的键值对。

  3. 字典不包含元素之间的顺序概念。它们是简单的无序集合。

Mixing Data types in a Dictionary

观察以下代码来了解在字典中混合数据类型 -

>>> # Mixing Data Types in a Dictionary
>>>
>>> my_dict
{1: 'msft', 2: 'Software', 3: 'Microsoft Technologies'}
>>> my_dict[4] = 'Operating System'
>>> my_dict
{1: 'msft', 2: 'Software', 3: 'Microsoft Technologies', 4: 'Operating System'}
>>> my_dict['Bill Gates'] = 'Owner'
>>> my_dict
{1: 'msft', 2: 'Software', 3: 'Microsoft Technologies', 4: 'Operating System',
'Bill Gates': 'Owner'}

从上面的代码中,我们能观察到 -

  1. 不仅仅是字符串,字典值可以是任何数据类型,包括字符串、整数,甚至字典本身。

  2. 与字典值不同,字典键受到更多限制,但可以是任何类型,如字符串、整数或任何其他类型。

Deleting Items from Dictionaries

观察以下代码来了解如何从字典中删除项 -

>>> # Deleting Items from a Dictionary
>>>
>>> my_dict
{1: 'msft', 2: 'Software', 3: 'Microsoft Technologies', 4: 'Operating System',
'Bill Gates': 'Owner'}
>>>
>>> del my_dict['Bill Gates']
>>> my_dict
{1: 'msft', 2: 'Software', 3: 'Microsoft Technologies', 4: 'Operating System'}
>>>
>>> my_dict.clear()
>>> my_dict
{}

从上面的代码中,我们能观察到 -

  1. del - 允许你按键从字典中删除单个项。

  2. clear - 从字典中删除所有项。

Sets

集合是一种无序集合,没有重复的元素。尽管单个项不可变,但集合本身是可变的,即我们可以向集合中添加或删除元素/项。我们可以对集合执行并集、交集等数学运算。

尽管一般集合可以使用树来实现,但 Python 中的集合可以使用哈希表来实现。这允许它使用一种高度优化的方法来检查特定元素是否包含在集合中。

Creating a set

集合是通过将所有项(元素)用逗号分隔或使用内置函数 set() 放置在花括号 {} 内创建的。观察以下代码行 -

>>> #set of integers
>>> my_set = {1,2,4,8}
>>> print(my_set)
{8, 1, 2, 4}
>>>
>>> #set of mixed datatypes
>>> my_set = {1.0, "Hello World!", (2, 4, 6)}
>>> print(my_set)
{1.0, (2, 4, 6), 'Hello World!'}
>>>

Methods for Sets

观察以下代码来了解集合的方法 -

>>> >>> #METHODS FOR SETS
>>>
>>> #add(x) Method
>>> topics = {'Python', 'Java', 'C#'}
>>> topics.add('C++')
>>> topics
{'C#', 'C++', 'Java', 'Python'}
>>>
>>> #union(s) Method, returns a union of two set.
>>> topics
{'C#', 'C++', 'Java', 'Python'}
>>> team = {'Developer', 'Content Writer', 'Editor','Tester'}
>>> group = topics.union(team)
>>> group
{'Tester', 'C#', 'Python', 'Editor', 'Developer', 'C++', 'Java', 'Content
Writer'}
>>> # intersets(s) method, returns an intersection of two sets
>>> inters = topics.intersection(team)
>>> inters
set()
>>>
>>> # difference(s) Method, returns a set containing all the elements of
invoking set but not of the second set.
>>>
>>> safe = topics.difference(team)
>>> safe
{'Python', 'C++', 'Java', 'C#'}
>>>
>>> diff = topics.difference(group)
>>> diff
set()
>>> #clear() Method, Empties the whole set.
>>> group.clear()
>>> group
set()
>>>

Operators for Sets

观察以下代码来了解集合的运算符 -

>>> # PYTHON SET OPERATIONS
>>>
>>> #Creating two sets
>>> set1 = set()
>>> set2 = set()
>>>
>>> # Adding elements to set
>>> for i in range(1,5):
   set1.add(i)
>>> for j in range(4,9):
   set2.add(j)
>>> set1
{1, 2, 3, 4}
>>> set2
{4, 5, 6, 7, 8}
>>>
>>> #Union of set1 and set2
>>> set3 = set1 | set2 # same as set1.union(set2)
>>> print('Union of set1 & set2: set3 = ', set3)
Union of set1 & set2: set3 = {1, 2, 3, 4, 5, 6, 7, 8}
>>>
>>> #Intersection of set1 & set2
>>> set4 = set1 & set2 # same as set1.intersection(set2)
>>> print('Intersection of set1 and set2: set4 = ', set4)
Intersection of set1 and set2: set4 = {4}
>>>
>>> # Checking relation between set3 and set4
>>> if set3 > set4: # set3.issuperset(set4)
   print('Set3 is superset of set4')
elif set3 < set4: #set3.issubset(set4)
   print('Set3 is subset of set4')
else: #set3 == set4
   print('Set 3 is same as set4')
Set3 is superset of set4
>>>
>>> # Difference between set3 and set4
>>> set5 = set3 - set4
>>> print('Elements in set3 and not in set4: set5 = ', set5)
Elements in set3 and not in set4: set5 = {1, 2, 3, 5, 6, 7, 8}
>>>
>>> # Check if set4 and set5 are disjoint sets
>>> if set4.isdisjoint(set5):
   print('Set4 and set5 have nothing in common\n')
Set4 and set5 have nothing in common
>>> # Removing all the values of set5
>>> set5.clear()
>>> set5 set()

Object Oriented Python - Building Blocks

在本章中,我们将详细讨论面向对象术语和编程概念。类只是实例的一个工厂。这个工厂包含描述如何创建实例的蓝图。实例或对象是根据类构造的。在大多数情况下,我们可以拥有一个类的多个实例。每个实例都有一组属性,这些属性在类中定义,因此特定类的每个实例都应具有相同的属性。

Class Bundles : Behavior and State

一个类可以让你将一个对象的的行为和状态捆绑在一起。观察以下图表以更好地理解 -

bundles

在讨论类捆绑时,以下几点值得注意 -

  1. 单词 behavior 等同于 function - 它是一段执行某些操作(或实现某一行为)的代码

  2. 单词 statevariables 相同——它是类内存储值的一个地方。

  3. 当我们一起断言类行为和状态时,这意味着类会封装函数和变量。

Classes have methods and attributes

在 Python 中,创建方法定义类行为。方法这个词是面向对象编程中给类内部定义的函数的一个名称。总结一下:

  1. Class functions ——是 methods 的同义词

  2. Class variables ——是 name attributes. 的同义词

  3. Class ——给具有确切行为的实例创建一个蓝图。

  4. Object ——类的实例之一,执行类中定义的功能。

  5. Type ——指示该实例所属的类

  6. Attribute ——任何对象值:object.attribute

  7. Method ——类中定义的“可调用属性”

观察以下代码段以作示例——

var = “Hello, John”
print( type (var)) # < type ‘str’> or <class 'str'>
print(var.upper()) # upper() method is called, HELLO, JOHN

Creation and Instantiation

以下代码展示了如何创建我们的第一个类,然后创建它的实例。

class MyClass(object):
   pass
# Create first instance of MyClass
this_obj = MyClass()
print(this_obj)
# Another instance of MyClass
that_obj = MyClass()
print (that_obj)

在此,我们创建了一个称为 MyClass 的类,该类不做任何任务。 MyClass 类中的参数 object 涉及类继承,将在后面的章节中讨论。上面的代码中的 pass 表明,该块是空的,也就是一个空的类定义。

让我们创建一个类 MyClass() 的实例 this_obj 并对其进行打印,如以下所示:

<__main__.MyClass object at 0x03B08E10>
<__main__.MyClass object at 0x0369D390>

在此,我们创建了 MyClass. 的一个实例。十六进制代码是指对象存储的地址。另一个实例指向另一个地址。

现在让我们在类 MyClass() 中定义一个变量,并从该类的实例中获取变量,如下面的代码所示:

class MyClass(object):
   var = 9

# Create first instance of MyClass
this_obj = MyClass()
print(this_obj.var)

# Another instance of MyClass

that_obj = MyClass()
print (that_obj.var)

Output

执行上述代码时,可以看到以下输出:

9
9

由于实例知道自己是通过哪个类实例化,因此当从实例请求属性时,实例会查找属性和类。这称为 attribute lookup.

Instance Methods

类中定义的函数称为 method. 实例方法需要一个实例才能调用它,并且不需要装饰器。在创建实例方法时,第一个参数始终为 self. 虽然我们可以用任何其他名称调用它(self),但建议使用 self,因为它是一个命名约定。

class MyClass(object):
   var = 9
   def firstM(self):
      print("hello, World")
obj = MyClass()
print(obj.var)
obj.firstM()

Output

执行上述代码时,可以看到以下输出:

9
hello, World

请注意,在上面的程序中,我们定义了一个方法,其中 self 为参数。但我们无法调用该方法,因为我们没有向其声明任何参数。

class MyClass(object):
   def firstM(self):
      print("hello, World")
      print(self)
obj = MyClass()
obj.firstM()
print(obj)

Output

执行上述代码时,可以看到以下输出:

hello, World
<__main__.MyClass object at 0x036A8E10>
<__main__.MyClass object at 0x036A8E10>

Encapsulation

封装是 OOP 的基本原则之一。OOP 让我们能够隐藏对象的内部工作原理的复杂性,在以下方面对开发人员有利 −

  1. 简化并使之易于理解,无需了解内部即可使用对象。

  2. 可以轻松管理任何更改。

面向对象编程严重依赖于封装。术语“封装”和“抽象”(也称为数据隐藏)通常被用作同义词。它们几乎是同义词,因为抽象是通过封装实现的。

封装为我们提供了限制对某些对象组件的访问权限的机制,这意味着对象内部表示不能从对象定义外部看到。通常通过特殊方法 GettersSetters. 来访问这些数据

这些数据存储在实例属性中,可以从类外的任何地方进行操作。为了保护它,只应使用实例方法访问该数据。禁止直接访问。

class MyClass(object):
   def setAge(self, num):
      self.age = num

   def getAge(self):
      return self.age

zack = MyClass()
zack.setAge(45)
print(zack.getAge())

zack.setAge("Fourty Five")
print(zack.getAge())

Output

执行上述代码时,可以看到以下输出:

45
Fourty Five

应该使用异常处理结构仅在数据正确有效时存储数据。如上所见,对于 setAge() 方法,没有对用户输入的限制。它可以是字符串、数字或列表。因此,我们需要检查上面的代码以确保存储的正确性。

class MyClass(object):
   def setAge(self, num):
      self.age = num

   def getAge(self):
      return self.age
zack = MyClass()
zack.setAge(45)
print(zack.getAge())
zack.setAge("Fourty Five")
print(zack.getAge())

Init Constructor

方法 *init* 会在类对象实例化后立即隐式调用。这将初始化对象。

x = MyClass()

上面显示的这一行代码将创建一个新实例,并将该对象分配给局部变量 x。

实例化操作,即 calling a class object ,创建一个空对象。许多类希望使用对象创建一个实例,该实例定制为特定的初始状态。因此,类可以定义一个名为 “ init ()“ 的特殊方法,如下所示 −

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

Python 在实例化期间调用 init ,定义了一个当类实例化时应该出现的附加属性,该属性可以设置该对象的某些起始值或在实例化时运行所需例程。因此,在此示例中,可以通过以下方法获取一个新的已初始化实例 −

x = MyClass()

方法 init () 可以具有一个或多个参数,来获得更大的灵活性。init 表示初始化,因为它初始化实例的属性。它被称为类的构造器。

class myclass(object):
   def __init__(self,aaa, bbb):
      self.a = aaa
      self.b = bbb

x = myclass(4.5, 3)
print(x.a, x.b)

Output

4.5 3

Class Attributes

类中定义的属性称为“类属性”,而函数中定义的属性称为“实例属性”。在定义时,这些属性没有前缀 self,因为它们是类的属性,而不是特定实例的属性。

类属性可以通过类本身( className.attributeName)以及类的实例(inst.attributeName)来访问。因此,实例既可以访问实例属性,也可以访问类属性。

>>> class myclass():
   age = 21
>>> myclass.age
21
>>> x = myclass()
>>> x.age
21
>>>

类属性可以在实例中被覆盖,虽然这并不是一个打破封装的好方法。

Python 中有一个用于查找属性的路径。第一个是在类中定义的方法,然后是其上方的类。

>>> class myclass(object):
   classy = 'class value'
>>> dd = myclass()
>>> print (dd.classy) # This should return the string 'class value'
class value
>>>
>>> dd.classy = "Instance Value"
>>> print(dd.classy) # Return the string "Instance Value"
Instance Value
>>>
>>> # This will delete the value set for 'dd.classy' in the instance.
>>> del dd.classy
>>> >>> # Since the overriding attribute was deleted, this will print 'class
value'.

>>> print(dd.classy)
class value
>>>

我们在实例 dd 中覆盖“classy”类属性。覆盖时,Python 解释器会读取覆盖的值。但是一旦新值被“del”删除,覆盖的值便不再存在于该实例中,因此查找将向上一个级别并从类中获取它。

Working with Class and Instance Data

在本节中,让我们了解类数据与实例数据的关系。我们可以将数据存储在类中或实例中。在设计类时,我们需要决定哪些数据属于实例,哪些数据应该存储在总体类中。

实例可以访问类数据。如果我们创建多个实例,那么这些实例既可以访问它们各自的属性值,也可以访问总体类数据。

因此,类数据是所有实例共享的数据。观察下面给出的代码以更好地理解−

class InstanceCounter(object):
   count = 0 # class attribute, will be accessible to all instances
   def __init__(self, val):
      self.val = val
      InstanceCounter.count +=1 # Increment the value of class attribute, accessible through class name
# In above line, class ('InstanceCounter') act as an object
   def set_val(self, newval):
      self.val = newval

   def get_val(self):
      return self.val

   def get_count(self):
      return InstanceCounter.count
a = InstanceCounter(9)
b = InstanceCounter(18)
c = InstanceCounter(27)

for obj in (a, b, c):
   print ('val of obj: %s' %(obj.get_val())) # Initialized value ( 9, 18, 27)
   print ('count: %s' %(obj.get_count())) # always 3

Output

val of obj: 9
count: 3
val of obj: 18
count: 3
val of obj: 27
count: 3

简而言之,类属性对于类的所有实例都是相同的,而实例属性对于每个实例都是特定的。对于两个不同的实例,我们将有两种不同的实例属性。

class myClass:
   class_attribute = 99

   def class_method(self):
      self.instance_attribute = 'I am instance attribute'

print (myClass.__dict__)

Output

执行上述代码时,可以看到以下输出:

{'__module__': '__main__', 'class_attribute': 99, 'class_method': <function myClass.class_method at 0x04128D68>, '__dict__': <attribute '__dict__' of 'myClass' objects>, '__weakref__': <attribute '__weakref__' of 'myClass' objects>, '__doc__': None}

实例属性 myClass.dict 如下所示−

>>> a = myClass()
>>> a.class_method()
>>> print(a.__dict__)
{'instance_attribute': 'I am instance attribute'}

Object Oriented Shortcuts

本章节详细讲述了Python中各种内建函数、文件 I/O 操作和重载概念。

Python Built-in Functions

Python 解释器具有许多称为内建函数的函数,随时可供使用。在其最新版本中,Python 包含 68 个内建函数,如下表中所示 −

BUILT-IN FUNCTIONS

abs()

dict()

help()

min()

setattr()

all()

dir()

hex()

next()

slice()

any()

divmod()

id()

object()

sorted()

ascii()

enumerate()

input()

oct()

staticmethod()

bin()

eval()

int()

open()

str()

bool()

exec()

isinstance()

ord()

sum()

bytearray()

filter()

issubclass()

pow()

super()

bytes()

float()

iter()

print()

tuple()

callable()

format()

len()

property()

type()

chr()

frozenset()

list()

range()

vars()

classmethod()

getattr()

locals()

repr()

zip()

compile()

globals()

map()

reversed()

import()

complex()

hasattr()

max()

round()

delattr()

hash()

memoryview()

set()

本节简要讨论了一些重要的函数 −

len() function

len() 函数获取字符串、列表或集合的长度。它返回对象的长度或项目数,其中对象可以是字符串、列表或集合。

>>> len(['hello', 9 , 45.0, 24])
4

len() 函数在内部像 list.len()tuple.len() 一样工作。因此,请注意,len() 仅对具有 *len ()* 方法的对象起作用。

>>> set1
{1, 2, 3, 4}
>>> set1.__len__()
4

然而,在实践中,我们偏爱 len() ,而不是 len() 函数,原因如下 −

  1. 更有效率。并且无需编写特定方法来拒绝访问 len 之类的特殊方法。

  2. 易于维护。

  3. It supports backward compatibility.

Reversed(seq)

返回反转迭代器。seq必须是具有 reversed ()方法,或者支持序列协议的( len ()方法和 getitem ()方法)的对象。通常在 for 循环中使用,当我们想要从后往前循环项目时。

>>> normal_list = [2, 4, 5, 7, 9]
>>>
>>> class CustomSequence():
   def __len__(self):
      return 5
   def __getitem__(self,index):
      return "x{0}".format(index)
>>> class funkyback():
   def __reversed__(self):
      return 'backwards!'
>>> for seq in normal_list, CustomSequence(), funkyback():
      print('\n{}: '.format(seq.__class__.__name__), end="")
      for item in reversed(seq):
         print(item, end=", ")

末尾的for循环打印普通列表的反转列表,以及两个自定义序列的实例。输出结果表明 reversed() 适用于所有这三个序列,但是当我们定义 reversed 时,结果非常不同。

Output

执行上述代码时,可以看到以下输出:

list: 9, 7, 5, 4, 2,
CustomSequence: x4, x3, x2, x1, x0,
funkyback: b, a, c, k, w, a, r, d, s, !,

Enumerate

enumerate () 方法为可迭代项添加一个计数器,然后返回数数对象。

enumerate ()的语法为−

enumerate(iterable, start = 0)

这里,第二个参数 start 是可选的,默认情况下索引从0开始。

>>> # Enumerate
>>> names = ['Rajesh', 'Rahul', 'Aarav', 'Sahil', 'Trevor']
>>> enumerate(names)
<enumerate object at 0x031D9F80>
>>> list(enumerate(names))
[(0, 'Rajesh'), (1, 'Rahul'), (2, 'Aarav'), (3, 'Sahil'), (4, 'Trevor')]
>>>

所以 enumerate() 返回一个迭代器,它产生一个包含在传递序列中元素计数的元组。由于返回值是迭代器,因此直接访问它并没有太大的用处。使用for循环进行计数是enumerate()的一种更好方法。

>>> for i, n in enumerate(names):
   print('Names number: ' + str(i))
   print(n)
Names number: 0
Rajesh
Names number: 1
Rahul
Names number: 2
Aarav
Names number: 3
Sahil
Names number: 4
Trevor

在标准库中还有许多其他函数,下面列出了一些更广泛使用的函数:

  1. hasattr, getattr, setattrdelattr, 允许通过字符串名称来操作对象的属性。

  2. allany, 接受一个可迭代对象,如果所有或任何元素评估为真,则返回 True

  3. nzip, 接受两个或更多序列,并返回一个新的元组序列,其中每个元组包含每个序列中的一个值。

File I/O

文件概念与面向对象编程术语相关。Python 已经将操作系统在抽象中提供的接口封装起来,允许我们处理文件对象。

open() 内置函数用于打开文件并返回文件对象。它是使用两个参数的最常用函数,即:

open(filename, mode)

open() 函数调用两个参数,第一个是文件名,第二个是模式。此处,模式可以是“r”,表示只读模式;“w”,表示只写(同名现有文件将被删除);“a”,表示打开文件进行追加,写入文件中的任何数据将自动添加到末尾。“r+”打开文件进行读写。默认模式是只读。

在 Windows 中,附加到模式后的“b”以二进制模式打开文件,因此还有“rb”、“wb”和“r+b”等模式。

>>> text = 'This is the first line'
>>> file = open('datawork','w')
>>> file.write(text)
22
>>> file.close()

在某些情况下,我们只想追加到现有文件,而不是覆盖它,为此,我们可以提供值“a”作为模式参数,将其追加到文件末尾,而不是完全覆盖现有文件内容。

>>> f = open('datawork','a')
>>> text1 = ' This is second line'
>>> f.write(text1)
20
>>> f.close()

一旦打开一个文件进行读取,我们可以调用 read、readline 或 readlines 方法来获取文件的内容。read 方法返回整个文件的内容,作为 str 或 bytes 对象,具体取决于第二个参数是否是“b”。

为了可读性,并且为了避免一次读取一个大文件,通常最好直接对文件对象使用 for 循环。对于文本文件,它将一次读取每一行,我们可以在循环体中处理。但是,对于二进制文件,最好使用 read() 方法读取固定大小的数据块,并传递最大字节数参数以进行读取。

>>> f = open('fileone','r+')
>>> f.readline()
'This is the first line. \n'
>>> f.readline()
'This is the second line. \n'

通过 file 对象上的 write 方法写入文件,会将字符串(二进制数据的字节)对象写入文件。writelines 方法接受一个字符串序列,并将每次迭代的值写入文件。writelines 方法不会在序列中的每个元素之后附加新行。

最后,当我们完成文件的读写后,应该调用 close() 方法,以确保将所有缓冲写入都写入磁盘,确保文件已正确清理并且释放了与文件捆绑的所有资源并返回给操作系统。最好方法是调用 close() 方法,但在技术上,当脚本存在时会自动发生这种情况。

An alternative to method overloading

方法重载是指有多个方法具有相同名称,并接受不同的参数集。

给定单个方法或函数,我们可以自己指定参数的数量。根据函数定义,可以调用它,参数个数为 0、1、2 或更多。

class Human:
   def sayHello(self, name = None):
      if name is not None:
         print('Hello ' + name)
      else:
         print('Hello ')

#Create Instance
obj = Human()

#Call the method, else part will be executed
obj.sayHello()

#Call the method with a parameter, if part will be executed
obj.sayHello('Rahul')

Output

Hello
Hello Rahul

Default Arguments

Functions Are Objects Too

可调用对象是可以接受一些参数并可能返回对象的。函数是 Python 中最简单的可调用对象,但还有其他对象,如类或某些类实例。

Python 中的每个函数都是一个对象。对象可以包含方法或函数,但对象不必是函数。

def my_func():
   print('My function was called')
my_func.description = 'A silly function'
def second_func():

   print('Second function was called')

   second_func.description = 'One more sillier function'

def another_func(func):
   print("The description:", end=" ")
   print(func.description)
   print('The name: ', end=' ')
   print(func.__name__)
   print('The class:', end=' ')
   print(func.__class__)
   print("Now I'll call the function passed in")
   func()

another_func(my_func)
another_func(second_func)

在上面的代码中,我们能够将两个不同的函数作为参数传递给我们的第三个函数,并为每个函数获取不同的输出,即:

The description: A silly function
The name: my_func
The class:
Now I'll call the function passed in
My function was called
The description: One more sillier function
The name: second_func
The class:
Now I'll call the function passed in
Second function was called

callable objects

就像函数是可以设置属性的对象一样,也可以创建一个可以像函数一样被调用的对象。

在 Python 中,具有 call () 方法的任何对象都可以使用函数调用语法进行调用。

Inheritance and Polymorphism

继承和多态性——这是 Python 中一个非常重要的概念。如果你想学习,你必须更深入地了解它。

Inheritance

面向对象编程的主要优势之一是重用。继承就是实现这一目标的机制之一。继承允许程序员首先创建一个通用类或基类,然后稍后将其扩展为更专门的类。它允许程序员编写更好的代码。

使用继承,你可以使用或继承基类中所有可用的数据字段和方法。稍后,你可以添加自己方法和数据字段,因此继承提供了一种组织代码的方法,而不是从头开始重写它。

在面向对象术语中,当类 X 扩展类 Y 时,Y 被称为超类/父类/基类,X 被称为子类/子类/派生类。这里需要注意的一点是只有非私有的数据字段和方法可供子类访问。私有数据字段和方法仅可在类内访问。

创建派生类的语法为 -

class BaseClass:
   Body of base class
class DerivedClass(BaseClass):
   Body of derived class

Inheriting Attributes

现在,看下面的示例 -

inheriting attributes

Output

inheriting attributes output

我们首先创建一个名为 Date 的类,并传递对象作为参数,这里的对象是由 Python 提供的内置类。稍后,我们创建另一个名为 time 的类,并调用 Date 类作为参数。通过此调用,我们可以访问时间类中日期类的所有数据和属性。正因为如此,当我们尝试从我们之前创建的时间类对象 tm 中获取 get_date 方法时,这是可能的。

Object.Attribute Lookup Hierarchy

  1. The instance

  2. The class

  3. 该类继承的所有类

Inheritance Examples

让我们仔细看看继承示例——

inheritance example

让我们创建两个类来参与示例 -

  1. 动物——模拟动物的类

  2. 猫——动物的子类

  3. 狗 - 动物子类

在 Python 中,用于创建对象(实例)并为属性分配值的是类的构造函数。

子类构造函数总是调用父类构造函数以初始化其属性值,然后开始为其属性分配值。

python constructor

Output

python constructor output

在上面的示例中,我们看到在父类中放置的命令属性或方法,以便所有子类或子类都将从父类继承该属性。

如果子类尝试从另一个子类继承方法或数据,那么它将引发错误,就像我们看到 Dog 类试图从该 cat 类中调用 swatstring() 方法时,它会引发错误(在本例中类似 AttributeError)。

Polymorphism (“MANY SHAPES”)

多态性是 Python 中类定义的一项重要功能,在您跨类或子类拥有同名方法时使用。这允许函数在不同时间使用不同类型的实体。所以,它提供了灵活性并松散耦合,以便随着时间的推移可以扩展和容易维护代码。

这允许函数使用任何这些多态类的对象,而无需了解跨类的区别。

多态性可以通过继承来实现,其中子类使用基类方法或重写它们。

让我们用我们之前关于继承的示例来理解多态性的概念,并在两个子类中添加一个称为 show_affection 的通用方法 −

从示例中我们可以看到,它指的是一种设计,其中不同类型对象可以以相同的方式被对待,或者更具体地说,两个或多个具有同名方法或通用接口的类,因为相同的方法(在本例中为 show_affection)被使用任一类型的对象调用。

polymorphism

Output

polymorphism output

因此,所有动物都会表现出感情(show_affection),但它们表现方式不同。“show_affection” 行为因此是多态的,因为它的行为因动物而异。因此,抽象的“动物”概念实际上不会“show_affection”,但特定的动物(例如狗和猫)具有动作“show_affection” 的具体实现。

Python 本身具有多态的类。例如,len() 函数可以与多个对象一起使用,并且所有函数都根据输入参数返回正确的输出。

polymorphic

Overriding

在 Python 中,当一个子类包含一个覆盖超类方法的方法时,还可以通过调用来调用超类方法

Super(Subclass, self).method 而不是 self.method。

Example

class Thought(object):
   def __init__(self):
      pass
   def message(self):
      print("Thought, always come and go")

class Advice(Thought):
   def __init__(self):
      super(Advice, self).__init__()
   def message(self):
      print('Warning: Risk is always involved when you are dealing with market!')

Inheriting the Constructor

如果从我们之前的继承示例中可以看到, init 位于父类中的向上,因为子类 dog 或 cat 没有 init 方法。Python 使用继承属性查找来在 animal 类中查找 init 。当我们创建子类时,它将首先在 dog 类中查找 init 方法,然后在未找到后查看父类 Animal 并找到它们并进行调用。因此,随着我们类设计的变得复杂,我们可能希望首先通过父类构造函数,然后通过子类构造函数来初始化一个实例。

constructor

Output

constructor output

在上例中——所有动物都有一个名称,所有狗都有一个特定的品种。我们使用 super 来调用父类构造函数。因此,dog 有它自己的 init ,但首先发生的是我们调用 super。Super 是内置函数,它旨在将一个类与其超类或其父类相关联。

在这种情况下,我们所说的是获取 dog 的超类并将 dog 实例传递给我们在构造函数中所说的任何方法 init 。因此,换句话说,我们使用 dog 对象调用父类 Animal init 。你可能想知道,为什么我们不直接使用 dog 实例来说 Animal init ,我们也可以这样做,但是如果 animal 类名称在将来某个时间发生更改怎么办。如果我们想要重新排列类层次结构,那么 dog 会从另一个类继承。在这种情况下使用 super 会让事情保持模块化,并且易于更改和维护。

因此,在这个示例中,我们能够将通用 init 功能与更具体的功能相结合。这给了我们机会将通用功能与特定功能分开,这可以消除代码重复,并且以反映系统整体设计的方式将类相互关联。

Conclusion

  1. init 就像其他任何方法一样;它可以被继承

  2. 如果一个类没有 init 构造函数,Python 将检查其父类以查看是否可以找到一个。

  3. 一旦找到,Python 就会调用它并停止查找

  4. 我们可以使用 super() 函数来调用父类中的方法。

  5. 我们可能希望在父类和我们自己的类中进行初始化。

Multiple Inheritance and the Lookup Tree

顾名思义,多重继承是 Python 中的一个类从多个类继承的情况。

例如,一个孩子从父母(母亲和父亲)双方继承性格特征。

Python Multiple Inheritance Syntax

要让一个类从多个父类继承,我们在定义它时将这些类的名称写在派生类的圆括号中。我们用逗号分隔这些名称。

下面是一个示例:

>>> class Mother:
   pass

>>> class Father:
   pass

>>> class Child(Mother, Father):
   pass

>>> issubclass(Child, Mother) and issubclass(Child, Father)
True

多重继承是指从两个或两个以上的类中继承的能力。当孩子从父母继承,而父母从祖父母类继承时,复杂性就会出现。Python 会爬一个继承树,寻找要从某个对象读取的属性。它将在实例中、类内、父类中和最后从祖父母类中进行检查。现在出现的一个问题是,以什么顺序搜索这些类——广度优先还是深度优先。默认情况下,Python 使用深度优先。

这就是为什么在下面的图表中,Python 首先在类 A 中搜索 dothis() 方法。因此,以下示例中的方法解析顺序为:

Mro- D→B→A→C

查看下面的多重继承图表:

multiple inheritance

让我们通过一个示例来了解 Python 的“mro”特性的。

Output

python mro feature output

Example 3

让我们再举一个“菱形”多重继承的示例。

diamond shape multiple inheritance

上面的图表将被认为是模棱两可的。从我们之前的示例中理解“方法解析顺序” .i.e. mro 将为 D→B→A→C→A,但事实并非如此。从 C 中获得第二个 A 时,Python 将忽略前面的 A。因此,在这种情况下,mro 将为 D→B→C→A。

让我们基于上面的图表创建一个示例:

method resolution order

Output

method resolution order output

理解以上输出的简单规则是——如果同一个类出现在方法解析顺序中,则这个类的早期出现将从方法解析顺序中移除。

总结:

  1. 任何类都可以从多个类继承

  2. Python 在搜索继承类时通常使用“深度优先”顺序。

  3. 但是当两个类从同一个类继承时,Python 会从 mro 中消除该类的第一次出现。

Decorators, Static and Class Methods

函数(或方法)通过 def 语句创建。

尽管方法在以下一点上的工作方式与函数完全相同,但方法的第一个参数是实例对象。

我们可以根据其行为方式对方法进行分类,例如:

  1. Simple method - 在类外部定义。此函数可以通过提供实例参数来访问类属性:

def outside_func(():
  1. Instance method

def func(self,)
  1. Class method - 如果我们需要使用类属性

   @classmethod
def cfunc(cls,)
  1. Static method - 没有任何关于类的信息

      @staticmethod
def sfoo()

到目前为止,我们已经看到了实例方法,现在是时候深入了解其他两种方法了,

Class Method

@classmethod 装饰器是一个内置函数装饰器,它将作为第一个参数传递调用它的类,或调用它的实例的类。该评估的结果会隐藏您的函数定义。

syntax

class C(object):
   @classmethod
   def fun(cls, arg1, arg2, ...):
      ....
fun: function that needs to be converted into a class method
returns: a class method for function

他们有权访问此 cls 参数,它不能修改对象实例状态。这需要访问 self。

  1. 它绑定到类,而不是类的对象。

  2. 类方法仍然可以修改适用于类的所有实例的类状态。

Static Method

静态方法不接受 self 或 cls(class) 参数,但它可以自由地接受任意数量的其他参数。

syntax

class C(object):
   @staticmethod
   def fun(arg1, arg2, ...):
   ...
returns: a static method for function funself.
  1. 静态方法既不能修改对象状态,也不能修改类状态。

  2. 他们可以访问的数据受到限制。

When to use what

  1. 我们通常使用类方法创建工厂方法。工厂方法为不同的用例返回类对象(类似于构造函数)。

  2. 我们通常使用静态方法创建实用函数。

Python Design Pattern

Overview

现代软件开发需要满足复杂业务需求。它还需要考虑以下因素,例如将来的可扩展性和可维护性。软件系统的好设计对于实现这些目标至关重要。设计模式在这样的系统中起着重要作用。

为了理解设计模式,让我们考虑以下示例 -

  1. 每辆汽车的设计都遵循基本设计模式,四个轮子,方向盘,核心驱动系统,例如加速器-断裂-离合器等。

因此,所有反复构建/生成的物品必然在其设计中遵循一种模式,比如汽车、自行车、比萨饼、ATM 机,甚至是你的沙发床。

几乎已成为编码软件中的某种逻辑/机制/技术标准的方法的设计,因此被称为或研究为软件设计模式。

Why is Design Pattern Important?

使用设计模式的好处如下−

  1. 通过久经考验的方法帮你解决常见的设计问题。

  2. 没有歧义的理解,因为它们有详细的文档。

  3. 缩短总体开发时间。

  4. 更轻松地处理未来的扩展和修改。

  5. 可以减少系统错误,因为它们是针对常见问题的久经考验的解决方案。

Classification of Design Patterns

GoF(四人帮)设计模式分为三类,即创建型、结构型和行为型。

Creational Patterns

创建型设计模式将对象创建逻辑与系统其他部分分离开来。创建型模式替代你创建对象,为你创建它们。创建型模式包括抽象工厂、生成器、工厂方法、原型和单例。

由于语言的动态特性,Python 中通常不使用创建型模式。此外,语言本身为我们提供了创建的所需灵活性,以足够优雅的方式,我们很少需要在顶层实现任何东西,如单例或工厂。

此外,这些模式提供了一种在隐藏创建逻辑的情况下创建对象的方式,而不是直接使用 new 运算符实例化对象。

Structural Patterns

有时,你不必从头开始,而是需要使用一组现有的类来构建更大的结构。这就是结构类模式使用继承来构建新结构的地方。结构对象模式使用组合/聚合来获得新功能。适配器、桥接、复合、装饰器、外观、享元和代理是结构模式。它们提供了组织类层次结构的最佳方式。

Behavioral Patterns

行为模式提供了处理对象之间通信的最佳方式。属于此类别的模式有:访问者、职责链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略和模板方法是行为模式。

因为它们表示系统的行为,所以通常用于描述软件系统的功能。

Commonly used Design Patterns

Singleton

它是所有设计模式中最有争议和最著名的模式之一。它用于过度面向对象语言,并且是传统面向对象编程的重要组成部分。

单例模式用于:

  1. 当需要实现日志记录时。logger 实例由系统的各个组件共享。

  2. 配置文件正在使用它,因为需要对信息进行缓存,并由系统中的所有各个组件共享。

  3. 管理到数据库的连接。

以下是 UML 图表,

uml diagram
class Logger(object):
   def __new__(cls, *args, **kwargs):
      if not hasattr(cls, '_logger'):
      cls._logger = super(Logger, cls).__new__(cls, *args, **kwargs)
return cls._logger

此示例中,Logger 为单例。

在调用 new 时,它会构造该类的某个新实例。当覆盖它时,我们首先检查我们的单例实例是否已创建。如果没有,我们使用超级调用创建它。因此,每当我们调用 Logger 上的构造函数时,我们始终会获得完全相同的实例。

>>>
>>> obj1 = Logger()
>>> obj2 = Logger()
>>> obj1 == obj2
True
>>>
>>> obj1
<__main__.Logger object at 0x03224090>
>>> obj2
<__main__.Logger object at 0x03224090>

Object Oriented Python - Advanced Features

在此,我们将研究 Python 提供的部分高级特性

Core Syntax in our Class design

在此,我们将关注 Python 如何让我们利用我们的类中的操作符。Python 主要涉及对象和方法在对象上的调用,即使它隐藏在某种便捷的语法中时也是如此。

>>> var1 = 'Hello'
>>> var2 = ' World!'
>>> var1 + var2
'Hello World!'
>>>
>>> var1.__add__(var2)
'Hello World!'
>>> num1 = 45
>>> num2 = 60
>>> num1.__add__(num2)
105
>>> var3 = ['a', 'b']
>>> var4 = ['hello', ' John']
>>> var3.__add__(var4)
['a', 'b', 'hello', ' John']

因此,如果我们需要将魔术方法 add 添加到我们自己的类,我们可以这样做吗。让我们尝试。

我们有一个名为 Sumlist 的类,它具有一个构造函数 init ,该构造函数获取一个列表作为名为 my_list 的参数。

class SumList(object):
   def __init__(self, my_list):
      self.mylist = my_list
   def __add__(self, other):
     new_list = [ x + y for x, y in zip(self.mylist, other.mylist)]

     return SumList(new_list)

   def __repr__(self):
      return str(self.mylist)

aa = SumList([3,6, 9, 12, 15])

bb = SumList([100, 200, 300, 400, 500])
cc = aa + bb # aa.__add__(bb)
print(cc) # should gives us a list ([103, 206, 309, 412, 515])

Output

[103, 206, 309, 412, 515]

但有很多方法是由其他魔术方法内部管理的。以下列出部分方法,

'abc' in var # var.__contains__('abc')
var == 'abc' # var.__eq__('abc')
var[1] # var.__getitem__(1)
var[1:3] # var.__getslice__(1, 3)
len(var) # var.__len__()
print(var) # var.__repr__()

Inheriting From built-in types

类还可从内置类型继承,这意味着从任何内置类型继承并利用在其中发现的所有功能。

在以下示例中,我们正在从字典继承,但我们正在实现它的一种方法 setitem 。在我们设置字典中的键值时,会调用此 (setitem) 方法。由于这是一个魔术方法,因此它将隐式调用。

class MyDict(dict):

   def __setitem__(self, key, val):
      print('setting a key and value!')
      dict.__setitem__(self, key, val)

dd = MyDict()
dd['a'] = 10
dd['b'] = 20

for key in dd.keys():
   print('{0} = {1}'.format(key, dd[key]))

Output

setting a key and value!
setting a key and value!
a = 10
b = 20

让我们扩展我们的前一个示例,以下我们调用了两个魔术方法 getitemsetitem ,在处理列表索引时会更好用。

# Mylist inherits from 'list' object but indexes from 1 instead for 0!
class Mylist(list): # inherits from list
   def __getitem__(self, index):
      if index == 0:
         raise IndexError
      if index > 0:
         index = index - 1
         return list.__getitem__(self, index) # this method is called when

# we access a value with subscript like x[1]
   def __setitem__(self, index, value):
      if index == 0:
         raise IndexError
      if index > 0:
      index = index - 1
      list.__setitem__(self, index, value)

x = Mylist(['a', 'b', 'c']) # __init__() inherited from builtin list

print(x) # __repr__() inherited from builtin list

x.append('HELLO'); # append() inherited from builtin list

print(x[1]) # 'a' (Mylist.__getitem__ cutomizes list superclass
               # method. index is 1, but reflects 0!

print (x[4]) # 'HELLO' (index is 4 but reflects 3!

Output

['a', 'b', 'c']
a
HELLO

在上面的示例中,我们在 Mylist 中设置了一个三项列表,并隐式调用 init 方法,并且在我们打印元素 x 时,我们获得了三项列表 ([‘a’,’b’,’c’])。然后,我们将另一元素附加到该列表。稍后我们询问索引 1 和索引 4。但如果你查看输出,我们正在从 (index-1) 中获取我们所要求的元素。众所周知,列表索引从 0 开始,但这里的索引从 1 开始(这就是我们获取列表中第一个项的原因)。

Naming Conventions

在此,我们将研究我们对变量(特别是私有变量)使用的名称以及全世界 Python 程序员使用的约定。尽管变量被指定为私有的,但 Python 中没有隐私,这是设计使然。与任何其他有据可查的语言一样,Python 也有命令和风格方面的惯例,虽然它并不强制执行它们,但会推广它们。有一个由 Guido van Rossum” the originator of Python, that describe the best practices and use of name and is called PEP8. Here is the link for this, https://www.python.org/dev/peps/pep-0008/ 编写的风格指南

PEP 代表 Python 增强提案,是一系列文档,在 Python 社区中分发,以讨论提议的更改。例如,建议所有人,

  1. Module names − all_lower_case

  2. 类名和异常名 - 驼峰式

  3. 全局名称和局部名称 - 全小写

  4. 函数和方法名称 - 全小写

  5. Constants − ALL_UPPER_CASE

这些只是建议,如果你愿意,可以随时更改。但由于大多数开发人员都遵循这些建议,因此你的代码的可读性可能会降低。

Why conform to convention?

我们可以遵循 PEP 建议,因为这允许我们获得,

  1. 更多开发人员熟悉

  2. 代码的大多数读者都更清楚。

  3. 与处理相同代码库的其他贡献者的风格相匹配。

  4. 专业软件开发人员的标志

  5. Everyone will accept you.

Variable Naming − ‘Public’ and ‘Private’

在 Python 中,当我们处理模块和类时,我们将一些变量或属性指定为私有。在 Python 中,不存在“私有”实例变量,除了对象内部以外,无法访问该变量。私有简单地意味着它们根本不是供代码用户使用,而是供内部使用。通常,大多数 Python 开发人员遵循一个惯例,即一个名称以下划线开头,例如。 _attrval(以下示例)应被视为 API 或任何 Python 代码的非公有部分,无论它是一个函数、一个方法还是一个数据成员。以下是我们遵循的命名约定,

  1. 公有属性或变量(供此模块的导入者或此类的用户使用)− regular_lower_case

  2. 私有属性或变量(模块或类的内部使用)− _single_leading_underscore

  3. 不应子类化的私有属性 − __double_leading_underscore

  4. Magic 属性 − double_underscores (使用它们,不要创建它们)

class GetSet(object):

   instance_count = 0 # public

   __mangled_name = 'no privacy!' # special variable

   def __init__(self, value):
      self._attrval = value # _attrval is for internal use only
      GetSet.instance_count += 1

   @property
   def var(self):
      print('Getting the "var" attribute')
      return self._attrval

   @var.setter
   def var(self, value):
      print('setting the "var" attribute')
      self._attrval = value

   @var.deleter
   def var(self):
      print('deleting the "var" attribute')
      self._attrval = None

cc = GetSet(5)
cc.var = 10 # public name
print(cc._attrval)
print(cc._GetSet__mangled_name)

Output

setting the "var" attribute
10
no privacy!

Object Oriented Python - Files and Strings

Strings

字符串是所有编程语言中最常用的数据类型。这是为什么?因为我们更能理解文本,而不是数字,所以我们在书写和交谈时使用文本和单词,同样,在编程中,我们也使用字符串。在字符串中,我们解析文本、分析文本语义并进行数据挖掘 - 所有这些数据都是人类可理解的文本。Python 中的字符串是不可变的。

String Manipulation

在 Python 中,字符串可以用多种方式标记,对于多行字符串可以使用单引号(')、双引号(")甚至三重引号(''')。

>>> # String Examples
>>> a = "hello"
>>> b = ''' A Multi line string,
Simple!'''
>>> e = ('Multiple' 'strings' 'togethers')

字符串操作非常有用,在每种语言中都得到了非常广泛的使用。通常,程序员需要分解字符串并仔细检查它们。

字符串可以进行迭代(逐个字符)、切片或连接。语法与列表相同。

str 类中包含大量方法,可以使字符串操作变得更容易。dir 和 help 命令在 Python 解释器中提供了如何使用这些方法的指导。

以下是我们使用的一些常用字符串方法。

Sr.No.

Method & Description

1

isalpha() 检查所有字符是否是字母

2

isdigit() Checks Digit Characters

3

isdecimal() Checks decimal Characters

4

isnumeric() checks Numeric Characters

5

find() 返回子字符串的最高索引

6

istitle() Checks for Titlecased strings

7

join() Returns a concatenated string

8

lower() returns lower cased string

9

upper() returns upper cased string

10

partion() Returns a tuple

11

bytearray() 返回给定字节大小的数组

12

enumerate() Returns an enumerate object

13

isprintable() Checks printable character

让我们尝试运行几个字符串方法:

>>> str1 = 'Hello World!'
>>> str1.startswith('h')
False
>>> str1.startswith('H')
True
>>> str1.endswith('d')
False
>>> str1.endswith('d!')
True
>>> str1.find('o')
4
>>> #Above returns the index of the first occurence of the character/substring.
>>> str1.find('lo')
3
>>> str1.upper()
'HELLO WORLD!'
>>> str1.lower()
'hello world!'
>>> str1.index('b')
Traceback (most recent call last):
   File "<pyshell#19>", line 1, in <module>
      str1.index('b')
ValueError: substring not found
>>> s = ('hello How Are You')
>>> s.split(' ')
['hello', 'How', 'Are', 'You']
>>> s1 = s.split(' ')
>>> '*'.join(s1)
'hello*How*Are*You'
>>> s.partition(' ')
('hello', ' ', 'How Are You')
>>>

String Formatting

在 Python 3.x 中,字符串的格式发生了变化,现在更合乎逻辑且更灵活。可以在格式字符串中使用 format() 方法或 % 符号(旧样式)进行格式化。

字符串可以包含文字或用大括号 {} 括起来的替换字段,每个替换字段都可以包含位置参数的数字索引或关键字参数的名称。

syntax

str.format(*args, **kwargs)

Basic Formatting

>>> '{} {}'.format('Example', 'One')
'Example One'
>>> '{} {}'.format('pie', '3.1415926')
'pie 3.1415926'

以下示例允许重新调整显示顺序而不更改参数。

>>> '{1} {0}'.format('pie', '3.1415926')
'3.1415926 pie'

字符串填充和对齐

可以将值填充到特定长度。

>>> #Padding Character, can be space or special character
>>> '{:12}'.format('PYTHON')
'PYTHON '
>>> '{:>12}'.format('PYTHON')
' PYTHON'
>>> '{:<{}s}'.format('PYTHON',12)
'PYTHON '
>>> '{:*<12}'.format('PYTHON')
'PYTHON******'
>>> '{:*^12}'.format('PYTHON')
'***PYTHON***'
>>> '{:.15}'.format('PYTHON OBJECT ORIENTED PROGRAMMING')
'PYTHON OBJECT O'
>>> #Above, truncated 15 characters from the left side of a specified string
>>> '{:.{}}'.format('PYTHON OBJECT ORIENTED',15)
'PYTHON OBJECT O'
>>> #Named Placeholders
>>> data = {'Name':'Raghu', 'Place':'Bangalore'}
>>> '{Name} {Place}'.format(**data)
'Raghu Bangalore'
>>> #Datetime
>>> from datetime import datetime
>>> '{:%Y/%m/%d.%H:%M}'.format(datetime(2018,3,26,9,57))
'2018/03/26.09:57'

Strings are Unicode

字符串作为不可变 Unicode 字符的集合。Unicode 字符串提供了创建可在任何地方运行的软件或程序的机会,因为 Unicode 字符串可以表示任何可能的字符,而不仅仅是 ASCII 字符。

即使字节对象引用文本数据,许多 IO 操作也只知道如何处理字节。因此,了解如何在字节和 Unicode 之间进行互换非常重要。

Converting text to bytes

将字符串转换为字节对象称为编码。有许多形式的编码,最常见的是:PNG;JPEG、MP3、WAV、ASCII、UTF-8 等。此外,(编码)是一种以字节表示音频、图像、文本等的格式。

这种转换可以通过 encode() 实现。它将编码技术作为参数。默认情况下,我们使用“UTF-8”技术。

>>> # Python Code to demonstrate string encoding
>>>
>>> # Initialising a String
>>> x = 'TutorialsPoint'
>>>
>>> #Initialising a byte object
>>> y = b'TutorialsPoint'
>>>
>>> # Using encode() to encode the String >>> # encoded version of x is stored in z using ASCII mapping
>>> z = x.encode('ASCII')
>>>
>>> # Check if x is converted to bytes or not
>>>
>>> if(z==y):
   print('Encoding Successful!')
else:
   print('Encoding Unsuccessful!')
Encoding Successful!

Converting bytes to text

将字节转换为文本称为解码。这是通过 decode() 实现的。如果我们知道哪个编码用于对其进行编码,则可以将字节字符串转换为字符字符串。

因此,编码和解码是逆向过程。

>>>
>>> # Python code to demonstrate Byte Decoding
>>>
>>> #Initialise a String
>>> x = 'TutorialsPoint'
>>>
>>> #Initialising a byte object
>>> y = b'TutorialsPoint'
>>>
>>> #using decode() to decode the Byte object
>>> # decoded version of y is stored in z using ASCII mapping
>>> z = y.decode('ASCII')
>>> #Check if y is converted to String or not
>>> if (z == x):
   print('Decoding Successful!')
else:
   print('Decoding Unsuccessful!') Decoding Successful!
>>>

File I/O

操作系统将文件表示为字节序列,而不是文本。

文件是磁盘上的一个已命名位置,用于存储相关信息。它用于永久存储磁盘中的数据。

在 Python 中,文件操作按以下顺序进行。

  1. Open a file

  2. 从文件(操作)中读取或写入。打开文件

  3. Close the file.

Python 用适当的解码(或编码)调用包装传入(或传出)字节流,以便我们可以直接处理 str 对象。

Opening a file

Python 有一个内置函数 open() 来打开文件。这将生成一个文件对象,也称为句柄,因为它用于相应地读取或修改文件。

>>> f = open(r'c:\users\rajesh\Desktop\index.webm','rb')
>>> f
<_io.BufferedReader name='c:\\users\\rajesh\\Desktop\\index.webm'>
>>> f.mode
'rb'
>>> f.name
'c:\\users\\rajesh\\Desktop\\index.webm'

要从文件中读取文本,我们只需要将文件名传递给函数。系统将打开该文件以进行读取,并使用平台默认编码将字节转换为文本。

Exception and Exception Classes

一般而言,异常是任何不寻常状况。异常通常表示错误,但有时候在程序中故意加入异常,如提早终止程序或从资源不足中回复。有许多内置的异常,表示各种状况,如读到档案结尾后,或除以零。我们可以定义我们自己的异常,称为自定义异常。

异常处理让你能优雅地处理错误,并采取有意义的作为。异常处理有两种组件:“抛出”和“捕获”。

Identifying Exception (Errors)

Python 中发生的每个错误都会产生异常,该异常将以其错误类型识别为错误状况。

>>> #Exception
>>> 1/0
Traceback (most recent call last):
   File "<pyshell#2>", line 1, in <module>
      1/0
ZeroDivisionError: division by zero
>>>
>>> var = 20
>>> print(ver)
Traceback (most recent call last):
   File "<pyshell#5>", line 1, in <module>
      print(ver)
NameError: name 'ver' is not defined
>>> #Above as we have misspelled a variable name so we get an NameError.
>>>
>>> print('hello)

SyntaxError: EOL while scanning string literal
>>> #Above we have not closed the quote in a string, so we get SyntaxError.
>>>
>>> #Below we are asking for a key, that doen't exists.
>>> mydict = {}
>>> mydict['x']
Traceback (most recent call last):
   File "<pyshell#15>", line 1, in <module>
      mydict['x']
KeyError: 'x'
>>> #Above keyError
>>>
>>> #Below asking for a index that didn't exist in a list.
>>> mylist = [1,2,3,4]
>>> mylist[5]
Traceback (most recent call last):
   File "<pyshell#20>", line 1, in <module>
      mylist[5]
IndexError: list index out of range
>>> #Above, index out of range, raised IndexError.

Catching/Trapping Exception

当你的程序中发生不寻常的事,而且你希望使用异常机制来处理它,你就要“抛出一个异常”。关键字 try 和 except 用于捕获异常。任何时候在 try 块中发生异常时,Python 会寻找匹配的 except 块来处理该异常。如果有的话,执行就会跳到那里。

syntax

try:
   #write some code
   #that might throw some exception
except <ExceptionType>:
   # Exception handler, alert the user

try 子句中的代码将逐语句执行。

如果发生异常,try 块的其余部分将被跳过,并且 except 子句将被执行。

try:
   some statement here
except:
   exception handling

让我们写一些代码,看看在你不在程序中使用任何错误处理机制时会发生什么。

number = int(input('Please enter the number between 1 & 10: '))
print('You have entered number',number)

只要使用者输入数字,以上程序就会正常运作,但如果使用者试图输入一些其他数据类型(例如字符串或列表)时,会发生什么情况?

Please enter the number between 1 > 10: 'Hi'
Traceback (most recent call last):
   File "C:/Python/Python361/exception2.py", line 1, in <module>
      number = int(input('Please enter the number between 1 & 10: '))
ValueError: invalid literal for int() with base 10: "'Hi'"

现在 ValueError 是异常类型。让我们尝试使用异常处理来重新编写上述代码。

import sys

print('Previous code with exception handling')

try:
   number = int(input('Enter number between 1 > 10: '))

except(ValueError):
   print('Error..numbers only')
   sys.exit()

print('You have entered number: ',number)

如果我们运行此程序,并且输入一个字符串(而不是数字),我们便可以看到会得到不同的结果。

Previous code with exception handling
Enter number between 1 > 10: 'Hi'
Error..numbers only

Raising Exceptions

要从你自己的方法引发错误,你需要使用 raise 关键字,如下所示

raise ExceptionClass(‘Some Text Here’)

我们举个例子

def enterAge(age):
   if age<0:
      raise ValueError('Only positive integers are allowed')
   if age % 2 ==0:
      print('Entered Age is even')
   else:
      print('Entered Age is odd')

try:
   num = int(input('Enter your age: '))
   enterAge(num)
except ValueError:
   print('Only positive integers are allowed')

运行程序并输入正整数。

Expected Output

Enter your age: 12
Entered Age is even

但是当我们尝试输入负数时,会得到,

Expected Output

Enter your age: -2
Only positive integers are allowed

Creating Custom exception class

你可以通过扩展 BaseException 类或 BaseException 的子类来创建自定义异常类。

custom exception class

从上图中,我们可以看到 Python 中大多数异常类都从 BaseException 类扩展而来。你可以从 BaseException 类或其子类派生你自己的异常类。

创建一个名为 NegativeNumberException.py 的新文件,并编写以下代码。

class NegativeNumberException(RuntimeError):
   def __init__(self, age):
      super().__init__()
      self.age = age

以上代码创建一个新异常类,名为 NegativeNumberException,它仅包含一个构造函数,该构造函数使用 super() init () 调用父类构造函数并设置年龄。

现在为了创建你自己的自定异常类,将会编写一些代码并导入新的异常类。

from NegativeNumberException import NegativeNumberException
def enterage(age):
   if age < 0:
      raise NegativeNumberException('Only positive integers are allowed')

   if age % 2 == 0:
      print('Age is Even')

   else:
      print('Age is Odd')

try:
   num = int(input('Enter your age: '))
   enterage(num)
except NegativeNumberException:
   print('Only positive integers are allowed')
except:
   print('Something is wrong')

Output

Enter your age: -2
Only positive integers are allowed

另一种创建自定异常类的方式。

class customException(Exception):
   def __init__(self, value):
      self.parameter = value

   def __str__(self):
      return repr(self.parameter)
try:
   raise customException('My Useful Error Message!')
except customException as instance:
   print('Caught: ' + instance.parameter)

Output

Caught: My Useful Error Message!

Exception hierarchy

内建异常的类层次为 −

+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning

Object Oriented Python - Object Serialization

在数据存储的上下文中,序列化是将数据结构或对象状态转换为可以存储(例如,在文件或内存缓冲区中)或以后传输和重建的格式的过程。

在序列化中,对象被转换成可以存储的格式,以便能够在以后对其进行反序列化并从序列化格式重新创建原始对象。

Pickle

Pickling 是将 Python 对象层次结构转换为字节流(通常不可读)以写入文件的过程,这也称为序列化。反序列化是逆向操作,其中字节流被转换回正在工作的 Python 对象层次结构。

Pickle 是存储对象的运维最简单的方式。Python Pickle 模块是一种面向对象的方式,可以将对象直接存储在特殊的存储格式中。

What can it do?

  1. Pickle 可以非常容易地存储和复制字典以及列表。

  2. 存储对象属性并将其还原到相同状态。

What pickle can’t do?

  1. 它不保存对象的代码。只有它的属性值。

  2. 它不能存储文件句柄或连接套接字。

简言之,我们可以说,腌制是一种将数据变量存储到文件中并从中检索数据变量的方法,其中变量可以是列表、类等。

要腌制某些内容,您必须:

  1. import pickle

  2. 将变量写入文件,类似于

pickle.dump(mystring, outfile, protocol),

第三个参数协议是可选的。要解腌制某些内容,您必须:

导入pickle

将变量写入文件,类似于

myString = pickle.load(inputfile)

Methods

pickle 接口提供了四种不同的方法。

  1. dump() - dump()方法对此类对象序列号:open file(类似文件的对象)。

  2. dumps() - 序列号为字符型

  3. load() - 从类似open的对象解序列号。

  4. loads() - 从字符型解序列号。

基于以上程序,以下是“腌制”的一个示例。

pickling

Output

My Cat pussy is White and has 4 legs
Would you like to see her pickled? Here she is!
b'\x80\x03c__main__\nCat\nq\x00)\x81q\x01}q\x02(X\x0e\x00\x00\x00number_of_legsq\x03K\x04X\x05\x00\x00\x00colorq\x04X\x05\x00\x00\x00Whiteq\x05ub.'

因此,在上面的示例中,我们已经创建了Cat类的实例,然后我们将其腌制,将我们的“Cat”实例转换为简单的字节数组。

通过这种方式,我们可以轻松地将字节数组存储在二进制文件或数据库字段中,并稍后从存储支持中将其还原为其原始形式。

另外,如果您想使用腌制对象创建一个文件,您可以使用dump()方法(而不是dumps*()*)同时传递已打开的二进制文件,并且腌制结果将自动存储在文件中。

[….]
binary_file = open(my_pickled_Pussy.bin', mode='wb')
my_pickled_Pussy = pickle.dump(Pussy, binary_file)
binary_file.close()

Unpickling

将二进制数组转换为对象层次的过程称为解腌制。

解腌制过程是通过使用pickle模块的load()函数完成的,并从简单的字节数组中返回一个完整对象层次。

让我们在前面的示例中使用load函数。

unpicking

Output

MeOw is black
Pussy is white

JSON

JSON(JavaScript Object Notation)是 Python 标准库的一部分,是一种轻量级数据交换格式。它易于人类阅读和编写。它易于解析和生成。

由于其简单性,JSON 是一种我们存储和交换数据的方式,这是通过其 JSON 语法完成的,且用于许多 Web 应用程序中。因为它采用人类可读的格式,加上它在处理 API 时非常有效,这可能成为使用它进行数据传输的原因之一。

JSON 格式数据的示例如下:

{"EmployID": 40203, "Name": "Zack", "Age":54, "isEmployed": True}

Python 便于处理 Json 文件。为此目的而使用的模块是 JSON 模块。应将此模块包含(内置)在您的 Python 安装中。

因此,让我们看看如何将 Python 字典转换为 JSON,并将其写入文本文件。

JSON to Python

读取 JSON 意味着将 JSON 转换为 Python 值(对象)。json 库将 JSON 解析为 Python 中的字典或列表。为此,我们使用 loads() 函数(从字符串加载),如下所示:

json to python

Output

json to python output

下面是示例 json 文件之一:

data1.json
{"menu": {
   "id": "file",
   "value": "File",
   "popup": {
      "menuitem": [
         {"value": "New", "onclick": "CreateNewDoc()"},
         {"value": "Open", "onclick": "OpenDoc()"},
         {"value": "Close", "onclick": "CloseDoc()"}
      ]
   }
}}

上面的内容(Data1.json)看起来像传统字典。我们可以使用 pickle 存储此文件,但其输出不是人类可读的格式。

JSON(JavaScript 对象通知)是一种非常简单的格式,这也是它流行的原因之一。现在让我们通过下面的程序来了解 json 输出。

java script object notification

Output

java script object notification output

以上我们打开了 json 文件(data1.json)进行读取,获取文件处理程序并传递到 json.load 中,然后取回对象。当我们尝试打印对象的输出时,它和 json 文件相同。尽管对象的类型是字典,但它显示为 Python 对象。正如我们看到这个 pickle 一样,写入 json 也很简单。上面我们加载了 json 文件,添加了另一个键值对,并将其写回同一个 json 文件。现在,如果我们查看 data1.json,它看起来是不同的,即它与我们之前看到的格式不同。

若要使我们的输出看起来相同(人类可读的格式),请将几个参数添加到程序的最后一行,

json.dump(conf, fh, indent = 4, separators = (‘,’, ‘: ‘))

与 pickle 类似,我们可以使用 dumps 打印字符串,并使用 loads 加载。以下是示例:

string with dumps

YAML

YAML 可能是所有人编程语言中最接近于人类的 data 序列化标准。

Python yaml 模块称为 pyaml

YAML 是 JSON 的替代品:

  1. Human readable code - YAML 是最接近人类可读格式的数据,甚至它的主页内容也以 YAML 显示以便强调这一点。

  2. Compact code - 在 YAML 中,我们使用空格缩进表示结构,而不是括号。

  3. Syntax for relational data - 对于内部引用,我们使用锚 (&) 和别名 (*)。

  4. One of the area where it is used widely is for viewing/editing of data structures - 例如配置文件,在调试和文档标题期间转储。

Installing YAML

由于 yaml 不是内置模块,因此我们需手动安装它。在 Windows 计算机上安装 yaml 的最佳方法是通过 pip。在 Windows terminal 上运行以下命令来安装 yaml:

pip install pyaml (Windows machine)
sudo pip install pyaml (*nix and Mac)

运行上方命令后,屏幕基于当前最新版本显示以下内容。

Collecting pyaml
Using cached pyaml-17.12.1-py2.py3-none-any.whl
Collecting PyYAML (from pyaml)
Using cached PyYAML-3.12.tar.gz
Installing collected packages: PyYAML, pyaml
Running setup.py install for PyYAML ... done
Successfully installed PyYAML-3.12 pyaml-17.12.1

为了测试它,在 Python shell 中导入 yaml 模块,如果未找到错误,那么我们可以说,安装成功了。

安装 pyaml 之后,我们看一下下面的代码,

script_yaml1.py
yaml

上面,我们创建了三个不同的数据结构、字典、列表和元组。在每个结构上,我们执行 yaml.dump。重点是如何在屏幕上显示输出。

Output

yaml output

字典输出看起来很干净,即 key:value。

用空白分隔不同的对象。

列表用破折号 (-) 表示。

元组首先用 !!Python/tuple 表示,然后用与列表相同格式表示。

加载 yaml 文件

假设我有一个 yaml 文件,其中包含,

---
# An employee record
name: Raagvendra Joshi
job: Developer
skill: Oracle
employed: True
foods:
   - Apple
   - Orange
   - Strawberry
   - Mango
languages:
   Oracle: Elite
   power_builder: Elite
   Full Stack Developer: Lame
education:
   4 GCSEs
   3 A-Levels
   MCA in something called com

现在,让我们编写代码来通过 yaml.load 函数加载此 yaml 文件。以下是代码。

yaml load function

由于输出看起来不是很好读,我在最后使用 json 对它进行了美化。比较我们获得的输出和我们拥有的实际 yaml 文件。

Output

yaml load function output

软件开发生命中最重要的一方面就是调试。在本节中,我们将了解通过内置调试器或第三方调试器进行 Python 调试的不同方式。

PDB – The Python Debugger

模块 PDB 支持设置断点。断点是程序有意暂停的地方,您可以在其中获得更多有关程序状态的信息。

要设置断点,请插入以下行

pdb.set_trace()

Example

pdb_example1.py
import pdb
x = 9
y = 7
pdb.set_trace()
total = x + y
pdb.set_trace()

我们在本程序中插入了一些断点。程序在每个断点(pdb.set_trace())处暂停。要查看变量内容,只需键入变量名即可。

c:\Python\Python361>Python pdb_example1.py
> c:\Python\Python361\pdb_example1.py(8)<module>()
-> total = x + y
(Pdb) x
9
(Pdb) y
7
(Pdb) total
*** NameError: name 'total' is not defined
(Pdb)

按 c 或继续继续执行程序,直到下一个断点。

(Pdb) c
--Return--
> c:\Python\Python361\pdb_example1.py(8)<module>()->None
-> total = x + y
(Pdb) total
16

最终,您将需要调试更大的程序—使用子例程的程序。有时,您要查找的问题存在于子例程内。考虑以下程序。

import pdb
def squar(x, y):
   out_squared = x^2 + y^2
   return out_squared
if __name__ == "__main__":
   #pdb.set_trace()
   print (squar(4, 5))

现在运行上述程序,

c:\Python\Python361>Python pdb_example2.py
> c:\Python\Python361\pdb_example2.py(10)<module>()
-> print (squar(4, 5))
(Pdb)

我们可以使用 ? 寻求帮助,但箭头指示即将执行的行。在这个时候,点击 s s 很管用,可以逐步进入该行。

(Pdb) s
--Call--
>c:\Python\Python361\pdb_example2.py(3)squar()
-> def squar(x, y):

这是对函数的调用。如果您想要了解您所处代码位置的概览,请尝试 l −

(Pdb) l
1 import pdb
2
3 def squar(x, y):
4 -> out_squared = x^2 + y^2
5
6 return out_squared
7
8 if __name__ == "__main__":
9 pdb.set_trace()
10 print (squar(4, 5))
[EOF]
(Pdb)

您可以点击 n 跳到下一行。此时,您处于 out_squared 方法中,并且可以访问函数内部声明的变量,例如 x 和 y。

(Pdb) x
4
(Pdb) y
5
(Pdb) x^2
6
(Pdb) y^2
7
(Pdb) x**2
16
(Pdb) y**2
25
(Pdb)

所以我们可以看到 ^ 运算符不是我们想要的,而我们需要使用 ** 运算符来进行平方。

通过这种方式,我们可以在函数/方法内部调试我们的程序。

Logging

自 Python 2.3 版本以来,logging 模块就已成为 Python 标准库的一部分。由于它是一个内置模块,所有 Python 模块都可以参与日志记录,以便我们的应用程序日志可以包含您自己的消息,以及来自第三方模块的消息。它提供了大量的灵活性与功能。

Benefits of Logging

  1. Diagnostic logging − 它记录与应用程序操作相关的事件。

  2. Audit logging − 它记录用于业务分析的事件。

消息以“严重性”级别进行编写和记录。

  1. DEBUG (debug()) − 用于开发的诊断消息。

  2. INFO (info()) − 标准的“进度”消息。

  3. WARNING (warning()) − 检测到一个不严重的问题。

  4. ERROR (error()) − 遇到一个错误,可能很严重。

  5. CRITICAL (critical()) − 通常是一个致命错误(程序停止)。

我们来看一下下面的简单程序,

import logging

logging.basicConfig(level=logging.INFO)

logging.debug('this message will be ignored') # This will not print
logging.info('This should be logged') # it'll print
logging.warning('And this, too') # It'll print

上面我们正在记录严重性级别的消息。首先,我们导入该模块,调用 basicConfig 并设置日志记录级别。我们在上面设置的级别为 INFO。然后,我们有三个不同的语句:debug 语句、info 语句和 warning 语句。

Output of logging1.py

INFO:root:This should be logged
WARNING:root:And this, too

由于 info 语句在 debug 语句之后,我们无法看到 debug 消息。要也在输出终端中获取 debug 语句,我们需要更改的只是 basicConfig 的级别。

logging.basicConfig(level = logging.DEBUG)

然后,我们在输出中可以看到,

DEBUG:root:this message will be ignored
INFO:root:This should be logged
WARNING:root:And this, too

另外,默认行为表示,如果我们未设置任何日志记录级别,则为 warning。只需注释掉上述程序的第二行并运行该代码即可。

#logging.basicConfig(level = logging.DEBUG)

Output

WARNING:root:And this, too

Python内置日志级别实际上是整数。

>>> import logging
>>>
>>> logging.DEBUG
10
>>> logging.CRITICAL
50
>>> logging.WARNING
30
>>> logging.INFO
20
>>> logging.ERROR
40
>>>

我们也可以将日志消息保存到文件里。

logging.basicConfig(level = logging.DEBUG, filename = 'logging.log')

现在,所有日志消息都将进入当前工作目录中的文件(logging.log),而不是屏幕上。这是一个更好的方法,因为它让我们对得到的消息进行后期分析。

我们还可以用日志消息设置日期戳。

logging.basicConfig(level=logging.DEBUG, format = '%(asctime)s %(levelname)s:%(message)s')

输出将类似于,

2018-03-08 19:30:00,066 DEBUG:this message will be ignored
2018-03-08 19:30:00,176 INFO:This should be logged
2018-03-08 19:30:00,201 WARNING:And this, too

Benchmarking

基准测试或分析基本上是测试你的代码执行的速度有多快,以及瓶颈在哪里?这样做的主要原因是进行优化。

timeit

Python带有称为timeit的内置模块。你可以用它来计时小的代码段。timeit模块使用平台特定的时间函数,以便你获得尽可能最准确的时间。

所以,它允许我们比较每一项代码的两个传输值,然后优化脚本以提供更好的性能。

timeit模块有一个命令行界面,但它也可以导入。

有两种调用脚本的方法。让我们首先使用脚本,为此运行以下代码并查看输出。

import timeit
print ( 'by index: ', timeit.timeit(stmt = "mydict['c']", setup = "mydict = {'a':5, 'b':10, 'c':15}", number = 1000000))
print ( 'by get: ', timeit.timeit(stmt = 'mydict.get("c")', setup = 'mydict = {"a":5, "b":10, "c":15}', number = 1000000))

Output

by index: 0.1809192126703489
by get: 0.6088525265034692

在上面我们使用了两种不同的方法,即通过下标和get来访问字典键值。我们执行语句100万次,因为它对于非常小的数据执行的速度太快。现在,我们可以看到与get相比,索引访问快得多。我们可以多次运行代码,执行时间会有细微的变化,以获得更好的理解。

另一种方法是在命令行中运行以上测试。我们开始吧,

c:\Python\Python361>Python -m timeit -n 1000000 -s "mydict = {'a': 5, 'b':10, 'c':15}" "mydict['c']"
1000000 loops, best of 3: 0.187 usec per loop

c:\Python\Python361>Python -m timeit -n 1000000 -s "mydict = {'a': 5, 'b':10, 'c':15}" "mydict.get('c')"
1000000 loops, best of 3: 0.659 usec per loop

上述输出可能因你的系统硬件和你系统中当前正在运行的所有应用程序而异。

下面我们可以使用timeit模块,如果我们想调用一个函数。因为我们可以在函数中添加多个语句进行测试。

import timeit

def testme(this_dict, key):
   return this_dict[key]

print (timeit.timeit("testme(mydict, key)", setup = "from __main__ import testme; mydict = {'a':9, 'b':18, 'c':27}; key = 'c'", number = 1000000))

Output

0.7713474590139164

Object Oriented Python - Libraries

Requests − Python Requests Module

Requests是Python的一个模块,它是一个优雅而简单的Python HTTP库。有了它,你可以发送各种HTTP请求。通过这个库,我们可以添加头信息、表单数据、多部分文件和参数,以及访问响应数据。

由于Requests不是一个内置模块,因此我们首先需要安装它。

你可以通过在终端中运行以下命令来安装它:

pip install requests

安装模块后,你可以通过在Python shell中键入以下命令来验证安装是否成功。

import requests

如果安装成功,你将不会看到任何错误消息。

Making a GET Request

作为示例,我们将使用“pokeapi”

pokeapi

Output −

pokeapi output

Making POST Requests

requests 库方法适用于所有当前使用的 HTTP 动词。如果您想对 API 终结点发出一个简单的 POST 请求,则可以这样做 −

req = requests.post(‘http://api/user’, data = None, json = None)

与我们之前的 GET 请求相同,但这具有两个额外的关键字参数 −

  1. 可以填充词典、文件或将在 POST 请求的 HTTP 主体中传递的字节的数据。

  2. json 可以填充一个 json 对象,该对象将同时传递到 HTTP 请求的正文中。

Pandas: Python Library Pandas

Pandas 是一个开源 Python 库,提供高性能的数据操作和分析工具,并使用其强大的数据结构。Pandas 是数据科学中最广泛使用的 Python 库之一。它主要用于数据整理,原因有很多:功能强大且灵活。

基于 Numpy 包,关键数据结构称为 DataFrame。这些数据框架使我们能够存储和操作表格数据,其中包括观测行和变量列。

有几种创建 DataFrame 的方法。一种方法是使用词典。例如 −

dataframe

Output

dataframe output

从输出中,我们可以看到新的 brics DataFrame,Pandas 已为每个国家分配了一个键,从数值 0 到 4。

如果不给出 0 到 4 的索引值,而希望有不同的索引值(例如,两个字母的国家代码),也可以轻松地做到 −

将下面的代码添加到上面的代码中,得到

brics.index = ['BR', 'RU', 'IN', 'CH', 'SA']

Output

dataframe brics index

Indexing DataFrames

indexing dataframes

Output

indexing dataframes output

Pygame

Pygame 是一个开源且跨平台的库,用于制作包括游戏在内的多媒体应用程序。它包含计算机图形和声音库,旨在与 Python 编程语言配合使用。您可以使用 Pygame 开发很多酷炫的游戏。

Overview

Pygame 由多个模块组成,每个模块处理一组特定任务。例如,display 模块处理显示窗口和屏幕,draw 模块提供绘制形状的函数,key 模块处理键盘。这些只是库中的几个模块。

Pygame 库的主页位于 https://www.pygame.org/news

要制作 Pygame 应用程序,请按照以下步骤:

导入 Pygame 库

import pygame

初始化 Pygame 库

pygame.init()

创建一个窗口。

screen = Pygame.display.set_mode((560,480))
Pygame.display.set_caption(‘First Pygame Game’)

Initialize game objects

在这一步,我们会加载图片,加载声音,进行对象定位,设置一些状态变量等。

Start the game loop.

它只是一个循环,处理事件,检查输入,移动对象并绘制它们。循环的每次迭代称为一次帧。

将以上所有逻辑及入到下方程序中,

Pygame_script.py

pygame script

Output

pygame script output

Beautiful Soup: Web Scraping with Beautiful Soup

网络抓取背后的总想法是获取存在于网站上的数据,并将其转换为可用于分析的格式。

它是一个用于从 HTML 或 XML 文件中提取数据的 Python 库。凭借您最喜欢的解析器,它提供了解析、搜索和修改解析树的惯用方法。

由于 BeautifulSoup 不是内置库,因此我们需要在尝试使用它之前将其安装。若要安装 BeautifulSoup,请运行以下命令:

$ apt-get install Python-bs4 # For Linux and Python2
$ apt-get install Python3-bs4 # for Linux based system and Python3.

$ easy_install beautifulsoup4 # For windows machine,
Or
$ pip instal beatifulsoup4 # For window machine

安装完成后,我们就可以运行一些示例并详细探索 Beautifulsoup,

beautifulsoup in details

Output

beautifulsoup in details output

以下是一些导航该数据结构的简单方法 −

data structure

一项常见任务是从页面 <a> 标签中提取所有 URL −

urls

另一项常见任务是从页面中提取所有文本 −

text from page