Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。

如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。

接下来我们先来简单的了解下面向对象的一些基本特征。


面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

创建类

使用class语句来创建一个新类,class之后为类的名称并以冒号结尾,如下实例:

  1. class ClassName:
  2. '类的帮助信息' #类文档字符串
  3. class_suite #类体

类的帮助信息可以通过ClassName.__doc__查看。

class_suite 由类成员,方法,数据属性组成。

实例

以下是一个简单的Python类实例:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class Employee:
  5. '所有员工的基类'
  6. empCount = 0
  7.  
  8. def __init__(self, name, salary):
  9. self.name = name
  10. self.salary = salary
  11. Employee.empCount += 1
  12.  
  13. def displayCount(self):
  14. print "Total Employee %d" % Employee.empCount
  15.  
  16. def displayEmployee(self):
  17. print "Name : ", self.name, ", Salary: ", self.salary
  • empCount变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用Employee.empCount访问。
  • 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法

创建实例对象

要创建一个类的实例,你可以使用类的名称,并通过__init__方法接受参数。

  1. "创建 Employee 类的第一个对象"
  2. emp1 = Employee("Zara", 2000)
  3. "创建 Employee 类的第二个对象"
  4. emp2 = Employee("Manni", 5000)

访问属性

您可以使用点(.)来访问对象的属性。使用如下类的名称访问类变量:

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

完整实例:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class Employee:
  5. '所有员工的基类'
  6. empCount = 0
  7.  
  8. def __init__(self, name, salary):
  9. self.name = name
  10. self.salary = salary
  11. Employee.empCount += 1
  12.  
  13. def displayCount(self):
  14. print "Total Employee %d" % Employee.empCount
  15.  
  16. def displayEmployee(self):
  17. print "Name : ", self.name, ", Salary: ", self.salary
  18.  
  19. "创建 Employee 类的第一个对象"
  20. emp1 = Employee("Zara", 2000)
  21. "创建 Employee 类的第二个对象"
  22. emp2 = Employee("Manni", 5000)
  23. emp1.displayEmployee()
  24. emp2.displayEmployee()
  25. print "Total Employee %d" % Employee.empCount

执行以上代码输出结果如下:

  1. Name : Zara ,Salary: 2000
  2. Name : Manni ,Salary: 5000
  3. Total Employee 2

你可以添加,删除,修改类的属性,如下所示:

  1. emp1.age = 7 # 添加一个 'age' 属性
  2. emp1.age = 8 # 修改 'age' 属性
  3. del emp1.age # 删除 'age' 属性

你也可以使用以下函数的方式来访问属性:

  • getattr(obj, name[, default]) : 访问对象的属性。
  • hasattr(obj,name) : 检查是否存在一个属性。
  • setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
  • delattr(obj, name) : 删除属性。
  1. hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
  2. getattr(emp1, 'age') # 返回 'age' 属性的值
  3. setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
  4. delattr(empl, 'age') # 删除属性 'age'

Python内置类属性

  • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
  • __doc__ :类的文档字符串
  • __name__: 类名
  • __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
  • __bases__ : 类的所有父类构成元素(包含了以个由所有父类组成的元组)

Python内置类属性调用实例如下:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class Employee:
  5. '所有员工的基类'
  6. empCount = 0
  7.  
  8. def __init__(self, name, salary):
  9. self.name = name
  10. self.salary = salary
  11. Employee.empCount += 1
  12.  
  13. def displayCount(self):
  14. print "Total Employee %d" % Employee.empCount
  15.  
  16. def displayEmployee(self):
  17. print "Name : ", self.name, ", Salary: ", self.salary
  18.  
  19. print "Employee.__doc__:", Employee.__doc__
  20. print "Employee.__name__:", Employee.__name__
  21. print "Employee.__module__:", Employee.__module__
  22. print "Employee.__bases__:", Employee.__bases__
  23. print "Employee.__dict__:", Employee.__dict__

执行以上代码输出结果如下:

  1. Employee.__doc__: 所有员工的基类
  2. Employee.__name__: Employee
  3. Employee.__module__: __main__
  4. Employee.__bases__: ()
  5. Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0x10a939c80>, 'empCount': 0, 'displayEmployee': <function displayEmployee at 0x10a93caa0>, '__doc__': '\xe6\x89\x80\xe6\x9c\x89\xe5\x91\x98\xe5\xb7\xa5\xe7\x9a\x84\xe5\x9f\xba\xe7\xb1\xbb', '__init__': <function __init__ at 0x10a939578>}

python对象销毁(垃圾回收)

同Java语言一样,Python使用了引用计数这一简单技术来追踪内存中的对象。

在Python内部记录着所有使用中的对象各有多少引用。

一个内部跟踪变量,称为一个引用计数器。

当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。

  1. a = 40 # 创建对象 <40>
  2. b = a # 增加引用, <40> 的计数
  3. c = [b] # 增加引用. <40> 的计数
  4.  
  5. del a # 减少引用 <40> 的计数
  6. b = 100 # 减少引用 <40> 的计数
  7. c[0] = -1 # 减少引用 <40> 的计数

垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。

实例

析构函数 __del__ ,__del__在对象销毁的时候被调用,当对象不再被使用时,__del__方法运行:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class Point:
  5. def __init__( self, x=0, y=0):
  6. self.x = x
  7. self.y = y
  8. def __del__(self):
  9. class_name = self.__class__.__name__
  10. print class_name, "销毁"
  11.  
  12. pt1 = Point()
  13. pt2 = pt1
  14. pt3 = pt1
  15. print id(pt1), id(pt2), id(pt3) # 打印对象的id
  16. del pt1
  17. del pt2
  18. del pt3

以上实例运行结果如下:

  1. 3083401324 3083401324 3083401324
  2. Point 销毁

注意:通常你需要在单独的文件中定义一个类,

类的继承

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。

需要注意的地方:继承语法 class 派生类名(基类名)://... 基类名写作括号里,基本类是在类定义的时候,在元组之中指明的。

在python中继承中的一些特点:

  • 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
  • 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
  • 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。

语法:

派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:

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

实例:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class Parent: # 定义父类
  5. parentAttr = 100
  6. def __init__(self):
  7. print "调用父类构造函数"
  8.  
  9. def parentMethod(self):
  10. print '调用父类方法'
  11.  
  12. def setAttr(self, attr):
  13. Parent.parentAttr = attr
  14.  
  15. def getAttr(self):
  16. print "父类属性 :", Parent.parentAttr
  17.  
  18. class Child(Parent): # 定义子类
  19. def __init__(self):
  20. print "调用子类构造方法"
  21.  
  22. def childMethod(self):
  23. print '调用子类方法 child method'
  24.  
  25. c = Child() # 实例化子类
  26. c.childMethod() # 调用子类的方法
  27. c.parentMethod() # 调用父类方法
  28. c.setAttr(200) # 再次调用父类的方法
  29. c.getAttr() # 再次调用父类的方法

以上代码执行结果如下:

  1. 调用子类构造方法
  2. 调用子类方法 child method
  3. 调用父类方法
  4. 父类属性 : 200

你可以继承多个类

  1. class A: # 定义类 A
  2. .....
  3.  
  4. class B: # 定义类 B
  5. .....
  6.  
  7. class C(A, B): # 继承类 A 和 B
  8. .....

你可以使用issubclass()或者isinstance()方法来检测。

  • issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
  • isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

方法重写

如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法:

实例:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class Parent: # 定义父类
  5. def myMethod(self):
  6. print '调用父类方法'
  7.  
  8. class Child(Parent): # 定义子类
  9. def myMethod(self):
  10. print '调用子类方法'
  11.  
  12. c = Child() # 子类实例
  13. c.myMethod() # 子类调用重写方法

执行以上代码输出结果如下:

  1. 调用子类方法

基础重载方法

下表列出了一些通用的功能,你可以在自己的类重写:

序号 方法, 描述 & 简单的调用
1 __init__ ( self [,args...] )
构造函数
简单的调用方法: obj = className(args)
2 __del__( self )
析构方法, 删除一个对象
简单的调用方法 : dell obj
3 __repr__( self )
转化为供解释器读取的形式
简单的调用方法 : repr(obj)
4 __str__( self )
用于将值转化为适于人阅读的形式
简单的调用方法 : str(obj)
5 __cmp__ ( self, x )
对象比较
简单的调用方法 : cmp(obj, x)

运算符重载

Python同样支持运算符重载,实例如下:

  1. #!/usr/bin/python
  2.  
  3. class Vector:
  4. def __init__(self, a, b):
  5. self.a = a
  6. self.b = b
  7.  
  8. def __str__(self):
  9. return 'Vector (%d, %d)' % (self.a, self.b)
  10.  
  11. def __add__(self,other):
  12. return Vector(self.a + other.a, self.b + other.b)
  13.  
  14. v1 = Vector(2,10)
  15. v2 = Vector(5,-2)
  16. print v1 + v2

以上代码执行结果如下所示:

  1. Vector(7,8)

类属性与方法

类的私有属性

__private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs

类的方法

在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数

类的私有方法

__private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.__private_methods

实例

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. class JustCounter:
  5. __secretCount = 0 # 私有变量
  6. publicCount = 0 # 公开变量
  7.  
  8. def count(self):
  9. self.__secretCount += 1
  10. self.publicCount += 1
  11. print self.__secretCount
  12.  
  13. counter = JustCounter()
  14. counter.count()
  15. counter.count()
  16. print counter.publicCount
  17. print counter.__secretCount # 报错,实例不能访问私有变量

Python 通过改变名称来包含类名:

  1. 1
  2. 2
  3. 2
  4. Traceback (most recent call last):
  5. File "test.py", line 17, in <module>
  6. print counter.__secretCount # 报错,实例不能访问私有变量
  7. AttributeError: JustCounter instance has no attribute '__secretCount'

Python不允许实例化的类访问私有数据,但你可以使用 object._className__attrName 访问属性,将如下代码替换以上代码的最后一行代码:

  1. .........................
  2. print counter._JustCounter__secretCount

python 练习 30的更多相关文章

  1. python实用30个小技巧

    python实用30个小技巧 展开1.原地交换两个数字Python 提供了一个直观的在一行代码中赋值与交换(变量值)的方法,请参见下面的示例: In [1]: x,y = 10 ,20 In [2]: ...

  2. python的30个编程技巧

     1.原地交换两个数字 x, y =10, 20 print(x, y) y, x = x, y print(x, y) 10 20 20 10 2.链状比较操作符 n = 10 print(1 &l ...

  3. python(30)- 常用模块

    模块就是py文件.python中能开辟作用域的只有函数.类和模块. for循环不能开辟作用域,for循环内的变量为全局变量.if...else...同for循环一样. 一 time模块 时间表示形式 ...

  4. 『无为则无心』Python函数 — 30、Python变量的作用域

    目录 1.作用于的概念 2.局部变量 3.全局变量 4.变量的查找 5.作用域中可变数据类型变量 6.多函数程序执行流程 1.作用于的概念 变量作用域指的是变量生效的范围,在Python中一共有两种作 ...

  5. python手记(30)

    #!/usr/bin/env python #-*- coding: utf-8 -*- import cv2 import numpy as np fn="test3.png" ...

  6. python(30)——【random模块】【if __name__ =='__main__'】【os模块】

    一.random模块(随机模块) 1.random 常用模块介绍 import random print(random.random()) #返回[0,1)之间的随机浮点数 print(random. ...

  7. 零基础入门学习Python(30)--文件系统:介绍一个高大上的东西

    知识点 os,os.path模块中关于文件.目录常用的函数使用方法 在使用os模块,需要先进行import操作: import os os模块中关于文件/目录常用的函数使用方法 函数名 函数作用 示例 ...

  8. python爬虫30 | scrapy后续,把「糗事百科」的段子爬下来然后存到数据库中

    上回我们说到 python爬虫29 | 使用scrapy爬取糗事百科的例子,告诉你它有多厉害! WOW!! scrapy awesome!! 怎么会有这么牛逼的框架 wow!! awesome!! 用 ...

  9. Python笔记(30)-----logger

    转自: https://www.jb51.net/article/139080.htm logging模块介绍 Python的logging模块提供了通用的日志系统,熟练使用logging模块可以方便 ...

随机推荐

  1. Shared Preferences 数据存储

    SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数. 其背后是用xml文件存放数据,文件存放在/data/data/<package name>/s ...

  2. 【翻译】Anatomy of a Program in Memory—剖析内存中的一个程序(进程的虚拟存储器映像布局详解)

    [翻译]Anatomy of a Program in Memory—剖析内存中的一个程序(进程的虚拟存储器映像布局详解) . . .

  3. jquery之event与originalEvent的关系、event事件对象用法浅析

    在jquery中,最终传入事件处理程序的 event 其实已经被 jQuery 做过标准化处理, 其原有的事件对象则被保存于 event 对象的 originalEvent 属性之中, 每个 even ...

  4. System.MissingMethodException: 找不到方法:

    This is a problem which can occur when there is an old version of a DLL still lingering somewhere ar ...

  5. ggplot2 legend图例的修改

    ggplot2中的legend包括四个部分: legend.tittle, legend.text, legend.key, legend.backgroud.针对每一部分有四种处理方式: eleme ...

  6. Django Models的数据类型

    Django中的页面管理后台 Djano中自带admin后台管理模块,可以通过web页面去管理,有点想php-admin,使用步骤: 在项目中models.py 中创建数据库表 class useri ...

  7. [UVa1213]Sum of Different Primes(递推,01背包)

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...

  8. VBA中自定义类和事件的(伪)注册

    想了解一下VBA中自定义类和事件,以及注册事件处理程序的方法. 折腾了大半天,觉得这样的方式实在称不上“注册”,所以加一个“伪”字.纯粹是瞎试,原理也还没有摸透.先留着,有时间再接着摸. 做以下尝试: ...

  9. hnoi 2016 省选总结

    感觉省选好难的说...反正我数据结构太垃圾正解想到了也打不出来打一打暴力就滚粗了! DAY1 0+20+30 DAY2 60-20+0+60 最后170-20分,暴力分还是没有拿全! 然而这次是给了5 ...

  10. .net中类型转换的案例

    .net中三种数据类型转换区别((int),Int32.Parse() 和 Convert.toInt32() )(typename)valuename,是通用方法: Convert类提供了灵活的类型 ...