Python 面向对象:类的创建及其基本内置方法的使用
首先了解一下什么是面向对象
- 面向过程:
就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用分别的函数来实现,问题就解决了。- 面向对象
是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为 1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的i变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
1 类的建立及对象的创建
在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,你定义一大类对象都有的通用行为。基于类创建对象 时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。
- 要设计一个类,通常要满足三个要求:
- 类名:这类事物的总称,满足大驼峰命名法
- 属性:这类事物所具有的特征
- 方法:这类事物具有什么样的行为
1.1 简单的类的定义
定义简单的类:
class 类名:
def 方法一(self,参数列表):
pass
def 方法二(self,参数列表):
pass
示例:定义一个动物类,动物一般都能吃喝跑睡
class Animal(): # 类名称
def drunk(self): # 方法
pass
def eat(self): # 方法
pass
def run(self): # 方法
pass
def sleep(self): # 方法
pass
执行如下:
1.2 属性的添加及调用
类中必定包含此类的特点,也就是所谓的属性,此时要调用一个内置方法_ init _(self)
借用上一个动物的例子,基本的每个动物都有姓名和年龄,这就是其属性
示例如下:
class Animal():
def __init__(self,name,age): # 初始化属性 name 和 age
self.name = name
self.age = age
def drunk(self):
print '%s 要喝水' % self.name
def eat(self):
print '%s 要吃饭' % self.name
def run(self):
print '%s 要跑步' % self.name
def sleep(self):
print '%s 要睡觉' % self.name
cat = Animal('cat',2) # 通过类来创建实例
cat.run() # 调用类中的方法
cat.drunk()
cat.eat()
cat.sleep()
===========================================================================================
其中:
1. def __init__(self,name,age):
self.name = name
self.age = age
两个变量都有前缀 self 。以 self 为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这
些变量。 self.name = name 获取存储在形参 name 中的值,并将其存储到变量 name 中,然后该变量被关联到当前
创建的实例。 self.age = age 的作用与此类似。像这样可通过实例访问的变量称为属性 。
2. cat = Animal('cat',2)
通过对象名 = 类名(实参) 的形式来创建实例,类在进行实例化之前系统是不会给其分配内存空间的
3. cat.run()
类中方法的调用,是通过 实例.方法名称 进行调用的
执行如下:
控制台显示如下:
2. 方法
类中的函数称为方法 ;你前面学到的有关函数的一切都适用于方法,就目前而言,唯一重要的差别是调用方法的方式。
上面对类的建立中使用了一个基本的内置方法 _ init _(self),下面就介绍一下几种常用的内置方法
2.1 _ init _ ()初始化方法
- 当使用类名( )创建对象时,python的解释器会自动执行以下操作
- 为对象在内存中分配空间–创建对象
- 调用初始化方法为对象的属性设置初始值–初始化方法(_ init ),这个初始化方法就是: init _ 方法, _ init _ 是对象的内置方法, _ init _ 方法时专门用来定义一个类具有哪些属性的方法
示例:定义一个动物类,动物一般都有名称年龄
class Animal(): # 定义一个类
def __init__(self,name,age):
# 初始化方法来进行属性添加
self.name = name
self.age = age
def attr(self):
# 定义此方法,返回属性的值
return self.name,self.age
cat = Animal('cat',2) # 建立实例
print cat.attr() # 调用实例方法来进行显示返回属性的值
执行如下:
控制台结果如下:
2.2 _ del _()方法
当删除一个对象时,python解释器会默认调用一个方法,这个方法为_ del _ ()方法。在python中,对于开发者来说很少会直接销毁对象(如果需要,应该使用del关键字销毁)。Python的内存管理机制能够很好的胜任这份工作。也就是说,不管是手动调用 del 还是由 python自动回收都会触发 _ del _ 方法执行:
示例:
class Animal(object):
# 初始化方法
# 创建完对象后会自动被调用
def __init__(self, name):
print('__init__方法被调用')
self.name = name
# 析构方法
# 当对象被删除时,会自动被调用
def __del__(self):
print("__del__方法被调用")
print("%s对象马上被干掉了..." % self.name)
# 创建对象
dog = Animal("哈皮狗")
# 删除对象,__del__ 方法被调用
del dog
cat = Animal("波斯猫")
print '马上删除%s',cat.name
# 若不主动删除对象,会先执行此命令,再调用__del__命令
执行如下:
控制台显示如下:
2.3 _ str _()方法
在 python 中,使用 python 输出对象变量,
默认情况下,会输出这个变量引用的对象是由哪一个类创建的以及在内存中的地址(十六进制表示)
如果在开发中,希望使用print输出对象变量时,
能够打印自定义的内容,就可以利用_ str 这个内置方法了
需要通过 return 来返回所要输出的字符串
示例:不使用 _ str _ 方法之前
class Animal():
# 初始化方法
# 创建完对象后会自动被调用
def __init__(self, name):
print('__init__方法被调用')
self.name = name
# 建立对象
cat = Animal('Tom')
print cat # 直接显示实例,返回的是实例指向的内存地址
执行如下:
控制台显示如下:
示例:使用 _ str _ 方法之后
class Animal():
# 初始化方法
# 创建完对象后会自动被调用
def __init__(self, name):
print('__init__方法被调用')
self.name = name
def __str__(self):
return '返回 %s' % self.name
cat = Animal('Tom')
print cat
执行如下:
控制台显示:
2.4 _ new _()方法(单例)
在进行 _ new _ 方法的介绍之前先介绍一个概念:新式类与旧式类
- Python中类分两种:旧式类和新式类:
新式类,旧式类(经典类)
新式类 定义时给类后加上(object)
class A(object)
pass
python 3 以后若是未指定继承自object 会默认继承自 object 类
python 3 以前则不会,需要进行指定
可通过 dir()函数,来查看对象可调用的类的方法
示例:新式类
class A(object):
pass
a = A()
# 通过print来查看
print dir(a)
旧式类示例:
class B:
pass
b = B()
print dir(b)
执行如下:
控制台显示如下:
注:
新式类旧式类最明显的区别在于继承搜索的顺序发生了改变
即:
经典类多继承搜索顺序(深度优先):
先深入继承树左侧查找,然后再返回,开始查找右侧
新式类多继承搜索顺序(广度优先):
先在水平方向查找,然后再向上查找。
此种区别会在面向对象特点——继承中介绍到
下面介绍 _ new _ 方法
_ new _ ()是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在Python 中 存在于类里面的构造方法 _ init _ () 负责将类的实例化,而在 _ init _ ()启动之前, _ new _ ()决定是否 要使用该 _ init _ ()方法,因为_ new _ ()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。
如果将类比喻为工厂,那么_ init _ ()方法则是该工厂的生产工人,_ init _ ()方法接受的初始化参数则是生产所需原料,_ init _ ()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 _ new _ ()则是生产部经理,_ new _ ()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
_ new _ ()方法的特性:
_ new _ ()方法是在类准备将自身实例化时调用。
_ new _ ()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
静态方法在下面会讲到
_ new _ () 最经典的作用,实现单例
单例:单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例
示例:
class MusicPlayer(object):
instance = None
def __new__(cls, *args, **kwargs):
# 第一个参数cls:哪一类调用,就传递哪一类
# 第二个参数 *args:多值参数
# 第三个参数 **kwargs:多值的字典参数
# 创建对象的时候,new方法会被自动调用
# 重写了父类的方法
if cls.instance is None:
cls.instance = object.__new__(cls)
return cls.instance
player1 = MusicPlayer()
print player1
player2 = MusicPlayer()
print player2
执行如下:
控制台显示如下:
由控制台显示可知,实例 player1 player2所返回的内存地址相同,故为本质上为同一实例
3 几种特殊属性及方法(类属性,类方法,静态方法,私有属性,私有方法)
3.1 私有属性,私有方法
如果一个属性是以两个下划线开始 就标识这个这个属性是一个私有属性
如果一个自定义方法是以两个下划线开始 就标识这个这个方法是一个私有方法
私有属性私有方法都不能直接访问
示例:私有属性
class Animal(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定义私有属性
cat = Animal('cat',2)
print cat.name
print cat.__age
# 在外部调用私有属性会显示该类没有此属性
执行如下:
控制台显示如下:
可在类的内部调用私有属性:
执行如下:
控制台显示如下:
示例:私有方法
class Animal(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定义私有属性
def __test(self): # 定义私有方法
print '这是私有方法'
cat = Animal('cat', 2)
cat.__test() # 在外对私有方法进行调用
执行如下:
控制台显示如下:
想要对私有方法进行调用,可以在类中定义公有方法,通过公有方法间接调用私有方法
示例:
class Animal(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定义私有属性
def __test(self): # 定义私有方法
print '这是私有方法'
def test(self):
print '这是公有方法,通过此方法调用私有方法'
Animal.__test(self)
cat = Animal('cat', 2)
cat.test()
执行如下:
控制台显示如下:
3.2 类属性,类方法
- 类是一个特殊的对象
Python中一切皆对象
class AAA: 定义的类属性属于类对象
obj1 = AAA:属于实例对象
在运行程序时,类 同样会被加载到内存
类对象可以有自己属性和方法
通过 类名. 的方式可以直接访问类的属性或者调用类的方法
3.2.1 类属性
- 类属性是针对类对象定义的属性
使用复制语句在class关键字下方可以定义类属性
类属性用于记录这个类相关的特性
示例:
class Tool():
count = 0
# 使用赋值语句定义类的属性,记录所有的工具的数量
def __init__(self,name):
self.name = name
Tool.count += 1
# 让类的属性加1
# 创建工具对象(对象在创建的时候,会自动调用初始化方法)
tool1 = Tool('锄头')
tool2 = Tool('斧头')
# 输出工具对象的总数
# 使用 ‘类名.属性名’ 来获取
print Tool.count
执行如下:
控制台显示如下:
3.2.2 类方法
- 类方法就是针对类对象定义的方法
在类方法内部就可以直接访问类属性或者调用其他类方法- 语法如下:
@classmethod
def 类方法(cls)
pass
示例:
class Car(object):
# 定义类属性
count = 0
@classmethod
def show_car_count(cls):
# cls.count:在类方法内部访问类属性
print '汽车对象的数量为 %s' % cls.count
def __init__(self,name):
self.name = name
Car.count += 1
# 创建car对象
car1 = Car('Bwm')
car2 = Car('Benci')
car3 = Car('Toyota')
# 调用类方法
Car.show_car_count()
执行如下:
控制台显示如下:
3.2.3 静态方法
静态方法
- 静态方法
在开发时,如果需要在类中封装一个方法,这个方法:
即不需要访问实例属性或者调用实例方法
也不需要访问类属性或者调用类方法
这时可以把这个方法封装成一个静态方法- 语法如下:
@staticmethod
def 静态方法():
pass
示例:
class Car(object):
@staticmethod
def tool():
# 静态方法不需要传递第一个参数:self
print 'By car to school is too convinent!'
# 通过类名,调用静态方法
# 不需要创建对象,直接可以调用
Car.tool()
执行如下:
控制台显示如下:
4. 以上几种的对比
4.1 类对象和实例对象的区别
类对象就是类本身,当遇见类的时候,就会创建新的命名空间,命名空间
包含所有类变量和方法定义的名称。
实例对象就是通过类对象创建出来的实例(类对象实例化之后返回的
就是实例对象),用来存储实例属性和存储实例对象的引用。
4.2 类属性和实例属性的区别
类属性:定义在类内部,方法外边,属于所有类对象和所有实例对象
调用:类对象.属性 = 值
实例属性:通过init初始化的变量和实例对象创建出来的属性
调用:实例对象.属性
4.3 类方法和实例方法和静态方法的区别
类方法:必须有一个参数,这个参数表示为当前类对象,一般为cls,在
方法的头部加上@classmethod
实例方法:必须有一个参数,表示当前实例对象,一般是self
静态方法:普通函数的格式,不需要强制要求传递参数,在方法的头部
加上注释@staticmethod一般用于实例对象、类对象无关的