面向对象三大特性
- 封装:根据职责将属性和方法封装到一个抽象的类中
- 继承:实现代码的重用,相同的代码不需要重复编写
- 多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
dir内置函数
方法名 :python提供的内置函数和属性
可以使用:
dir([]) #查看列表的内置函数和属性
定义类
只包含方法
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
方法的定义格式与函数基本一样,区别在于方法的第一个参数必须是self,并且类名的命名方式必须是大驼峰命名法
self参数
哪个对象调用该方法,self就指该对象:
class Cat:
def eat(self):
print("%s eat fish" %self.name)
tom = Cat()
tom.name = "Tom" #为tom增加name属性(不推荐)
tom.eat() #输出Tom eat fish
bob = Cat
bob.name ="Bob"
bob.eat() #输出Bob eat fish
初始化方法
- 当使用类名创建对象时,会自动执行以下操作:
- 为对象在内存中分配空间:创建对象
- 为对象的属性设置初始值:初始化方法(init)
- 这个初始化方法就是init方法,init 是对象的内置方法,init 方法是专门用来定义一个类具有哪些属性的方法
class Cat: def __init__(self): print("这是一个初始化方法") # 使用类名()创建对象时,会自动调用初始化方法__init__ tom = Cat() #输出结果 这是一个初始化方法
在初始化方法内部定义属性
在init方法内部使用self.属性名=属性的初始值 就可以定义属性。在定义属性后,再使用该类创建对象,都会拥有该属性
class Cat:
def __init__(self):
self.name="Hello"
tom = Cat()
bob = Cat()
print(tom.name)
print(bob.name)
# 输出结果
Hello
Hello
改造初始化方法
class Cat:
def __init__(self,name):
self.name=name
tom = Cat("Tom")
bob = Cat("Bob")
print(tom.name) #输出Tom
print(bob.name) #输出Bob
内置方法和属性
del 方法
- 当一个对象被从内存中销毁时,自动调用del方法
- 如果希望对象在被销毁前再做一些事情,可以考虑del 方法
- 生命周期:
- 一个对象从调用类名()创建,生命周期开始
- 一个对象del对象一旦被调用,生命周期结束
- 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
在代码执行结束后回收
tom是全局变量,del 函数会在所有代码执行完毕后自动调用
class Cat:
def __init__(self,name):
self.name=name
def __del__(self):
print("%s 已销毁"%self.name)
tom = Cat("Tom")
print("----------------------")
# 输出结果
----------------------
Tom已销毁
使用del方法删除对象
class Cat:
def __init__(self,name):
self.name=name
def __del__(self):
print("%s 已销毁"%self.name)
tom = Cat("Tom")
del tom
print("----------------------")
# 输出结果
Tom已销毁
----------------------
str 方法
返回对象的描述信息,print函数输出使用,必须返回一个字符串
class Cat:
def __init__(self,name):
self.name=name
def __del__(self):
print("%s 已销毁"%self.name)
tom = Cat("Tom")
print(tom)
#输出结果
<__main__.Cat object at 0x000002D897863B88>
Tom 已销毁
使用str方法后:
class Cat:
def __init__(self,name):
self.name=name
def __del__(self):
print("%s 已销毁"%self.name)
def __str__(self):
return "hello world"
tom = Cat("Tom")
print(tom)
# 输出结果
hello world
Tom 已销毁
需求分析
- 画类图
- 被使用的类应该先开发
- 类与类之间调用是通过对象实现的
身份运算符
身份运算符被用于比较两个对象的内存地址是否一致(是否是对同一个对象的引用)。在Python中对None比较时,建议使用is判断
- is: is是判断两个标识符是不是引用同一个对象。 x is y 类似id(x)==id(y)
- is not: is not是判断两个标识符是不是引用不同对象。 x is not y 类似id(x)!=id(y)
注:id()是查看变量的内存地址
is和==的区别
- is用于判断两个对象引用对象是否是同一个(比较地址)
- ==用于判断引用对象的值是否相等
私有属性和私有方法
私有属性和私有方法只能在对象的内部被访问,不能在外部进行访问
- 私有属性:对象不希望公开的属性
- 私有方法:对象不希望公开的方法
定义方法,在属性名或方法名前加两个下划线
私有属性
class Woman:
def __init__(self,name):
self.name = name
self.__age = 18
def secret(self):
print("%s的年龄为%d" % (self.name,self.__age)) #true,在对象内部的方法可以访问私有属性
xiaofang = Woman("小芳")
print(xiaofang.__age) # false,在对象外部不能访问私有属性
xiaofang.secret()
私有方法
class Woman:
def __init__(self,name):
self.name = name
self.__age = 18
def __secret(self):
print("%s的年龄为%d" % (self.name,self.__age))
xiaofang = Woman("小芳")
xiaofang.__secret() #error,在对象外部不能访问私有方法
伪私有属性和私有方法
Python中,并没有真正意义上的私有。在给属性、方法命名时,实际上是对名称做了一些特殊处理,使得外界无法访问。
可以使用以下方式访问私有属性和方法(在开发中不要使用这种方法访问私有属性和私有方法)
class Woman:
def __init__(self,name):
self.name = name
self.__age = 18
def __secret(self):
print("%s的年龄为%d" % (self.name,self.__age))
xiaofang = Woman("小芳")
print(xiaofang._Woman__age)
xiaofang._Woman__secret()
继承
继承语法:
class 类名(父类名):
pass
继承的传递性
如果B类继承A类,C类继承B类,则C类也继承自A类。子类可以访问父类的公共属性和方法。
重用
在子类中重写父类的同名方法,使用子类对象调用方法时,会调用子类中重写的方法。
覆盖
子类方法完全不同于父类的同名方法
class Dog:
def bark(self):
print("汪汪汪")
class Xiaotianquan(Dog):
def bark(self):
print("可以说话")
xiaotian = Xiaotianquan()
xiaotian.bark()
#输出结果 : 可以说话
扩展
子类方法在父类同名方法的基础上再加上额外的属性。使用super().创建一个新的对象调用父类中封装的方法
class Dog(Animal):
def bark(self):
print("汪汪汪")
class Xiaotianquan(Dog):
def bark(self):
#1.针对子类的特殊需求,编写代码
print("可以说话")
#2. 使用super().调用原本在父类中封装的方法
super().bark()
#3. 增加其他子类的方法
print("asdsadddd")
xiaotian = Xiaotianquan()
xiaotian.bark()
# 输出结果
可以说话
汪汪汪
asdsadddd
多继承
一个子类可以继承多个父类,并且拥有所有父类的属性和方法:
class 类名(父类名1,父类名2....):
pass
如果在多个父类中具有同名的方法或属性,应避免使用多继承。
MRO方法顺序
在多继承中可以使用类的内置属性mro查看方法的调用顺序
class A:
pass
class B:
pass
class C:
pass
class D(C,B,A):
pass
print(D.__mro__)
#输出结果
(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>) #结果中显示的顺序即对方法和属性查找的顺序
注:Object类是所有类的基类
多态
不同的子类对象调用相同的父类方法,产生不同的执行结果
class Dog:
def __init__(self,name):
self.name = name
def game(self):
print("%s正在玩耍" %(self.name))
class Xiaotianquan(Dog):
def game(self):
print("%s正在巡查公务" % (self.name))
class Person:
def __init__(self,personName):
self.personName = personName
def playWith(self,dog):
print("%s与%s正在玩耍" % (self.personName,dog.name))
dog.game() #传递不同的对象产生不同的结果
person = Person("小明")
dog = Dog("旺财")
person.playWith(dog)
#输出结果
小明与旺财正在玩耍
旺财正在玩耍
xiao = Xiaotianquan("哮天犬")
person.playWith(xiao)
#输出结果
小明与哮天犬正在玩耍
哮天犬正在巡查公务
类对象
在Python中,类也是一个对象,由类创建的对象叫做实例对象
类属性
类属性就是给类对象定义的属性,通常用来记录这个类相关的特征
一个工具类,需要统计所有该类创建的实例对象的数量
class Tool(object):
count = 0
def __init__(self,name):
self.name = name
# 让类属性加1
Tool.count+=1
tool1 = Tool("斧头")
tool2 = Tool("铲子")
print(Tool.count) # 输出结果 :2
类方法
针对类对象定义的方法,语法如下:
@classmethod #告诉解释器这是一个类方法
def 类方法名(cls): #第一个参数必须是cls
pass
实例:使用一个类方法打印输出创建的工具个数
class Tool(object):
count = 0
def __init__(self,name):
self.name = name
# 让类属性加1
Tool.count+=1
@classmethod
def showToolCount(cls):
print("已经创立了%d个工具" % (cls.count))
tool1 = Tool("斧头")
tool2 = Tool("铲子")
#类方法只能通过类名调用,cls不需要传递,解释器会自动传递
Tool.showToolCount() #输出结果:已经创立了2个工具
静态方法
如果一个方法同时满足以下两个条件:
- 不需要访问实例属性或调用实例方法
- 不需要访问类属性或调用类方法
那么该方法可以封装成一个静态方法,语法如下:
调用方式与类方法调用方法相同,都不需要创建对象@staticmethod def 静态方法名(): pass
方法分类:
- 实例方法:在方法内部需要访问实例属性(实例方法内部可以使用类名访问类属性)
- 类方法:方法内部只需要访问类属性
- 静态方法:方法内部,不需要访问实例属性和类属性