1 面向对象和面向过程
面向过程编程:将满足需求的所有步骤、从头到尾、逐步实现、将功能模块封装为“函数”,执行过程就是调用不同的函数,在复杂编程时,各函数之间互相调用,不利于大型程序实现。
面向对象编程:根据不同的对象,确定其职责,封装不同的“方法”,执行过程是让各对象调用其方法,而不需要知道它的详细信息,需要时调用即可,不会造成互相影响,适合复杂项目开发。
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
对象:通过类定义的数据结构实例。对象包括数据成员(类变量、实例变量)和方法。 方法:类中定义的函数。
类变量:定义在类中且在函数体之外,在整个实例化的对象中是公用的。
实例变量:定义在实例中的变量,只作用于当前实例的类。
在 对象的方法内部 可以直接访问 对象的属性;同一个类创建的多个对象,它们的属性互不干扰
实例属性(变量)会屏蔽掉同名的类属性(变量)
In [1]: class Assassin: #定义类
...: def creed1(self):
...: print("Nothing is true.")
...: def creed2(self):
...: print("Everything is permitted.")
...: def introduce(self):
...: print("%s from %s"%(Ezio.name,Ezio.home)) #注意注意!要将Ezio改为self
In [2]: Ezio = Assassin() #创建对象
In [3]: Ezio.creed1() #使用方法
Nothing is true.
In [4]: Ezio.creed2()
Everything is permitted.
In [5]: Ezio.name = 'Ezio Auditore' #添加属性(即变量)
In [6]: Ezio.home = 'Firenze'
In [7]: print("%s from %s"%(Ezio.name,Ezio.home)) #获取属性
Ezio Auditore from Firenze
In [9]: Altair = Assassin() #创建另一个对象
In [10]: Altair.introduce() #←←←
Ezio Auditore from Firenze
不同类的对象之间引用属性:
class Home:
def __init__(self, area):
self.area = area #房间剩余的可用面积
self.containsItem = []
def __str__(self):
msg = "当前房间可用面积为:" + str(self.area)
if len(self.containsItem) > 0:
msg = msg + " 容纳的物品有: "
for temp in self.containsItem:
msg = msg + temp.getName() + ", "
msg = msg.strip(", ")
return msg
def accommodateItem(self,item):
needArea = item.getUsedArea()
if self.area > needArea:
self.containsItem.append(item)
self.area -= needArea
print("ok:已经存放到房间中")
else:
print("err:可用面积为:%d,当前要存放物品需面积为%d"%(self.area, needArea))
class Bed:
def __init__(self,area,name = '床'):
self.name = name; self.area = area
def __str__(self):
msg = '床的面积为:' + str(self.area)
return msg
def getUsedArea(self):
return self.area
def getName(self):
return self.name
newHome = Home(100)#创建一个新家对象#100平米
print(newHome)
newBed = Bed(20)#创建一个床对象
print(newBed)
newHome.accommodateItem(newBed)#把床安放到家里
print(newHome)
newBed2 = Bed(30,'席梦思')#创建一个床对象
print(newBed2)
newHome.accommodateItem(newBed2)#把床安放到家里
print(newHome)
类方法、静态方法:
类方法的第一个参数必须是类对象,一般以cls作为第一个参数;类方法可以对类属性进行修改:
class Game(object):
num = 0 #类属性
def __init__(self): #实例方法
self.name = 'han' #实例属性
@classmethod #类方法
def addnum(cls):
cls.num = 100
@staticmethod #静态方法
def pp():
print('some')
game = Game()
Game.addnum() #通过类的名字调用类方法
game.addnum() #通过类的对象调用类方法
print(Game.num)
Game.pp() #通过类去调用静态方法
game.pp() #通过实例调用静态方法
2 特殊方法
类的方法与普通的函数只有一个特别的区别——必须有一个额外的第一个参数名称, 按照惯例是 self
特殊方法: __init__() 用于初始化,定义了 __init__() 方法的话,类的实例化操作(创建对象)时会自动调用 __init__() 方法。
class Assassin:
def __init__(self,s_name,s_home):
self.name = s_name; self.home = s_home
def creed1(self):
print("Nothing is true.")
def creed2(self):
print("Everything is permitted.")
def introduce(self):
print("%s from %s"%(self.name,self.home))
Ezio = Assassin('Ezio Auditore','Firenze')
Altair = Assassin('Altaïr Ibn-La Ahad','Levant')
Ezio.introduce();Altair.introduce()
---------------------
Ezio Auditore from Firenze
Altaïr Ibn-La Ahad from Levant
特殊方法:__str__() 用于打印对象的描述信息。
class Assassin1:
def __init__(self,s_name,s_home):
self.name = s_name; self.home = s_home
class Assassin2:
def __init__(self,s_name,s_home):
self.name = s_name; self.home = s_home
def __str__(self):
return '%s from %s'%(self.name,self.home)
Ezio = Assassin1('Ezio Auditore','Firenze')
Altair = Assassin2('Altaïr Ibn-La Ahad','Levant')
print(Ezio);print(Altair)
---------------------------------------------
<__main__.Assassin1 object at 0x7f9bc2913d68>
Altaïr Ibn-La Ahad from Levant
__del__ : 析构函数,释放对象时自动调用:
class bye:
def __del__(self):
print('good bye')
p1 = bye();p2=p1;del p1 #引用
print('hi there')
---------------------------------
hi there
good bye
-------------------------------
class bye:
def __del__(self):
print('good bye')
p1 = bye();p2=p1;del p1;del p2
print('hi there')
-------------------------------------
good bye
hi there
需要获取对象的引用次数,可以调用sys模块中的getrefcount方法。
__new__() 方法:至少需要传递一个参数cls,表示需要实例化的类。__new__是object基类提供的内置静态方法
实例化对象时,先调用__new__()方法给对象分配空间。__new__()必须要有返回值,返回实例化出来的实例的引用(可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回)将这个引用传递给__init__()的参数self,再由init进行对象初始化(定义属性)
class test(object):
def __init__(self):
print('__init__()')
def __del__(self):
print('__del__()')
def __str__(self):
print('__str__()')
return 'str'
def __new__(cls):
print('__new__()')
return object.__new__(cls) # or return super().__new__(cls)
t = test()
------------------------------------------------------------------------
__new__()
__init__()
__del__()
3 私有属性、方法
类的私有属性:以两个下划线开头来声明该属性为私有,不能在类地外部被使用或直接访问。
类的私有方法:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类外部调用。
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print (self.__secretCount,end=' ');print(self.publicCount)
counter = JustCounter()
counter.count()
counter.count()
print(self.publicCount,end=' ');print(self.__secretCount)
-------------------------------------------------------------------
1 1
2 2
2 Traceback (most recent call last):
File "class JustCounter.py", line 11, in <module>
print(counter.publicCount,end = ' ');print(counter.__secretCount)
AttributeError: 'JustCounter' object has no attribute '__secretCount'
---------------------------------------------------------------------
class mes:
def __send(self): #私有方法
print("sending...")
def send(self,money): #公开方法
if money >10:
self.__send()
else:
print("please charge")
mesg = mes()
mesg.send(5);mesg.send(100)
-------------------------------------------------------------------
please charge
sending...
4 继承
单继承:子类(派生类),继承自一个父类(基类、超类),派生自同一父类的不同子类之间独立的方法不能互相调用。
子类不能访问父类的私有属性、私有方法。
class Cat(object):
def __init__(self, name, color):
self.name = name ; self.color = color
def run(self):
print("%s %s running"%(self.color,self.name))
class Bosi(Cat):
def setNewName(self, newName):
self.name = newName
def eat(self):
print("%s %s eating"%(self.color,self.name))
bs = Bosi("kit",'red') #继承了__init__方法
bs.eat()
bs.setNewName('kid')
bs.run()
------------------------------------------------------------
red kit eating
red kid running
------------------------
class A():
def __init__(self):
self.num1 = 100
self.__num2 = 200
def test1(self):
print('test1')
def __test2(self):
print('test2')
def test3(self):
self.__test2()
print(self.__num2)
class B(A):
def test4(self):
self.__test2()
print(self.__num2)
b = B()
b.test1()
# b.__test2() 报错
print(b.num1)
# print(b.__num2) 报错
b.test3()
# b.test4() 报错
-------------------------------------
test1
100
test2
200
重写:可以在子类重写父类的方法
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
Parent.myMethod(self) #在子类方法中调用父类方法
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
------------------------------------------------------
调用子类方法
调用父类方法
调用父类方法
多继承:一个子类继承自多个父类。圆括号里代表父类的顺序,若有同名方法,而在子类中未指定,将从左至右搜索。
即同名方法在子类中未找到时,从左到右查找父类中是否包含方法。
class Base(object):
pass
class A(Base):
pass
class B(Base):
pass
class C(A,B):
pass
c=C()
print(C.__mro__)
----------------------------
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
5 多态
定义时的类型和运行时的类型不一样,此时就成为多态。多态的好处在于,当函数需要传入多个子类时,只需要接收父类型就可以了,而具体调用的方法是作用在哪一个子类里,由运行时该对象的确切类型决定:
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
class Tortoise(Animal):
def run(self):
print('Tortoise is running slowly...')
def run(animal):
animal.run()
dog = Dog();dog.run()
cat = Cat();cat.run()
what = Animal();what.run()
isinstance(dog, Animal);isinstance(what,Dog)
run(what);run(dog);run(cat);run(Tortoise())