个性化阅读
专注于IT技术分析

python面向对象编程:类和对象详解介绍 – Python高级开发教程

上一章Python教程请查看:python异常处理和断言

自从Python存在以来,Python一直是一种面向对象的语言,但是在Python中创建和使用类和对象非常简单,本章将帮助你成为使用Python的面向对象编程支持的专家。

如果你以前没有任何面向对象(OO)编程的经验,那么你可能需要参考一门介绍性课程,或者至少是某种教程,以便掌握基本概念。

一、OOP术语概述

OOP中常见的术语如下:

  • 类-一个用户定义的对象原型,它定义了一组属性来描述类的任何对象。属性是通过点表示法访问的数据成员(类变量和实例变量)和方法。
  • 类变量——一个类的所有实例共享的变量。类变量在类中定义,但在类的任何方法之外,类变量的使用频率不如实例变量。
  • 数据成员——保存与类及其对象相关的数据的类变量或实例变量。
  • 函数重载——指定一个特定函数的多个行为,执行的操作因涉及的对象或参数的类型而异。
  • 实例变量——定义在方法内部,只属于类当前实例的变量。
  • 继承——把一个类的特性转移到由它派生出来的其他类。
  • 一个类的个体对象,例如一个属于类圆的对象obj就是类圆的一个实例。
  • 实例化——类实例的创建。
  • 方法——类定义中定义的一种特殊函数。
  • 对象——由其类定义的数据结构的唯一实例,对象包括数据成员(类变量和实例变量)和方法。
  • 操作符重载——将一个以上的函数赋给一个特定的操作符。

二、创建类

类语句创建一个新的类定义,类的名称紧跟在关键字类后面,后面跟一个冒号如下所示:

class ClassName:
   '可选类文档字符串'
   class_suite

该类有一个文档字符串,可以通过classname .__doc__访问该字符串。

class_suite由定义类成员、数据属性和函数的所有组件语句组成。

下面是一个简单的Python类的例子:

class Employee:
   '基类'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "雇员数 %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary
  • 变量empCount是一个类变量,它的值在该类的所有实例之间共享,这可以作为雇员访问,类内部或类外部的empCount。
  • 第一个方法是一个特殊的方法,称为类构造函数或初始化方法,当你创建该类的新实例时,Python会调用这个方法。
  • 除了每个方法的第一个参数是self之外,你可以声明其他类方法,如普通函数。Python将self参数添加到列表中;在调用方法时不需要包含它。

三、创建实例对象

要创建类的实例,你可以使用类名来调用类,并传入类的任意参数。

"这将创建Employee类的第一个对象"
emp1 = Employee("Van Gogh", 2000)
"第二个实例对象"
emp2 = Employee("Oreja", 5000)

四、访问属性

你可以使用带有object的点操作符来访问对象的属性,类变量将使用如下的类名来访问:

emp1.displayEmployee()
emp2.displayEmployee()
print "雇员数: %d" % Employee.empCount

现在把上面所有的概念放在一起:

#!/usr/bin/python

class Employee:
   '基类s'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "雇员数 %d" % Employee.empCount

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

"创建第一个实例对象"
emp1 = Employee("Van Gogh", 2000)
"创建第二个实例对象"
emp2 = Employee("Oreja", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "雇员数 %d" % Employee.empCount

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

emp1.age = 7  # 添加'age' 属性.
emp1.age = 8  # 修改'age' 属性.
del emp1.age  # 删除 'age' 属性.

你可以使用以下函数,而不是使用常规语句来访问属性:

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

五、内置类属性

每个Python类使内置属性后,他们可以使用点操作符访问−像任何其他属性:

(1)__dict__−字典包含类的名称空间。

(2)__doc__−类文档字符串或没有,如果定义。

(3)__name__−类名。

(4)__module__−模块名称的类定义,这个属性是“__main__”互动模式。

(5)__bases__−可能包含基类空元组,按照他们的出现在基类列表中。

上面的类−我们试图访问这些属性

#!/usr/bin/python

class Employee:
   '基类'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "雇员数 %d" % Employee.empCount

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

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__

六、销毁对象(垃圾收集)

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

Python的垃圾收集器在程序执行期间运行,并在对象的引用计数为0时触发,当指向对象的别名数目改变时,该对象的引用计数也随之改变。

对象的引用计数在分配新名称或放在容器(列表、元组或字典)中时增加,当使用del删除对象、重新分配对象的引用或将其引用移出范围时,对象的引用计数将减少,当对象的引用计数为0时,Python自动收集它。

a = 40      # 创建对象<40>
b = a       # <40>增加引用计数 
c = [b]     # <40>增加引用计数

del a       # <40>减少引用计数
b = 100     # <40>减少引用计数 
c[0] = -1   # <40>减少引用计数 

通常你不会注意到垃圾收集器何时销毁孤立实例并回收其空间,但是类可以实现称为析构函数的特殊方法,该方法在实例即将被销毁时调用,此方法可用于清理实例使用的任何非内存资源。

这个del__()析构函数打印一个即将被销毁的实例的类名

#!/usr/bin/python

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) 
del pt1
del pt2
del pt3

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

七、类继承

你可以创建一个类,而不是从零开始,方法是通过在新类名后面的括号中列出父类,从而从一个已存在的类派生该类。

子类继承父类的属性,你可以像在子类中定义属性一样使用这些属性,子类还可以覆盖来自父类的数据成员和方法。

派生类的声明很像它们的父类,但是在类名之后给出了要继承的基类的列表:

class SubClassName (ParentClass1[, ParentClass2, ...]):
   '可选类文档字符串'
   class_suite

python类继承例子如下:

#!/usr/bin/python

class Parent:        # 定义父类
   parentAttr = 100
   def __init__(self):
      print "调用父类构造函数"

   def parentMethod(self):
      print '调用父类函数'

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

   def getAttr(self):
      print "父类属性 :", Parent.parentAttr

class Child(Parent): # 定义子类
   def __init__(self):
      print "调用子类构造函数"

   def childMethod(self):
      print '调用子类函数'

c = Child()          # 子类实例
c.childMethod()      # 调用子类方法
c.parentMethod()     # 调用父类方法
c.setAttr(200)       
c.getAttr()  

类似地,你可以从多个父类驱动一个类,如下所示

class A:        # 定义类A
.....

class B:         # 定义类B
.....

class C(A, B):   # A和B的子类

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

如果给定的子类确实是超类sup的子类,则issubclass(sub, sup)布尔函数返回true。

如果obj是Class类的实例或者是Class子类的实例,则isinstance(obj, Class)布尔函数返回true

八、重写方法

你总是可以覆盖父类方法,重写父方法的一个原因是,你可能希望子类具有特殊或不同的功能。

#!/usr/bin/python

class Parent:        # 定义父类
   def myMethod(self):
      print '调用父类函数'

class Child(Parent): # 定义子类
   def myMethod(self):
      print '调用子类函数'

c = Child()          # 子类实例
c.myMethod()         

九、重载基本方法

下表列出了一些可以在自己的类中覆盖的通用功能

编号 方法,说明和调用例子
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)

十、重载操作符

假设你创建了一个向量类来表示二维向量,那么当你使用加号操作符将它们相加时会发生什么?

但是你可以在类中定义__add__方法来执行向量加法,然后加号操作符将按照期望操作

#!/usr/bin/python

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

十一、数据隐藏

对象的属性在类定义之外可能可见,也可能不可见,你需要使用双下划线前缀来命名属性,这样外部人员就不能直接看到这些属性。

#!/usr/bin/python

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

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

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

.........................
print counter._JustCounter__secretCount
赞(0)
未经允许不得转载:srcmini » python面向对象编程:类和对象详解介绍 – Python高级开发教程

评论 抢沙发

评论前必须登录!