Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。
一、面向对象技术简介
- 类(class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖,也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类继承基类的字段和方法。继承也允许把一个派生类的对象作为一个基类的对象对待。例如,有这样一个设计:一个dog类型的对象派生自animal类,这是模拟“是一个”关系(例如,dog是一个animal)
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
二、什么是面向对象的程序设计及为什么要有它
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了程序的复杂度,复杂的问题简单化,流程化
缺点是:扩展性差,一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计的核心是对象(上帝式思维),对象是特征(变量)与技能(函数)的结合体,要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。
在现实世界中:对象----(共同的特征与技能)--->类
在程序中:先定义类----(实例化)----->对象
小结:
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差
三、类和对象
3.1 什么是对象,什么是类
Python中一切皆为对象,且Python统一了类与类型的概念,类型就是类
类定义
语法格式如下:
1. class 类名: # 类名首字母大写 ‘‘‘注释‘‘‘ 类体 2. class ClassName: <statement-1> . . . <statement-N>
类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。
类对象
类对象支持两种操作:属性引用和实例化
属性引用使用和Python中所有的属性引用一样的标准语法:obj.name
类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样的:
class Myclass: """一个简单的类实例""" i=12345 def f(self): return ‘hello world‘ # 实例化类 x=Myclass() # 访问类的属性和方法 print("MyClass 类的属性i为:",x.i) print("MyClass 类的方法f输出为:",x.f())
以上创建了一个新的类实例并将对象赋给局部变量x,x为空的对象。
输出结果为:
MyClass 类的属性i为: 12345 MyClass 类的方法f输出为: hello world
很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为__init__()的特殊方法(构造方法),像下面这样:
def __init__(self): self.data = [] #定义空列表
当然,__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上。例如:
class Teacher: school=‘oldboy‘ #定义对象的共同特征 def __init__(self,name,age): #用户创建对象传入的参数 self.name=name self.age=age def talk(self): print(‘is talking‘) def walk(self): print(‘is walking‘) t1=Teacher(‘egon‘,23) # 实例化:__init__(t1,‘egon‘,23) t2=Teacher(‘alex‘,32) # 实例化:__init__(t2,‘alex‘,32)
self代表类的实例。而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,按照惯例它的名称是self。
# 属性引用 # 数据属性 # print(Teacher.school) # print(Teacher.__dict__) # 函数属性 # print(Teacher.walk) # print(t1.name) # print(t2.talk)
类的方法
在类的内部,使用def关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数,self代表的是类的实例。
#类定义 class people: #定义基本属性 name = ‘‘ age = 0 #定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 #定义构造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" %(self.name,self.age)) # 实例化类 p = people(‘runoob‘,10,30) p.speak()
类有两种作用:属性引用和实例化
1)属性引用(类名.属性)
class Student: school = ‘oldboy‘ def __init__(self,name,age): #只用来初始化的,并且一定不能有返回值 self.name=name self.age=age def study(self): print(‘%s is studying‘ %self.name) s1=Student(‘egon‘,84) #步骤一:造出对象s1 #步骤二:初始化s1,把s1,‘egon‘,84传给__init__
__init__只用来初始化函数的,并且一定不能有返回值
数据属性、函数属性:
print(Student.school) #引用类的数据属性 #输出结果:oldboy print(Student.study) #引用类的函数属性 #输出结果:<function Student.study at 0x00000149F72B7620>
对象的修改、删除和添加:
#修改 Student.school=‘偶的博爱‘ #修改变量school的值 print(Student.school) #输出结果:偶的博爱 #删除 del Student.school #删除school属性的值 print(Student.__dict__) #类名.__dict__:查出的是一个字典,key为属性名value为属性值 输出结果:(上面为没删除之前,删除之后,通过__dict__可查看到类的信息) {‘__module__‘: ‘__main__‘, ‘school‘: ‘偶的博爱‘, ‘__init__‘: <function Student.__init__ at 0x000001BB20097598>, ‘study‘: <function Student.study at 0x000001BB20097620>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Student‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Student‘ objects>, ‘__doc__‘: None} {‘__module__‘: ‘__main__‘, ‘__init__‘: <function Student.__init__ at 0x000001BB20097598>, ‘study‘: <function Student.study at 0x000001BB20097620>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Student‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Student‘ objects>, ‘__doc__‘: None} #添加 Student.x=6666666666666 #添加一个属性x=6666666666666 print(Student.x) print(Student.__dict__) #可查看到字典里多了一值
只要是对象绑定方法都会字典传值,把自己传给函数
s1.study() #调用函数 egon is studying
2)我们定义的类的属性到底存在哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
3)特殊的类属性
类名.__name__ # 类的名字(字符串)
类名.__doc__ # 类的文档字符串
类名.__base__ # 类的第一父类
类名.__bases__ # 类所有父类构成的元组
类名.__dict__ # 类的字典属性
类名.__module__ # 类定义所在的模块
类名.__class__ # 实例对应的类(仅新式类中)
4)对象/实例
对象/实例本身只有数据属性,但是Python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法,绑定方法唯一绑定一个对象,同一个类的方法绑定到不同的对象上,属于不同的方法,内存地址都不会一样
对象的绑定方法的特别之处在于:obj.func()会把obj传给func的第一个参数
5)类名称空间与对象/实例名称空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:数据属性和函数属性
其中类的数据属性是共享给所有对象的,而类的函数属性是绑定到所有对象的
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会优先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类,最后都找不到就抛出异常
练习一堆类:
# 老师类 class Teacher: school=‘oldboy‘ def __init__(self,name,age): self.name=name self.age=age def talk(self): print(‘is talking‘) def walk(self): print(‘is walking‘) t1=Teacher(‘egon‘,23) # 实例化:__init__(t1,‘egon‘,23) t2=Teacher(‘alex‘,32) # 实例化:__init__(t2,‘alex‘,32)
# 学生类 class Student: job=‘student‘ def __init__(self,name,age): self.name=name self.age=age def talk(self): print(‘is talk‘) def eat(self): print(‘is eating‘) s1=Student(‘buer‘,20) # 实例化:__init__(s1,‘buer‘,20) s2=Student(‘dongbei‘,22) # 实例化:__init__(s2,‘dongbei‘,22) print(s1)
# 狗类 class Dog: bottle=‘dog‘ def __init__(self,name,color): self.name=name self.color=color def talk(self): print(‘汪汪汪‘) def eat(self): print(‘dog good‘) d1=Dog(‘哈士奇‘,‘blank‘) # 实例化:__init__(d1,‘哈士奇‘,‘blank‘) d2=Dog(‘泰迪‘,‘brown‘) # 实例化:__init__(d2,‘泰迪‘,‘brown‘)
# 猪类 class Pig: bottle=‘big‘ def __init__(self,name): self.name=name def talk(self): print(‘哼哼哼‘) def eat(self): print(‘pig good‘) p1=Pig(‘xiangzhu‘) # 实例化:__init__(p1,‘xiangzhu‘) p2=Pig(‘huazhu‘) # 实例化:__init__(p2,‘huazhu‘) print(p1)
# 动物类 class Animal: local=‘zoo‘ def __init__(self,name,kind): self.name=name self.kind=kind def talk(self): print(‘people do not know what to say‘) def pull(self): print(‘no need for toilet‘) a1=Animal(‘xingxing‘,‘monkey‘) a2=Animal(‘fenda‘,‘panda‘)