面向对象(类编程)
简介:全称Object Oriented Programing(OOP) ,是一种程序设计思想,面向对象编程
面向对象名词简介
借鉴菜鸟教程
- 类(class):类事抽象的模板,用来描述具有相同属性和方法的对象的集合。定义了集合中每个对象所拥有的方法,对象是类的实例
- 方法:类中自定义的函数
- 类变量:类变量在整个实例化的对象中是公用的,每个对象都可以调用类变量。类变量定义在类中且函数体之外。类变量通常不作为实例变量使用
- 数据成员:类变量或者实例变量用于处理类及实例对象所使用的相关数据
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对齐进行重新,这个过程叫做方法的覆盖,也叫做方法的重写
- 局部变量:定义在方法中的变量,只作用与当前实例的类
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量也叫做实例变量
- 继承:既一个派生类(同有的方法调用另一个类),继承基类(例如Person)的字段和方法。例如:A类和B类都需要调用相同的方法,既创建C类,把相同的方法放到C类,A类和B类继承C类,A类和B类就可以直接调用C类的方法了
- 实例化:创建一个类的实例,类的具体对象,例如:人类是一个类的集合,你不知道里边有谁谁谁,但是我如果说马云,你肯定就想到了他的身高,长相,money等等,这个过程也叫做实例化
- 对象:也叫做实例,通过类定义的数据结构实例,对象包括两个数据成员(类变量和实例变量)和方法,例如:你就知道人类,但是你不知道某个人,如果给这某个人来一个定义,他是马云,那么马云就是一个对象,它是人类的对象。
面向对象最重要的概念就是类(class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都具有相同的方法,但各自的数据不同
类的相关知识
- 类名一共有三个作用:
- 可以调用类中的变量
Fruits.discount
- 实例化创建一个对象 Fruits('苹果',5)
- 调用一个方法(现在不常用):类名.方法名()
- 可以调用类中的变量
- 对象名
- 查看对象的属性 对象名.属性
- 调用对象的方法 对象名.方法名()
- 类和对象和实例和实例化
- 什么是类 ? Dog Person Fruits
- 什么是对象 ?
alex
二饼 旺财 苹果 李子 - 什么是实例 ? 对象就是实例
- 实例化 是一个动词 类创造实例的过程叫做实例化
- 对象 = 类名() 实例化
属性引用(类名.属性)
''' class 类名: '类的文档及字符串' '类体' ''' # 我们创建一个类 class Person: pass # 创建一个人类 class Person: # 创建一个Person类 role = 'person' # 人的属性都是人 def walk(self): # 人可以走路,定义一个方法 print("Person is walking...") print(Person.role) # 查看人的属性 print(Person.walk) # 引用人的走路方法,注意这里不是调用,函数需要后面加括号,才算调用
实例化:(类名加括号就是实例化,会自动触发__init__
函数的运行,可以用它来为每个实例定义自己的特征)
# 创建一个人类 class Person: # 创建一个Person类 role = 'person' # 人的属性都是人 def __init__(self,name): self.name = name # 每一个角色都有属于自己的名字 def walk(self): # 人可以走路,定义一个方法 print("Person is walking...") print(Person.role) # 查看人的属性 print(Person.walk) # 引用人的走路方法,注意这里不是调用,函数需要后面加括号,才算调用
实例化的过程就是类-->对象的过程
原本我们只有一个Person类,但在这个过程中,产生了一个mhy
对象,他有自己的名字等等
语法:对象 = 类名(参数)
查看属性及调用方法
mhy = Person('mhy') # 类名()就等于执行Person.__init__ print(mhy.name) # 查看属性直接 对象名.属性名 print(Person.walk()) # 调用方法,对象名.方法名()
关于self
self:在实例化过程中自动将对象/实例本身传给__init__
函数的第一个参数,你也可以起别的名称,但是不要用,这是一种开发规范
类属性的补充:
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 print(Person.__name__) # 类的名字(字符串) # 结果 Person print(Person.__doc__) # 类的注释文档 # 结果 这是一个人类 print(Person.__base__) # 查看类的第一个父类(在讲继承时会讲) # 结果 <class '__main__.jicheng'> print(Person.__bases__) # 类所有父类构成的元组(在讲继承时会讲) # 结果 (<class '__main__.jicheng'>,) print(Person.__dict__) # 类的字典属性 # 结果 {'__module__': '__main__', '__doc__': '这是一个人类', 'role': 'person', '__init__': <function Person.__init__ at 0x031CEF18>, 'walk': <function Person.walk at 0x031CEF60>} print(Person.__module__) # 类定义所在的模块 # 结果 __main__ print(Person.__class__) # 实例对应的类(仅新式类中) # 结果 <class 'type'>
例子:人狗大战
class Person: # 定义一个人类 role = 'person' def __init__(self,name,hp,ad,sex,job): self.username = name # 每一个角色都有自己的昵称; self.hp = hp # 每一个角色都有自己的hp; self.ad = ad # 每一个角色都有自己的攻击力; self.sex = sex # 每一个角色都有自己的性别; self.job = job # 每一个角色都有自己的职业; def attack(self,dog): # 攻击狗的方法 # 人可以攻击狗,这里的狗也是一个对象。 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 dog.hp -= self.ad print('%s攻击了%s,%s掉了%s点血'%(self.username,dog.name,dog.name,self.ad)) class Dog: # 定义一个狗类 role = 'dog' def __init__(self,name,kind,hp,ad): # 初始化方法 self.name = name # 每一只狗都有自己的昵称; self.kind = kind # 每一只狗都有自己的品种; self.hp = hp # 每一只狗都有自己的血量 self.ad = ad # # 每一只狗都有自己的攻击力 def bite(self,person): # 狗咬人的方法 # 狗可以咬人,这里的狗也是一个对象。 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 person.hp -= self.ad print('%s咬了%s,%s掉了%s点血'%(self.name,person.username,person.username,self.ad)) # 谁在类的外部调用了这个方法,方法中的第一个self参数就是谁 alex = Person('alex',100,5,'不详','乞丐') # 实例化一个人对象 wangcan = Dog('旺财','teddy',2000,300) # 实例化一个狗 对象 erbing = Dog('二饼','哈士奇',10000,500) # 不同的对象 erbing.bite(alex) # Dog.bite(二饼,alex) # 狗对象调用狗的咬人方法攻击了人 print(alex.hp) # 查看人的血量
例子:求圆的面积及体积
from math import pi # 导入3.14 class Circle: ''' 定义了一个圆形类; 提供计算面积(area)和周长(perimeter)的方法 ''' def __init__(self,radius): self.radius = radius def area(self): return pi * self.radius * self.radius def perimeter(self): return 2 * pi *self.radius circle = Circle(10) #实例化一个圆 area1 = circle.area() #计算圆面积 per1 = circle.perimeter() #计算圆周长 print(area1,per1) #打印圆面积和周长
类命名空间与对象、实例的命名空间
创建一个类,就好创建一个类的名称空间,用来存储类中定义的名称,这些名称称之为类的属性
而类有两种属性:静态属性和动态属性
- 静态属性就是直接在类中的变量
- 动态属性就是定义在类中的方法
其中类的属性是共享给所有对象的
print(id(erbing.role)) 47994208 print(id(Dog.role)) 47994208
而类的动态属性是绑定到所有对象的
print(alex.attack) print(Person.attack) # 结果 <bound method Person.attack of <__main__.Person object at 0x0362EBD0>> <function Person.attack at 0x037E12B8>
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
例如:obj.name
会先在obj
自己的命名空间中查找name,查找不到则回去类里去找,类也找不到会去父类找..最后都找不到会抛出异常
组合用法
软件的重要用法除了继承之外还有另一种方式,既 组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class arms: def prick(self): # 这是该装备的主动技能,扎死对方 print('我靠 居然使用了无尽') # obj.life_value -= 500 # 假设攻击力是500 class Person: # 定义一个人类 '''这是一个人类''' role = 'person' # 人的角色属性都是人 def __init__(self, name): self.name = name # 每一个角色都有自己的昵称; self.arms = arms() # 给角色绑定一个武器; mhy = Person('mhy') mhy.arms.prick() # mhy组合了一个武器的对象,可以直接mhy.arms来使用组合类中的所有方法
组合例子
圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。
这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用
from math import pi class Circle: ''' 定义一个圆形类, 提供计算面积(area)和周长(perimeter)的方法 ''' def __init__(self,radius): self.radius = radius def area(self): '''计算圆形面积公式:πr²''' return pi* self.radius * self.radius def perimeter(self): '''计算圆的周长公式:2πr''' return 2 * pi * self.radius ret_object = Circle(5) # 实例化一个圆 print(ret_object.area()) # 打印圆计算的面积 print(ret_object.perimeter()) # 打印圆计算的周长 class Ring: ''' 定义一个圆环类, 提供了圆环的面积和周长的方法 ''' def __init__(self,radius_outside,radius_inside): self.radius_inside = Circle(radius_inside) self.radius_outside = Circle(radius_outside) def ring_area(self): return self.radius_outside.area() - self.radius_inside.area() def ring_perimeter(self): return self.radius_outside.perimeter() + self.radius_inside.perimeter() ring = Ring(10, 5) # 实例化一个圆环 print(ring.ring_area()) # 打印圆环计算的面积 print(ring.ring_perimeter()) # 打印圆环计算的周长
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
初识面向对象小结
定义一个人类
class Person: # 定义一个人类 role = 'person' # 人的角色属性都是人 def __init__(self, name, aggressivity, life_value, money): self.name = name # 每一个角色都有自己的昵称; self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; self.life_value = life_value # 每一个角色都有自己的生命值; self.money = money def attack(self,dog): # 人可以攻击狗,这里的狗也是一个对象。 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 dog.life_value -= self.aggressivity
定义一个狗类
class Dog: # 定义一个狗类 role = 'dog' # 狗的角色属性都是狗 def __init__(self, name, breed, aggressivity, life_value): self.name = name # 每一只狗都有自己的昵称; self.breed = breed # 每一只狗都有自己的品种; self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; self.life_value = life_value # 每一只狗都有自己的生命值; def bite(self,people): # 狗可以咬人,这里的狗也是一个对象。 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 people.life_value -= self.aggressivity
创建一个武器类
class Weapon: def __init__(self,name, price, aggrev, life_value): self.name = name self.price = price self.aggrev = aggrev self.life_value = life_value def update(self, obj): #obj就是要带这个装备的人 obj.money -= self.price # 用这个武器的人花钱买所以对应的钱要减少 obj.aggressivity += self.aggrev # 带上这个装备可以让人增加攻击 obj.life_value += self.life_value # 带上这个装备可以让人增加生命值 def prick(self, obj): # 这是该装备的主动技能,扎死对方 obj.life_value -= 500 # 假设攻击力是500
测试交互
lance = Weapon('长矛',200,6,100) egg = Person('egon',10,1000,600) #创造了一个实实在在的人egg ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 #egg独自力战"二愣子"深感吃力,决定穷毕生积蓄买一把武器 if egg.money > lance.price: #如果egg的钱比装备的价格多,可以买一把长矛 lance.update(egg) #egg花钱买了一个长矛防身,且自身属性得到了提高 egg.weapon = lance #egg装备上了长矛 print(egg.money,egg.life_value,egg.aggressivity) print(ha2.life_value) egg.attack(ha2) #egg打了ha2一下 print(ha2.life_value) egg.weapon.prick(ha2) #发动武器技能 print(ha2.life_value) #ha2不敌狡猾的人类用武器取胜,血槽空了一半
继承
什么是继承
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
python中类的继承分为:单继承和多继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__
)的实现
>>> ParentClass1.__bases__ (<class 'object'>,) >>> ParentClass2.__bases__ (<class 'object'>,)