强哥的博客

菜鸟成长记

了解Python 二

Python是什么?

Python是面向对象,高级语言,解释,动态和多用途编程语言。Python易于学习,而且功能强大,功能多样的脚本语言使其对应用程序开发具有吸引力。
Python的语法和动态类型具有其解释性质,使其成为许多领域的脚本编写和快速应用程序开发的理想语言。

Python支持多种编程模式,包括面向对象编程,命令式和函数式编程或过程式编程。

Python几乎无所不能,一些常用的开发领域,如Web编程。这就是为什么它被称为多用途,因为它可以用于网络,企业,3D CAD等软件和系统开发。

在Python中,不需要使用数据类型来声明变量,因为它是动态类型的,所以可以写一个如 a=10 来声明一个变量a中的值是一个整数类型。

Python使开发和调试快速,因为在python开发中没有包含编译步骤,并且编辑 <-> 测试 <-> 调试循环使用代码开发效率非常高。

Python是一种高级,解释,交互和面向对象的脚本语言。 Python被设计为高度可读性。 它使用英语关键字,而其他语言使用标点符号。它的语法结构比其他语言少。

  • Python是解释型语言 Python代码在解释器中运行时处理,执行前不需要编译程序。 这与PERL和PHP类似。
  • Python是交动的 在Python提示符下面直接和解释器进行交互来编写程序。
  • Python是面向对象的 Python支持面向对象的风格或编程技术,将代码封装在对象内。
  • Python是一门初学者的语言 Python是初学者程序员的伟大语言,并支持从简单的文本处理到WWW浏览器到游戏的各种应用程序的开发。

Python可以开发哪些程序?

Python作为一个整体可以用于任何软件开发领域。下面来看看Python可以应用在哪些领域的开发。如下所列 -

1.基于控制台的应用程序

Python可用于开发基于控制台的应用程序。 例如:IPython。

2.基于音频或视频的应用程序

Python在多媒体部分开发,证明是非常方便的。 一些成功的应用是:TimPlayer,cplay等。

3.3D CAD应用程序

Fandango是一个真正使用Python编写的应用程序,提供CAD的全部功能。

4.Web应用程序

Python也可以用于开发基于Web的应用程序。 一些重要的开发案例是:PythonWikiEngines,Pocoo,PythonBlogSoftware等,如国内的成功应用案例有:豆瓣,知乎等。

5.企业级应用

Python可用于创建可在企业或组织中使用的应用程序。一些实时应用程序是:OpenErp,Tryton,Picalo等。

6.图像应用

使用Python可以开发图像应用程序。 开发的应用有:VPython,Gogh,imgSeek等

Python安装和环境配置

Python 3适用于Windows,Mac OS和大多数Linux操作系统。即使Python 2目前可用于许多其他操作系统,有部分系统Python 3还没有提供支持或者支持了但被它们在系统上删除了,只保留旧的Python 2版本。

在本教程中,我们重点讲解如何在 Windows 10 和 Ubuntu 系统上安装 Python 3 的最新版本(当前新版本:Python 3.6.1)。

在Windows 10上安装Python 3

最新版本的Python 3(Python 3.5.1)的二进制文件可从Python官方网站的下载页面: http://www.python.org/downloads/windows/ 下载,可以使用以下不同的安装选项 -

这里写图片描述

这里选择: 下载Windows x86-64 executable installer 下载。下载完成后,双击 python-3.6.1-amd64.exe 可执行文件。

第一步:双击 python-3.6.1-amd64.exe 可执行文件,如下所示 -

这里写图片描述
第二步:选择“Cusomize installation“,如下所示 -

这里写图片描述

第三步:选择“Next>“,这里选择安装在 D:\Program Files\Python36,如下所示 -

这里写图片描述

第四步:开始安装 “Install“ ,如下 -

这里写图片描述

第五步:安装完成后选择关闭(Close),如下所示 -

这里写图片描述

测试安装结果

由于我们在安装的第一步中,已经选择了“Add Python 3.6 to PATH”了,所以这里不需要单独去设置环境变量了。如果没有选择此项,则应该需要将Python 3.6添加到环境变量。
假设您已经按照上面的步骤来安装完成,现在打开命令提示符,并在其中输入 python,然后回车 -

这里写图片描述

到此,在 Windows 10 系统上安装 Python 3.6 已经完成了。

在Ubuntu上安装Python 3

首先来看看当 Ubuntu 系统上安装的是什么版本的 Python,在终端上输入 python,如下所示 -

yiibai@ubuntu:~$ python -version
The program 'python' can be found in the following packages:
 * python-minimal
 * python3
Try: sudo apt install <selected package>
yiibai@ubuntu:~$

在上面显示结果中,还没有安装 Python 。

第一种情况:
如果使用的是Ubuntu 14.04或16.04,则可以使用J Fernyhough的PPA: http://launchpad.net/~jonathonf/+archive/ubuntu/python-3.6 来安装Python 3.6:

sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt-get update
sudo apt-get install python3.6

第二种情况:
如果使用的是Ubuntu 16.10或17.04,则Python 3.6位于Universe存储库中,直接升级 apt-get,然后再安装即可 -

sudo apt-get update
sudo apt-get install python3.6

现在,查看 Ubuntu 的当前版本 -

yiibai@ubuntu:~$ sudo lsb_release -a
[sudo] password for yiibai:
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.1 LTS
Release:        16.04
Codename:       xenial
yiibai@ubuntu:~$

提示:Ubuntu无法找到add-apt-repository问题的解决方法,执行安装命令:apt-get install python-software-properties,除此之外还要安装 apt-get install software-properties-common,然后就能用add-apt-repository了。

根据上面显示的系统信息,系统版本是:Ubuntu 16.04.1 LTS,所以属于第一种情况安装 Python 3.6,所以完整的安装步骤如下 -

sudo apt-get install python-software-properties
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt-get update
sudo apt-get install python3.6

注意,上面命令执行可能会出现中断或错误的情况,可尝试多执行几次。

当上面命令成功执行完成后,默认情况下,它也会安装了一个 Python 2.7,在命令行提示符下输入:python,那么它使用的是 Python 2.7,如果要使用 Python 3.6,那么可以直接输入:python3.6,验证安装结果如下所示 -

这里写图片描述
从源代码编译安装 Python 3.6
或者,如果您有时间和精力,也可以尝试从源代码编译来安装 Python 3.6 。源代码下载地址:http://www.python.org/ftp/python/3.6.1/

首先,需要使用以下命令安装一些构建依赖项。

sudo apt install build-essential checkinstall

sudo apt install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev

然后,从python.org下载Python 3.6源代码。

wget http://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz

接下来,解压缩tarball。

tar xvf Python-3.6.0.tar.xz

现在cd进入源目录,配置构建环境并进行安装。

cd Python-3.6.0/

./configure

sudo make altinstall

使altinstall命令跳过创建符号链接,所以/usr/bin/python仍然指向旧版本的Python,保证Ubuntu系统将不会中断。

完成完成后,可以通过键入以下命令来使用Python 3.6:

$ python3.6

以下是所有可用命令行选项的列表 -

编号 选项 说明
1 -d 提供调试输出
2 -O 生成优化的字节码(结果为.pyo文件)
3 -S 启动时不要运行导入站点来寻找Python路径
4 -v 详细输出(import语句的详细跟踪)
5 -X 禁用基于类的内置异常(仅使用字符串); 从版本1.6开始已经过时了
6 -c cmd 运行Python脚本作为cmd字符串发送
7 file 从给定运行的Python脚本文件

命令行脚本

通过在应用程序中调用解释器,可以在命令行中执行Python脚本,如以下示例所示。

$python  script.py          # Unix/Linux

or 

python% script.py           # Unix/Linux

or 

C:>python script.py         # Windows/DOS

注意 - 确保文件权限模式允许执行。

集成开发环境

如果您的系统上支持Python的GUI应用程序,也可以从图形用户界面(GUI)环境运行Python。

Unix - IDLE是第一个用于Python的Unix IDE。

Windows - PythonWin是Python的第一个Windows图形用户界面,是具有GUI的IDE。

Macintosh - Macintosh版本的Python以及IDLE IDE可从主网站获取,可作为MacBinary或BinHex’d文件下载。

如果您无法正确设置环境,则可以通过向系统管理员寻求帮助。确保Python环境设置正确,以正常工作。

注 - 后续章节中给出的所有示例都是使用Windows 7和Ubuntu Linux上提供的Python 3.6.1版本来执行。




Python面向对象(类和对象)

自从存在以来,Python一直是面向对象的语言。 因此,创建和使用类和对象是非常容易的。 本章将学习如何使用Python面向对象编程。

如果您以前没有面向对象(OO)编程的经验,可能需要查阅介绍面向对象(OO)编程课程或至少学习一些有关教程,以便掌握基本概念。

下面是面向对象编程(OOP)的一个小介绍,以帮助您快速入门学习 -

OOP术语概述

  • 类 -
    用于定义表示用户定义对象的一组属性的原型。属性是通过点符号访问的数据成员(类变量和实例变量)和方法。

  • 类变量
    由类的所有实例共享的变量。 类变量在类中定义,但在类的任何方法之外。 类变量不像实例变量那样频繁使用。

  • 数据成员 -
    保存与类及其对象相关联的数据的类变量或实例变量。

  • 函数重载 -
    将多个行为分配给特定函数。 执行的操作因涉及的对象或参数的类型而异。

  • 实例变量 -
    在方法中定义并仅属于类的当前实例的变量。

  • 继承 -
    将类的特征传递给从其派生的其他类。

  • 实例 -
    某个类的单个对象。 例如,对象obj属于Circle类,它是Circle类的实例。

  • 实例化 -
    创建类的实例。

  • 方法 -
    在类定义中定义的一种特殊类型的函数。

  • 对象 -
    由其类定义的数据结构的唯一实例。对象包括数据成员(类变量和实例变量)和方法。

  • 运算符重载 -
    将多个函数分配给特定的运算符。

1.创建类

class语句创建一个新的类定义。 类的名称紧跟在class关键字之后,在类的名称之后紧跟冒号,如下 -

class ClassName:
   'Optional class documentation string'
   class_suite
  • 该类有一个文档字符串,可以通过ClassName.doc访问。
  • class_suite由定义类成员,数据属性和函数的所有组件语句组成。

示例

以下是一个简单的Python类的例子 -

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1

   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)
  • 变量empCount是一个类变量,其值在此类中的所有实例之间共享。 这可以从类或类之外的Employee.empCount访问。
  • 第一个方法init ()是一种特殊的方法,当创建此类的新实例时,该方法称为Python构造函数或初始化方法。

声明其他类方法,如正常函数,但每个方法的第一个参数是self。 Python将self参数添加到列表中; 调用方法时不需要包含它。

2.创建实例对象

要创建类的实例,可以使用类名调用该类,并传递其init方法接受的任何参数。

## This would create first object of Employee class
emp1 = Employee("Maxsu", 2000)
## This would create second object of Employee class
emp2 = Employee("Kobe", 5000)

3.访问属性

可以使用带有对象的点(.)运算符来访问对象的属性。 类变量将使用类名访问如下 -

emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)

现在把所有的概念放在一起 -

#!/usr/bin/python3

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1

   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)


#This would create first object of Employee class"
emp1 = Employee("Maxsu", 2000)
#This would create second object of Employee class"
emp2 = Employee("Kobe", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)

当执行上述代码时,会产生以下结果 -

Name :  Maxsu ,Salary:  2000
Name :  Kobe ,Salary:  5000
Total Employee 2

可以随时添加,删除或修改类和对象的属性 -

emp1.salary = 7000  # Add an 'salary' attribute.
emp1.name = 'xyz'  # Modify 'age' attribute.
del emp1.salary  # Delete 'age' attribute.

如果不是使用普通语句访问属性,可以使用以下函数 -

  • getattr(obj,name [,default]) - 访问对象的属性。
  • hasattr(obj,name) - 检查属性是否存在。
  • setattr(obj,name,value) - 设置一个属性。如果属性不存在,那么它将被创建。
  • delattr(obj,name) - 删除一个属性。

下面是一此使用示例 -

hasattr(emp1, 'salary')    # Returns true if 'salary' attribute exists
getattr(emp1, 'salary')    # Returns value of 'salary' attribute
setattr(emp1, 'salary', 7000) # Set attribute 'salary' at 7000
delattr(emp1, 'salary')    # Delete attribute 'salary'

3.内置类属性

每个Python类保持以下内置属性,并且可以像任何其他属性一样使用点运算符访问它们 -

  • dict - 包含该类的命名空间的字典。
  • doc - 类文档字符串或无,如果未定义。
  • name - 类名。
  • module - 定义类的模块名称。此属性在交互模式下的值为“main”。
  • bases - 一个包含基类的空元组,按照它们在基类列表中出现的顺序。

对于上述类,尝试访问所有这些属性 -

#!/usr/bin/python3

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1

   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)

emp1 = Employee("Maxsu", 2000)
emp2 = Employee("Bryant", 5000)
print ("Employee.__doc__:", Employee.__doc__)
print ("Employee.__name__:", Employee.__name__)
print ("Employee.__module__:", Employee.__module__)
print ("Employee.__bases__:", Employee.__bases__)
print ("Employee.__dict__:", Employee.__dict__ )

当执行上述代码时,会产生以下结果 -

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {
   'displayCount': <function Employee.displayCount at 0x0160D2B8>, 
   '__module__': '__main__', '__doc__': 'Common base class for all employees', 
   'empCount': 2, '__init__': 
   <function Employee.__init__ at 0x0124F810>, 'displayEmployee': 
   <function Employee.displayEmployee at 0x0160D300>,
   '__weakref__': 
   <attribute '__weakref__' of 'Employee' objects>, '__dict__': 
   <attribute '__dict__' of 'Employee' objects>
}

4.销毁对象(垃圾收集)

Python自动删除不需要的对象(内置类型或类实例)以释放内存空间。 Python定期回收不再使用的内存块的过程称为垃圾收集。

Python的垃圾收集器在程序执行期间运行,当对象的引用计数达到零时触发。 对象的引用计数随着指向它的别名数量而变化。

当对象的引用计数被分配一个新名称或放置在容器(列表,元组或字典)中时,它的引用计数会增加。 当用del删除对象的引用计数时,引用计数减少,其引用被重新分配,或者其引用超出范围。 当对象的引用计数达到零时,Python会自动收集它。

a = 40      # Create object <40>
b = a       # Increase ref. count  of <40> 
c = [b]     # Increase ref. count  of <40> 

del a       # Decrease ref. count  of <40>
b = 100     # Decrease ref. count  of <40> 
c[0] = -1   # Decrease ref. count  of <40>

通常情况下,垃圾回收器会销毁孤立的实例并回收其空间。 但是,类可以实现调用析构函数的特殊方法del(),该方法在实例即将被销毁时被调用。 此方法可能用于清理实例使用的任何非内存资源。

示例

这个del()析构函数打印要被销毁的实例的类名 -

#!/usr/bin/python3

class Point:
   def __init__( self, x=0, y=0):
      self.x = x
      self.y = y
   def __del__(self):
      class_name = self.__class__.__name__
      print (class_name, "destroyed")

pt1 = Point()
pt2 = pt1
pt3 = pt1
print (id(pt1), id(pt2), id(pt3));   # prints the ids of the obejcts
del pt1
del pt2
del pt3

当执行上述代码时,会产生以下结果 -

3083401324 3083401324 3083401324
Point destroyed

注意 - 理想情况下,应该在单独的文件中定义类,然后使用import语句将其导入主程序文件。

在上面的例子中,假定Point类的定义包含在point.py中,并且其中没有其他可执行代码。

#!/usr/bin/python3
import point
p1 = point.Point()

5.类继承

使用类继承不用从头开始构建代码,可以通过在新类名后面的括号中列出父类来从一个预先存在的类派生它来创建一个类。

子类继承其父类的属性,可以像子类中一样定义和使用它们。子类也可以从父类代替代数据成员和方法。

语法

派生类被声明为很像它们的父类; 然而,继承的基类的列表在类名之后给出 -

class SubClassName (ParentClass1[, ParentClass2, ...]):
   'Optional class documentation string'
   class_suite

示例

#!/usr/bin/python3

class Parent:        # define parent class
   parentAttr = 100
   def __init__(self):
      print ("Calling parent constructor")

   def parentMethod(self):
      print ('Calling parent method')

   def setAttr(self, attr):
      Parent.parentAttr = attr

   def getAttr(self):
      print ("Parent attribute :", Parent.parentAttr)

class Child(Parent): # define child class
   def __init__(self):
      print ("Calling child constructor")

   def childMethod(self):
      print ('Calling child method')

c = Child()          # instance of child
c.childMethod()      # child calls its method
c.parentMethod()     # calls parent's method
c.setAttr(200)       # again call parent's method
c.getAttr()          # again call parent's method

当执行上述代码时,会产生以下结果 -

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

以类似的方式,可以从多个父类来构建一个新的类,如下所示:

class A:        # define your class A
.....

class B:         # define your calss B
.....

class C(A, B):   # subclass of A and B
.....

可以使用issubclass()或isinstance()函数来检查两个类和实例之间的关系。

  • issubclass(sub,sup)布尔函数如果给定的子类sub确实是超类sup的子类返回True。
  • isinstance(obj,Class)布尔函数如果obj是类Class的一个实例,或者是类的一个子类的实例则返回True。

重载方法

可以随时重载父类的方法。 重载父方法的一个原因是:您可能希望在子类中使用特殊或不同的方法功能。

示例

#!/usr/bin/python3

class Parent:        # define parent class
   def myMethod(self):
      print ('Calling parent method')

class Child(Parent): # define child class
   def myMethod(self):
      print ('Calling child method')

c = Child()          # instance of child
c.myMethod()         # child calls overridden method

当执行上述代码时,会产生以下结果 -

Calling child method

基本重载方法

下表列出了可以在自己的类中覆盖的一些通用方法 -

编号 方法 描述 调用示例
1 init ( self [,args…] ) 构造函数(带任意可选参数) obj = className(args)
2 del( self ) 析构函数,删除一个对象 del obj
3 repr( self ) 可评估求值的字符串表示 repr(obj)
4 str( self ) 可打印的字符串表示 str(obj)
5 cmp ( self, x ) 对象比较 cmp(obj, x)

6.重载运算符

假设已经创建了一个Vector类来表示二维向量。当使用加号(+)运算符执行运算时,它们会发生什么? 很可能Python理解不了你想要做什么。

但是,可以在类中定义add方法来执行向量加法,然后将按照期望行为那样执行加法运算 -

示例

#!/usr/bin/python3

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b

   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)

   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

当执行上述代码时,会产生以下结果 -

Vector(7,8)

7.数据隐藏

对象的属性在类定义之外可能或不可见。需要使用双下划线前缀命名属性,然后这些属性将不会直接对外部可见。

示例

#!/usr/bin/python3

class JustCounter:
   __secretCount = 0

   def count(self):
      self.__secretCount += 1
      print (self.__secretCount)

counter = JustCounter()
counter.count()
counter.count()
print (counter.__secretCount)

当执行上述代码时,会产生以下结果 -

1
2
Traceback (most recent call last):
   File "test.py", line 12, in <module>
      print counter.__secretCount
AttributeError: JustCounter instance has no attribute '__secretCount'

Python通过内部更改名称来包含类名称来保护这些成员。 可以访问object._className__attrName等属性。如果将最后一行替换为以下,那么它适用于 -

.........................
print (counter._JustCounter__secretCount)

当执行上述代码时,会产生以下结果 -

1
2
2

Python构造函数

构造函数是一种特殊类型的方法(函数),它在类的实例化对象时被调用。 构造函数通常用于初始化(赋值)给实例变量。 构造函数还验证有足够的资源来使对象执行任何启动任务。

创建一个构造函数

构造函数是以双下划线()开头的类函数。构造函数的名称是__init()。

创建对象时,如果需要,构造函数可以接受参数。当创建没有构造函数的类时,Python会自动创建一个不执行任何操作的默认构造函数。

每个类必须有一个构造函数,即使它只依赖于默认构造函数。

举一个例子:

创建一个名为ComplexNumber的类,它有两个函数init()函数来初始化变量,并且有一个getData()方法用来显示数字。

看这个例子:

#!/usr/bin/python3
#coding=utf-8

class ComplexNumber:

    def __init__(self, r = 0, i = 0):
        """"初始化方法"""
        self.real = r 
        self.imag = i 

    def getData(self):
        print("{0}+{1}j".format(self.real, self.imag))

if __name__ == '__main__':
    c = ComplexNumber(5, 6)
    c.getData()

执行上面代码,得到以下结果 -

5+6j

可以为对象创建一个新属性,并在定义值时进行读取。但是不能为已创建的对象创建属性。

看这个例子:

#!/usr/bin/python3
#coding=utf-8

class ComplexNumber:

    def __init__(self, r = 0, i = 0):
        """"初始化方法"""
        self.real = r 
        self.imag = i 

    def getData(self):
        print("{0}+{1}j".format(self.real, self.imag))

if __name__ == '__main__':
    c = ComplexNumber(5, 6)
    c.getData()

    c2 = ComplexNumber(10, 20)
    # 试着赋值给一个未定义的属性
    c2.attr = 120
    print("c2 = > ", c2.attr)

    print("c.attr => ", c.attr)

执行上面代码,得到以下结果 -

5+6j
c2 = >  120
Traceback (most recent call last):
  File "D:\test.py", line 23, in <module>
    print("c.attr => ", c.attr)
AttributeError: 'ComplexNumber' object has no attribute 'attr'

Python继承

什么是继承?

继承用于指定一个类将从其父类获取其大部分或全部功能。 它是面向对象编程的一个特征。 这是一个非常强大的功能,方便用户对现有类进行几个或多个修改来创建一个新的类。新类称为子类或派生类,从其继承属性的主类称为基类或父类。

子类或派生类继承父类的功能,向其添加新功能。 它有助于代码的可重用性。

下图表示:

这里写图片描述
这里写图片描述

语法-1

class DerivedClassName(BaseClassName):  
    <statement-1>  
    .  
    .  
    .  
    <statement-N>

语法-2

class DerivedClassName(modulename.BaseClassName):  
    <statement-1>  
    .  
    .  
    .  
    <statement-N>

参数说明

必须在包含派生类定义的范围中定义名称BaseClassName。还可以使用其他任意表达式代替基类名称。 当在另一个模块中定义基类时要指定模块的名称。

Python继承示例

我们来看一个简单的python继承示例,在这个示例中使用两个类:Animal和Dog。Animal是父类或基类,Dog是Animal的子类。

在这里,在Animal类中定义了eat()方法,Dog类中定义了bark()方法。 在这个例子中,我们创建Dog类的实例,并且仅通过子类的实例调用eat()和bark()方法。 由于父属性和行为自动继承到子对象,所以通过子实例也可以调用父类和子类的方法。

class Animal:   
    def eat(self):  
      print 'Eating...'  
class Dog(Animal):     
   def bark(self):  
      print 'Barking...'  

d=Dog()  
d.eat()  
d.bark()

执行上面代码,得到以下结果 -

Eating...  
Barking...

Python多重继承

在本文中,您将了解Python中的多重继承以及如何在程序中使用它。还将了解多级继承和方法解析顺序。

这里写图片描述

与C++一样,一个类可以从Python中的多个基类派生出来。这被称为多重继承。

在多重继承中,所有基类的特征都被继承到派生类中。多重继承的语法类似于单继承。

Python多重继承示例

class Base1:
    pass

class Base2:
    pass

class MultiDerived(Base1, Base2):
    pass

这里,MultiDerived派生自Base1和Base2类。

这里写图片描述

MultiDerived类从Base1和Base2继承。

Python中的多层继承

另一方面,我们也可以继承一个派生类的形式。这被称为多级继承。 它可以在Python中有任何的深度(层级)。在多级继承中,基类和派生类的特性被继承到新的派生类中。
下面给出了具有相应可视化的示例。

class Base:
    pass

class Derived1(Base):
    pass

class Derived2(Derived1):
    pass

这里,Derived1派生自Base,Derived2派生自Derived1。

这里写图片描述

Python中的方法解析顺序

Python中的每个类都派生自类:object。它是Python中最基础的类型。

所以在技术上,所有其他类,无论是内置还是用户定义,都是派生类,所有对象都是对象类的实例。

# Output: True
print(issubclass(list,object))

# Output: True
print(isinstance(5.5,object))

# Output: True
print(isinstance("Hello",object))

在多继承方案中,在当前类中首先搜索任何指定的属性。如果没有找到,搜索继续进入父类,深度优先,再到左右的方式,而不需要搜索相同的类两次。

所以在MultiDerived类的上面的例子中,搜索顺序是[MultiDerived,Base1,Base2,object]。 此顺序也称为MultiDerived类的线性化,用于查找此顺序的一组规则称为方法解析顺序(MRO)。

MRO必须防止本地优先排序,并提供单调性。它确保一个类总是出现在其父类之前,并且在多个父类的情况下,该顺序与基类的元组相同。

一个类的MRO可以被看作是mro属性或者mro()方法。前者返回一个元组,而后者返回一个列表。

>>> MultiDerived.__mro__
(<class '__main__.MultiDerived'>,
 <class '__main__.Base1'>,
 <class '__main__.Base2'>,
 <class 'object'>)

>>> MultiDerived.mro()
[<class '__main__.MultiDerived'>,
 <class '__main__.Base1'>,
 <class '__main__.Base2'>,
 <class 'object'>]

这里有一个更复杂的多重继承示例及其可视化图型。

这里写图片描述

class X: pass
class Y: pass
class Z: pass

class A(X,Y): pass
class B(Y,Z): pass

class M(B,A,Z): pass

# Output:
# [<class '__main__.M'>, <class '__main__.B'>,
# <class '__main__.A'>, <class '__main__.X'>,
# <class '__main__.Y'>, <class '__main__.Z'>,
# <class 'object'>]

print(M.mro())

参考这一点,进一步讨论MRO并了解实际算法如何计算。

Python操作符重载

可以根据所使用的操作数更改Python中运算符的含义。这种做法被称为运算符重载。

Python操作系统适用于内置类。 但同一运算符的行为在不同的类型有所不同。 例如,+运算符将对两个数字执行算术加法,合并两个列表并连接两个字符串。

Python中的这个功能,允许相同的操作符根据上下文的不同,其含义称为运算符重载。

那么当将它们与用户定义的类的对象一起使用时会发生什么? 考虑下面的类,它试图模拟二维坐标系中的一个点。

class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

现在,运行代码,尝试在Python shell中添加两点。

>>> p1 = Point(2,3)
>>> p2 = Point(-1,2)
>>> p1 + p2
Traceback (most recent call last):
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'

Python中的特殊功能

以双下划线_ 开头的类函数在Python中称为特殊函数。 这是因为,它们是有特殊含义。 上面定义的 _ init__()函数是其中之一。 每次创建该类的新对象时都会调用它。 Python中有很多特殊功能。

使用特殊功能,可以使类与内置函数兼容。

>>> p1 = Point(2,3)
>>> print(p1)
<__main__.Point object at 0x00000000031F8CC0>

但是如果打印不好或不够美观。可以在类中定义str()方法,可以控制它如何打印。 所以,把它添加到类中,如下代码 -

class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0},{1})".format(self.x,self.y)

现在再试一次调用print()函数。

>>> p1 = Point(2,3)
>>> print(p1)
(2,3)

当使用内置函数str()或format()时,调用同样的方法。

>>> str(p1)
'(2,3)'

>>> format(p1)
'(2,3)'

所以,当执行str(p1)或format(p1),Python在内部执行p1._ str_()。

在Python中重载+运算符

要重载+号,需要在类中实现add()函数。可以在这个函数里面做任何喜欢的事情。 但是返回Point对象的坐标之和是最合理的。

class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0},{1})".format(self.x,self.y)

    def __add__(self,other):
        x = self.x + other.x
        y = self.y + other.y
        return Point(x,y)

现在让我们再试一次运行上面的代码 -

>>> p1 = Point(2,3)
>>> p2 = Point(-1,2)
>>> print(p1 + p2)
(1,5)

实际发生的是,当执行p1 + p2语句时,Python将调用p1._ add_(p2),之后是Point.add(p1,p2)。 同样,也可以重载其他运算符。需要实现的特殊功能列在下面。

Python中的运算符重载特殊函数 -

运算符 表达式 内置函数
加法 p1 + p2 p1._ add_(p2)
减法 p1 - p2 p1._ sub_(p2)
乘法 p1 * p2 p1.mul(p2)
次幂 p1 ** p2 p1._ pow_(p2)
除法 p1 / p2 p1._ truediv_(p2)
地板除法 p1 // p2 p1._ floordiv_(p2)
模 (modulo) p1 % p2 p1._ mod_(p2)
按位左移 p1 << p2 p1._ lshift_(p2)
按位右移 p1 >> p2 p1._ rshift_(p2)
按位AND p1 & p p1._ and_(p2)
按位OR p1 or p2 p1 ._ or_(p2)
按位XOR p1 ^ p2 p1._ xor_(p2)
按位NOT `~p1 p1.invert() `

在Python中重载比较运算符

Python不会限制操作符重载算术运算符。也可以重载比较运算符。

假设想在Point类中实现小于符号<比较运算。

比较这些来自原点的数值,并为此返回结果。 可以实现如下。

class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0},{1})".format(self.x,self.y)

    def __lt__(self,other):
        self_mag = (self.x ** 2) + (self.y ** 2)
        other_mag = (other.x ** 2) + (other.y ** 2)
        return self_mag < other_mag

在Python shell中尝试这些示例运行。

>>> Point(1,1) < Point(-2,-3)
True

>>> Point(1,1) < Point(0.5,-0.2)
False

>>> Point(1,1) < Point(1,1)
False

类似地,可以实现的特殊功能,以重载其他比较运算符,如下表所示。

运算符 表达式 内置函数
小于 p1 < p2 p1._ lt_(p2)
小于或等于 p1 <= p2 p1._ le_(p2)
等于 p1 == p2 p1._ eq_(p2)
不等于 p1 != p2 p1._ ne_(p2)
大于 p1 > p2 p1._ gt_(p2)
大于或等于 p1 >= p2 p1._ ge_(p2)

Python异常处理

Python提供了两个非常重要的功能来处理Python程序中的异常和错误,并在其中添加调试的函数功能 -

  • 异常处理 - 在本教程中介绍。这是一个列表标准Python中提供的异常 - 标准异常。
  • 断言 - 在Python 3教程中的断言中介绍。

标准异常

以下是Python中可用的标准异常列表 -

编号 异常名称 描述
1 Exception 所有异常的基类
2 StopIteration 当迭代器的next()方法没有指向任何对象时引发。
3 SystemExit 由sys.exit()函数引发。
4 StandardError 除StopIteration和SystemExit之外的所有内置异常的基类。
5 ArithmeticError 数据计算出现的所有错误的基类。
6 OverflowError 当计算超过数字类型的最大限制时引发。
7 FloatingPointError 当浮点计算失败时触发。
8 ZeroDivisonError 对于所有的数字类型,当对零进行除数或模数时产生。
9 AssertionError 在Assert语句失败的情况下引发。
10 AttributeError 在属性引用或分配失败的情况下引发。
11 EOFError 当没有来自raw_input()或input()函数的输入并且达到文件结尾时引发。
12 ImportError 导入语句失败时引发。
13 KeyboardInterrupt 当用户中断程序执行时,通常按Ctrl + c。
14 LookupError 所有查找错误的基类。
15 IndexError 当序列中没有找到索引时引发。
16 KeyError 当在字典中找不到指定的键时引发。
17 NameError 当在本地或全局命名空间中找不到标识符时引发。
18 UnboundLocalError 当尝试访问函数或方法中的局部变量但未分配值时引发。
19 EnvironmentError 在Python环境之外发生的所有异常的基类。
20 IOError 在尝试打开不存在的文件时,输入/输出操作失败时触发,例如print语句或open()函数。
21 OSError 引起操作系统相关的错误。
22 SyntaxError 当Python语法有错误时引发。
23 IndentationError 当缩进未正确指定时触发。
24 SystemError 当解释器发现内部问题时引发,但遇到此错误时,Python解释器不会退出。
25 SystemExit 当Python解释器通过使用sys.exit()函数退出时引发。 如果没有在代码中处理,导致解释器退出。
26 TypeError 在尝试对指定数据类型无效的操作或函数时引发。
27 ValueError 当数据类型的内置函数具有有效参数类型时引发,但参数具有指定的无效值。
28 RuntimeError 产生的错误不属于任何类别时引发。
29 NotImplementedError 当需要在继承类中实现的抽象方法实际上没有实现时引发。

Python中的断言

断言是一个健全检查,可以在完成对程序的测试后打开或关闭。

  • 试想断言的最简单的方法就是将它与一个raise-if语句(或者更准确的说是一个加注if语句)相对应。测试表达式,如果结果为false,则会引发异常。
  • 断言由版本1.5引入的assert语句来执行,它是Python的最新关键字。
  • 程序员经常在函数开始时放置断言来检查有效的输入,并在函数调用后检查有效的输出。

assert语句

当它遇到一个assert语句时,Python会评估求值它的的表达式,是否为所希望的那样。 如果表达式为false,Python会引发AssertionError异常。

assert的语法是 -

assert Expression[, Arguments]

如果断言失败,Python将使用ArgumentExpression作为AssertionError的参数。 使用try-except语句可以像任何其他异常一样捕获和处理AssertionError异常。 如果没有处理,它们将终止程序并产生回溯。

示例

这里将实现一个功能:将给定的温度从开尔文转换为华氏度。如果是负温度,该功能将退出 -

#!/usr/bin/python3
def KelvinToFahrenheit(Temperature):
   assert (Temperature >= 0),"Colder than absolute zero!"
   return ((Temperature-273)*1.8)+32

print (KelvinToFahrenheit(273))
print (int(KelvinToFahrenheit(505.78)))
print (KelvinToFahrenheit(-5))

当执行上述代码时,会产生以下结果 -

32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print KelvinToFahrenheit(-5)
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!

什么是异常?

一个例外是在程序执行期间发生的一个事件,它破坏程序指令的正常流程。 一般来说,当Python脚本遇到无法应对的情况时,会引发异常。异常是一个表示错误的Python对象。

当Python脚本引发异常时,它必须立即处理异常,否则终止并退出。

处理异常

如果有一些可能引发异常的可疑代码,可以通过将可疑代码放在try:块中来保护您的程序。 在try:块之后,包括一个except:语句,然后是一个尽可能优雅地处理问题的代码块。

语法

下面是简单的语法try …. except … else块 -

try:
   You do your operations here
   ......................
except ExceptionI:
   If there is ExceptionI, then execute this block.
except ExceptionII:
   If there is ExceptionII, then execute this block.
   ......................
else:
   If there is no exception then execute this block.

以下是上述语法的几个重点 -

  • 一个try语句可以有多个except语句。 当try块包含可能引发不同类型的异常的语句时,这就很有用。
  • 还可以提供一个通用的except子句,它处理任何异常。
  • 在except子句之后,可以包含一个else子句。 如果try:block中的代码不引发异常,则else块中的代码将执行。
  • else-block是一个不需要try:block保护的代码的地方。

示例

此示例打开一个文件,将内容写入文件,并且优雅地出现,因为完全没有问题 -

#!/usr/bin/python3

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print ("Error: can\'t find file or read data")
else:
   print ("Written content in the file successfully")
   fh.close()

这产生以下结果 -

Written content in the file successfully

示例

此示例尝试打开一个没有写入权限的文件,因此它引发了一个异常 -

#!/usr/bin/python3

try:
   fh = open("testfile", "r")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print ("Error: can\'t find file or read data")
else:
   print ("Written content in the file successfully")

这产生以下结果 -

Error: can't find file or read data

except子句没有指定异常

也可以使用except语句,但不定义异常,如下所示 -

try:
   You do your operations here
   ......................
except:
   If there is any exception, then execute this block.
   ......................
else:
   If there is no exception then execute this block.

这种try-except语句捕获所有发生的异常。使用这种try-except语句不被认为是一个很好的编程实践,因为它捕获所有异常,但不会让程序员能更好地识别发生的问题的根本原因。

except子句指定多个异常

还可以使用相同的except语句来处理多个异常,如下所示:

try:
   You do your operations here
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block.

try-finally子句

可以使用finally:块和try:块。 finally:块是放置必须执行代码的地方,无论try块是否引发异常。 try-finally语句的语法是这样的 -

try:
   You do your operations here;
   ......................
   Due to any exception, this may be skipped.
finally:
   This would always be executed.
   ......................

注意 - 可以提供except子句或finally子句,但不能同时提供。不能使用else子句以及finally子句。

示例

#!/usr/bin/python3

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
finally:
   print ("Error: can\'t find file or read data")
   fh.close()

如果没有以写入形式打开文件的权限,则会产生以下结果 -

Error: can't find file or read data

同样的例子可以写得更干净如下 -

#!/usr/bin/python3

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print ("Going to close the file")
      fh.close()
except IOError:
   print ("Error: can\'t find file or read data")

当try块中抛出异常时,执行将立即传递给finally块。 在finally块中的所有语句都被执行之后,异常被再次引发,如果存在于try-except语句的下一个更高的层中,则在except语句中处理异常。

异常参数

一个异常可以有一个参数,参数它是一个值,它提供有关该问题的其他信息。 参数的内容因异常而异。 可以通过在except子句中提供变量来捕获异常的参数,如下所示:

try:
   You do your operations here
   ......................
except ExceptionType as Argument:
   You can print value of Argument here...

如果编写代码来处理单个异常,则可以在except语句中使用一个变量后跟异常的名称。 如果要捕获多个异常,可以使用一个变量后跟随异常的元组。

此变量接收大部分包含异常原因的异常值。 变量可以以元组的形式接收单个值或多个值。 该元组通常包含错误字符串,错误编号和错误位置。

示例

以下是一个例外 -

#!/usr/bin/python3

# Define a function here.
def temp_convert(var):
   try:
      return int(var)
   except ValueError as Argument:
      print ("The argument does not contain numbers\n", Argument)

# Call above function here.
temp_convert("xyz")

这产生以下结果 -

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

抛出异常

可以通过使用raise语句以多种方式引发异常。raise语句的一般语法如下 -

语法

raise [Exception [, args [, traceback]]]

这里,Exception是异常的类型(例如,NameError),args是异常参数的值。 参数是可选的; 如果没有提供,则异常参数为None。

最后一个参数traceback也是可选的(在实践中很少使用),如果存在,则是用于异常的追溯对象。

示例

异常可以是字符串,类或对象。 Python核心引发的大多数异常都是类,一个参数是类的一个实例。 定义新的例外是非常容易的,可以做到如下 -

def functionName( level ):
   if level <1:
      raise Exception(level)
      # The code below to this would not be executed
      # if we raise the exception
   return level

注意 - 为了捕获异常,“except”子句必须引用与类对象或简单字符串相同的异常。例如,为了捕获上述异常,必须写出except子句如下:

try:
   Business Logic here...
except Exception as e:
   Exception handling here using e.args...
else:
   Rest of the code here...

以下示例说明了使用引发异常 -

#!/usr/bin/python3
def functionName( level ):
   if level <1:
      raise Exception(level)
      # The code below to this would not be executed
      # if we raise the exception
   return level

try:
   l = functionName(-10)
   print ("level = ",l)
except Exception as e:
   print ("error in level argument",e.args[0])

这将产生以下结果 -

error in level argument -10

用户定义的异常

Python还允许通过从标准内置异常导出类来创建自己的异常。

这是一个与RuntimeError有关的示例。 在这里,从RuntimeError类创建一个子类。 当需要在捕获异常时显示更多具体信息时,这就很有用了。

在try块中,用户定义的异常被引发并被捕获在except块中。 变量e用于创建Networkerror类的实例。

class Networkerror(RuntimeError):
   def __init__(self, arg):
      self.args = arg

所以当定义了上面的类以后,就可以使用以下命令抛出异常 -

try:
   raise Networkerror("Bad hostname")
except Networkerror,e:
   print e.args
阅读更多
个人分类: python
想对作者说点什么? 我来说一句

一文了解python知识点

2018年05月29日 8.75MB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭