文章目录
1、类
1、面向对象编程
面向对象编程(object oriented programming,OOP):
-
对象 + 类 + 继承 + 多态 + 消息
-
现实世界存在的任何事务都可以称之为对象,对象一般由属性+方法组成。
-
类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
-
当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。
例子:
问题: 洗衣机里面放有脏衣服,怎么洗干净?
面向过程的解决方法:
- 执行加洗衣粉方法;
- 执行加水方法;
- 执行洗衣服方法;
- 执行清洗方法;
- 执行烘干方法;
面向对象的解决方法:
- 我先弄出两个对象:“洗衣机”对象和“人”对象
- 针对对象“洗衣机”加入一些属性和方法:“洗衣服方法”“清洗方法”、“烘干方法”
- 针对对象“人”加入属性和方法:“加洗衣粉方法”、“加水方法”
- 然后执行:
人.加洗衣粉; 人.加水
洗衣机.洗衣服; 洗衣机.清洗; 洗衣机.烘干
解决同一个问题 ,
面向过程编程就是将解决这个问题的过程拆成一个个方法(是没有对象去调用的),通过一个个方法的执行来解决问题。
面向对象编程就是先抽象出对象,然后用对象执行方法的方式解决问题。
1.1 面向过程和面向对象的比较
面向过程:
-
面向过程就是以过程为中心,分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
-
优点:
性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;
比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。 -
缺点:没有面向对象易维护、易复用、易扩展(耦合性高,导致可维护性比较差)
面向对象:
-
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
-
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
-
可维护性主要表现在3个方面:可理解性、可测试性和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。
-
缺点:性能比面向过程低
1.2 面向对象编程的特性
三大基本特性:封装,继承,多态
封装
-
封装,就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
-
一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。
-
在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
-
封装机制保证了类内部数据结构的完整性,因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。
-
对一个类实现良好的封装,用户只能借助暴露出来的类方法来访问数据,我们只需要在这些暴露的方法中加入适当的控制逻辑,即可轻松控制用户对类中属性或方法的不合理操作。
-
对类进行良好的封装,还可以提高代码的复用性。
继承
-
继承,指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。
-
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
-
通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。
-
要实现继承,可以通过 “继承”(Inheritance)和“组合”(Composition)来实现。
-
继承概念的实现方式有二类:实现继承与接口继承。
实现继承是指直接使用父类的属性和方法而无需额外编码的能力;
接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
多态
-
多态,是指一个类实例的相同方法在不同情形有不同表现形式。
-
多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
2、类的基本概念
数据成员:
- 类变量或者实例变量,用于处理类及其实例对象的相关的数据。
类变量:
-
类变量在整个实例化的对象中是公用的。所有实例共享一个属性
-
类变量定义在类中且在函数体之外
-
类变量通常不作为实例变量使用。
-
类方法的调用方式有 2 种,
既可以使用类名直接调用,也可以使用类的实例化对象调用。 -
可以通过类名修改类变量,会作用到所有的实例对象。
-
可以通过类对象可以访问类变量,但无法修改类变量的值。这是因为,通过类对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量。
-
可以动态的为类和对象添加类变量
实例变量:
-
在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,
-
是在类声明的内部但是在类的其他成员方法之外声明的。
-
不可以对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,此时访问到的是实例属性
当删除该实例属性后,再使用相同的名称,访问到的将是类属性。 -
实例变量指的是在任意类方法内部,以“self.变量名”的方式定义的变量,其特点是只作用于调用方法的对象。另外,实例变量只能通过对象名访问,无法通过类名访问。
class CLanguage :
# 下面定义了2个类变量
name = "C语言中文网"
add = "http://c.biancheng.net"
# 下面定义了一个say实例方法
def say(self, content):
print(content)
# 使用类名直接调用
print(CLanguage.name)
print(CLanguage.add)
# 使用类对象调用
clang1 = CLanguage()
print(clang1.name)
print(clang1.add)
# 使用类名修改类变量的值
CLanguage.name = "Python教程"
CLanguage.add = "http://c.biancheng.net/python"
print(CLanguage.name)
print(CLanguage.add)
# 动态地为类和对象添加类变量
clang2 = CLanguage()
CLanguage.catalog = 13
print(clang2.catalog)
局部变量:
- 定义在方法中的变量,只作用于当前实例的类。
实例化:
- 创建一个类的实例,类的具体对象。
- 创建类对象的过程,又称为类的实例化。
- 定义的类只有进行实例化,也就是使用该类创建对象之后,才能得到利用。
方法:
- 类中定义的函数。
对象:
- 通过类定义的数据结构实例。
- 对象包括两个数据成员(类变量和实例变量)和方法。
访问类的属性:
-
hasattr(obj, name):检查是否存在一个属性。
-
getattr(obj, name[, default]) ;访问对象的属性。
-
setattr(obj, name, value) :设置一个属性。如果属性不存在,会创建一个新属性。
-
delattr(obj, name) :删除属性。
'''
__init__是类的构造函数或者初始化方法,当创建了这个类的实例就会调用该方法
self代表类的实例,代表当前对象的地址
self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
self 不是 python 关键字,可以换成别的也可以(一般习惯用self)
empCount是 类变量
'''
class Employee:
'所有员工的基类'
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
emp1 = Employee('bob', 100)
hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age') # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(emp1, 'age') # 删除属性 'age'
3、继承与多态
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
什么时候使用继承:
- 假如我需要定义几个类,而类与类之间有一些公共的属性和方法,这时我就可以把相同的属性和方法作为基类的成员,而特殊的方法及属性则在本类中定义。这样子类只需要继承基类(父类),子类就可以访问到基类(父类)的属性和方法了,它提高了代码的可扩展性和重用性。
判断继承:
-
isinstance(obj, Class) :如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
-
issubclass(sub,sup) :用于检查类继承。判断一个类是另一个类的子类或者子孙类,
子类继承父类构造函数:
-
:子类可以没有构造函数,表示同父类构造一致:
子类不重写__init__()方法,实例化子类后,会自动调用父类的__init__()的方法。 -
子类重写__init__()方法,实例化子类后,将不会自动调用父类的__init__()的方法。
-
子类重写__init__()方法又需要调用父类的构造函数的方法:
子类既继承了父类一部分或者全部的属性,自己又新增一部分属性。(先继承再构造)
- 可以将实例用作属性添加到另一个类中去, 则每次调用__init__方法的时候都将执行该操作
多继承:
-
一个类继承自多个类就是多继承,它将具有多个类的特征。
-
如果子类和父类有相同的方法,就会调用子类中的方法。
-
如果不同的父类中存在着相同的方法名称,多个父类会根据它们在列表中的顺序被检查,如果对下一个类存在两个合法的选择,选择第一个父类
多态:鸭子类型
-
子类可以对方法重写
-
不同的子类对象调用相同的父类方法,产生不同的执行结果
-
多态可以增加代码的灵活度
# 父类
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
self.weight = 'weight'
def talk(self):
print("person is talking....")
class Book():
pass
# 直接继承父类的构造函数,实例化后自动调用person的__init__方法
# 子类新增方法listen
class Janpanese(Person):
def listen(self):
print('is listening...')
# 重写__init__方法,并继承父类的构造方法
# 子类重构方法talk
class Chinese(Person):
def __init__(self, name, age, language):
Person.__init__(self, name, age)
self.language = language # 定义类的本身属性
# 创建一个新的Book实例,并将其存储在属性self.book中,
# 每次调用__init__方法的时候都将执行该操作
self.book = Book()
# 子类重构talk方法
def talk(self):
print('%s is speaking chinese' % self.name)
# 多继承
# 重写__init__方法,并继承父类的构造方法
# 新增方法height
class American(Person, Chinese):
def __init__(self, name, age, language):
super(Person,self).__init__(name,age,)
super(Chinese,self).__init__(la