目录
1、面向对象编程
- Python完全采用了面向对象程序设计的思想,是真正面向对象的高级动态编程语言;
- Python中的一切内容都可以称为对象,除了数字、字符串、列表、元组、字典、集合、range对象、zip对象等,函数也是对象,类也是对象;
- 创建类时用变量形式表示的对象属性称为数据成员,用函数形式表示的对象行为称为成员方法,成员属性和成员方法统称为类的成员。
类(class)
对象/实例(Object)
数据成员:属性
类属性
实例属性
操作成员:函数
2. 类的定义与对象创建、使用
2.1 类的定义
- 类文档——类名后第1行(类说明)
- 类成员(class_suite)
- 属性(数据)
- 函数(操作、方法)
类定义示例:雇员类
- 类名:Employee
- 属性
- 类属性:empCount
- 实例属性:name,salary
- 函数
- __init__
- displayCount
- displayEmployee
(1)self
- 实例属性—— 写在 self 后面
只能通过对象访问,实例各自持有自己的值
- 类属性——类里面、函数外面定义
本类所有对象共享同一个值,可通过类名访问,可以从类内部或类外部以Employee.empCount的形式进行访问
self 代表当前对象,类定义中所有函数的第1个参数必须是self
(2)__init__
构造方法 创建对象实例时被调用
2.2 对象创建
格式:
变量=类名([参数列表])
如果类定义代码存放在文件中,则需要导入,格式有以下两种:
(1)格式1
import 模块名
变量=模块名.类名([参数列表])
(2)格式2
from 模块名 import 类名(或函数名或*)
变量=类名([参数列表])
2.3 成员访问
通过点号(.)运算符访问对象的成员或类的成员
>>> from myclasses import Employee
>>> emp1 = Employee('li',1000)
>>> emp1.displayEmployee()
Name : li , Salary: 1000
>>> emp1.displayCount()
Total Employee 1
>>> Employee.empCount # 显示类属性
1
>>> emp1.name
'li'
>>> emp1.salary
1000
2.4 类成员与实例成员
- 实例的数据成员:一般是指在构造函数__init__()中定义的,定义和使用时必须以self作为前缀;
- 类的数据成员:是在类中所有方法之外定义的;
- 在主程序中(或类的外部),实例属性属于实例(对象),只能通过对象名访问;而类属性属于类,可以通过类名或对象名访问;在类的方法中可以调用类本身的其他方法,也可以访问类属性以及对象属性;
- 在Python中比较特殊的是,可以动态地为类和对象增加成员,可以随时添加,删除或修改类和对象的属性,这一点是和很多面向对象程序设计语言不同的,也是Python动态类型特点的一种重要体现。
>>> emp1.name
'li'
>>> emp1.salary
1000
>>> emp1.__dict__
{'name': 'li', 'salary': 1000}
>>> emp1.age=40
>>> emp1.__dict__
{'name': 'li', 'salary': 1000, 'age': 40}
>>> del emp1.age
>>> emp1.__dict__
{'name': 'li', 'salary': 1000}
getattr(obj, name[, default]) − 访问对象的属性。
hasattr(obj,name) − 检查一个属性存在与否。
setattr(obj,name,value) − 设置属性。如果属性不存在,则将创建它。
delattr(obj, name) − 删除一个属性。
>>> emp1.__dict__
{'name': 'li', 'salary': 1000}
>>> getattr(emp1, 'name') #访问对象的属性,输出属性的值
'li'
>>> hasattr(emp1, 'name') #检查一个属性存在与否
True
>>> hasattr(emp1, 'age')
False
>>> setattr(emp1, 'age', 20) #设置属性。如果属性不存在,则将创建它。
>>> hasattr(emp1, 'age')
True
>>> delattr(emp1, 'age') #删除一个属性
>>> hasattr(emp1, 'age')
False
内置类属性
每个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("Zara", 2000)
emp2 = Employee("Manni", 5000)
print ("Employee.__dict__:", Employee.__dict__ )
print ("Employee.__doc__:", Employee.__doc__)
print ("Employee.__name__:", Employee.__name__)
print ("Employee.__module__:", Employee.__module__)
print ("Employee.__bases__:", Employee.__bases__)
>>> Employee.__doc__
'Common base class for all employees'
>>> Employee.__dict__
mappingproxy({'__module__': 'myclasses', '__doc__': 'Common base class for all employees', 'empCount': 1, '__init__': <function Employee.__init__ at 0x0000019D02BF8C18>, 'displayCount': <function Employee.displayCount at 0x0000019D02BD6AF8>, 'displayEmployee': <function Employee.displayEmployee at 0x0000019D02BD6CA8>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>})
>>> Employee.__name__
'Employee'
>>> Employee.__module__
'myclasses'
>>> Employee.__bases__
(<class 'object'>,)
2.5 公有与私有
- Python并没有对私有成员提供严格的访问保护机制; 在定义类的成员时,如果成员名以两个下划线“_ _”开头则表示是私有成员。私有成员在类的外部不能直接访问,需要通过调用对象的公有成员方法来访问,也可以通过Python支持的特殊方式(_类名__成员名)来访问;
- 公有成员既可以在类的内部进行访问,也可以在外部程序中使用。
>>> class Person:
... name = 'abc'
... __age = 45
...
>>> p = Person()
>>> p.name
'abc'
>>> p.__age
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__age'
>>> p._Person__age
45
- 在Python中,以下划线开头的变量名和方法名有特殊的含义,尤其是在类的定义中:
- _xxx:受保护成员,不能用'from module import *'导入;
- __xxx__:系统定义的特殊成员;
- __xxx:私有成员,只有类对象自己能访问,子类对象不能直接访问到这个成员,但在对象外部可以通过“对象名._类名__xxx”这样的特殊方式来访问。
2.6 对象消亡
- Python通过垃圾回收机制,自动删除不再使用的对象来回收内存空间。
- 新定义一个变量,或放入容器(如列表、元组或字典)时,引用增加;当用del方法删除一个变量,或重新分配,或引用超出范围时,引用数减少。当变量的引用数为0时,python删除回收分配空间。
- Python自动删除不需要的对象(内置类型或类实例)以释放内存空间。Python定期回收不再使用的内存块的过程称为垃圾收集。
- Python的垃圾收集器在程序执行期间运行,并在对象的引用计数达到零时触发。对象的引用计数随指向它的别名数量的变化而变化。
- 当为对象分配新名称或将其放置在容器(列表,元组或字典)中时,其引用计数就会增加。当用del删除对象,重新分配其引用或引用超出范围时,该对象的引用计数会减少。当对象的引用计数达到零时,Python会自动收集它。
>>> a = 40
>>> b = a
>>> c = [b]
>>> a,b,c
(40, 40, [40])
>>> del a
>>> b,c
(40, [40])
>>> b = 100
>>> c[0]=-1
>>> b,c
(100, [-1])
>>>
2.7 析构方法使用
通常,我们不会注意到垃圾收集器何时销毁一个孤立实例并回收其空间。但是,一个类可以实现称为析构函数的特殊方法__del __(),该方法将在实例即将被销毁时调用。此方法可能用于清除实例使用的任何非内存资源。
例
这个__del __()析构函数输出将要销毁的实例的类名-
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
运行结果:
3、继承
3.1 格式: 支持单一继承、多继承
除了从头开始,您还可以通过在新类名称后面的括号中列出父类来从现有类派生该类,从而创建一个类。
子类继承其父类的属性,您可以像在子类中定义它们一样使用这些属性。子类也可以覆盖父类的数据成员和方法。
句法
派生类的声明与父类很相似;但是,在类名称后给出了要继承的基类列表
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
class Parent: # 定义一个父类
parentAttr = 100
def __init__(self):
print('Calling parent constructor')
def parent_method(self):
print('Calling parent method')
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print("Parent attribute :", Parent.parentAttr)
class Child(Parent): # 定义一个子类
def __init__(self):
print("Calling child constructor")
def child_method(self):
print('Calling child method')
c = Child() # 子类实例
c.child_method() # 子类调用其方法
c.parent_method() # 调用父类方法
c.setAttr(200) # 调用父类方法
c.getAttr() # 调用父类方法
运行结果:
您可以使用issubclass()或isinstance()函数来检查两个类和实例之间的关系。
-
issubclass(sub, sup) - 布尔函数返回TRUE,如果给定的子类子确实是超类的子类SUP。
-
isinstance(obj, Class) - 布尔函数返回TRUE,如果OBJ是类的实例类或类是一个子类的实例
3.2 方法覆盖
始终可以覆盖父类方法。覆盖父方法的一个原因是,你可能需要子类中的特殊功能或其他功能。
class Parent: # 定义一个父类
def myMethod(self):
print ('Calling parent method')
class Child(Parent): # 定义一个子类
def myMethod(self):
print ('Calling child method')
c = Child() # 子类实例
c.myMethod() # 子类方法覆盖父类方法
运行结果:
内部方法(从Object中继承)
- __init__(self [,args ...]) 构造方法,生成对象是被调用,范例:obj = className(args)
- __del__(self) 析构方法,释放对象是被调用,范例:del obj
- __str__(self) 生成对象的可打印字符串,范例:str(obj)
- __add__ 用于加(☐ + ?)运算
- __cmp__(self, x) 对象比较,范例:cmp(obj,x)
3.3 运算符重载
假设你已经创建了一个Vector类来表示二维矢量。当使用加号运算符添加它们时会发生什么?
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)
运行结果:
3.4 数据隐藏 (_xxx属性为私有,不能对外)
在类定义之外,对象的属性可能不可见。您需要使用双下划线前缀来命名属性,这样外部人就不会直接看到那些属性。
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之类的属性
4、组合
概念:将其它类的实例化对象作另一个类成员。
class Turtle:
def __init__(self, x):
self.num = x
class Fish:
def __init__(self, x):
self.num = x
class Pool:
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(x)
def print_num(self):
print('水池里共有乌龟%d只,小鱼%d条' % (self.turtle.num, self.turtle.num))
练习
定义圆类Circle,要求如下:
- 实例变量 radius(半径);
- 构造函数用于初始化实例变量;
- perimeter()方法,返回圆周长;
- area()方法,返回圆面积;
- show()方法,打印圆的半径、周长、面积等信息;
分别创建两个半径为50、120的圆c1、c2,再调用show()方法。
http://www.tutorialspoint.com/python3/