类中: ①特征被称为属性;②行为被称为方法;③三要素:类名、属性、方法;
dir函数可以查看对象的所有方法;
dir显示的方法中,__方法名__
格式的方法是Python
提供的内置方法/属性
;
类中的方法第一个参数必须是self(类似Java中的this?);
创建第一个类:
class Cat:
def eat(self):
print("小猫爱吃鱼!")
def drink(self):
print("小猫爱喝水!")
tom = Cat() # 和Java不同,不需要使用 new
tom.eat()
tom.drink()
print(tom) # 输出对象变量
print("%x" % id(tom)) # 输出16进制的地址
print("%d" % id(tom)) # 输出10进制的地址
输出:
引用的强调
Python如果不想修改类,可以直接给对象增加属性(不同于其他语言!)(这种方式不推荐);
self关键字(Java中的this关键字): 哪一个对象调用的这个方法,self就是哪个对象的引用,可以通过self.访问对象的属性和方法;
初始化方法__init__:
当使用类名()创建对象时,会自动执行以下操作:
①. 为对象在内存中分配空间 – 创建对象;
②. 为对象的属性 设置初始值 – 初始化方法(init);
这个初始化方法就是__init__方法,__init__是对象的内置方法。
__init__方法是专门用来定义一个类具有哪些属性的方法!
在初始化方法__init__内部定义属性:
在init方法内部使用self.属性名 = 属性的初始值就可以定义属性;
定义属性之后,再使用该类创建的对象,都拥有该属性;
使用:
class Cat:
def __init__(self):
print("这是一个初始化方法")
self.name = "Tom"
def eat(self):
print("%s 爱吃鱼" % self.name)
tom = Cat()
print(tom.name)
tom.eat()
输出:
这是一个初始化方法
Tom
Tom 爱吃鱼
初始化方法__init__中带参数,构造对象;
class Cat:
def __init__(self, new_name):
print("这是一个初始化方法")
self.name = new_name
def eat(self):
print("%s 爱吃鱼" % self.name)
tom = Cat("Tom")
print(tom.name)
tom.eat()
lazy_cat = Cat("大懒猫")
print(lazy_cat.name)
lazy_cat.eat()
__del__方法的调用
class Cat:
def __init__(self, new_name):
print("初始化方法被调用")
def __del__(self):
print("del方法被调用")
# tom是一个全局变量 等到程序全部执行完成之后才会销毁
tom = Cat("Tom")
# 可以手动调用 del tom 提前销毁 tom对象
# del tom
print("*" * 50)
输出: (注意: 如果不注释 # del tom,__del__方法的调用就在输出横线的上方)
初始化方法被调用
**************************************************
del方法被调用
__str__方法(类似Java中的toString())
在python中,使用print输出对象变量,默认情况下输出这个变量 引用的对象是由哪一个类创建的对象,以及在内存中的地址(16进制表示) ;
如果在开发中,希望使用print输出对象变量时,能够打印自定义内容,就可以利用__str__方法;
注意:__str__方法必须返回一个字符串;
class Cat:
def __init__(self, new_name):
self.name = new_name
def __str__(self): # 返回的是一个字符串
return "我是小猫【%s】" % self.name
tom = Cat("Tom")
print(tom)
输出:
我是小猫【Tom】
1
面向对象案例一 : 房子和家具
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return "家具名称: %s, 家具面积: %s " % (self.name, self.area)
class House:
def __init__(self, house_type, area): # 房子类型, 总面积
self.house_type = house_type
self.area = area
self.free_area = area # 一开始剩余面积等于总面积
self.item_list = [] # 家具列表一开始是空的
pass
def __str__(self):
# python 能够自动的将一对括号内内部的代码 连接在一起
return ("户型: %s\n总面积: %.2f【剩余: %.2f】\n家具: %s" # 如果没有使用括号,这里就要有一个 \ 换行标符
% (self.house_type, self.area,
self.free_area, self.item_list)) # 注意这里使用了一个括号
def add_item(self, item): # 在列表中添加家具
if self.free_area < item.area:
print("房子已满,不能再放家具了!")
return
self.item_list.append(item.name)
self.free_area -= item.area
# 创建家具
bed = HouseItem("席梦思", 40)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 20)
# 创建房子
my_home = House("两室一厅", 60)
print(my_home)
# 添加家具
my_home.add_item(bed)
print(my_home)
my_home.add_item(chest)
print(my_home)
my_home.add_item(table)
print(my_home)
输出:
户型: 两室一厅
总面积: 60.00【剩余: 60.00】
家具: []
户型: 两室一厅
总面积: 60.00【剩余: 20.00】
家具: ['席梦思']
户型: 两室一厅
总面积: 60.00【剩余: 18.00】
家具: ['席梦思', '衣柜']
房子已满,不能再放家具了!
户型: 两室一厅
总面积: 60.00【剩余: 18.00】
家具: ['席梦思', '衣柜']
面向对象案例二 : 枪和士兵
class Gun: # 枪类
def __init__(self, model):
self.model = model
self.bullet_mount = 0
def add_bullet(self, count):
self.bullet_mount += count
def shoot(self):
if self.bullet_mount <= 0:
print("【%s】没有子弹了..." % self.model)
self.bullet_mount -= 1
print("%s 突突突...【剩余子弹: %d】" % (self.model, self.bullet_mount))
class Soldier:
def __init__(self, name):
self.name = name
# 这个使用None关键字 假定新兵没有枪
self.gun = None # Node类似Java中的null
def fire(self):
# 1.判断士兵是否有枪
# if self.gun == None: # 不推荐
if self.gun is None:
print("【%s】 还没有枪..." % self.name)
return
# 2. 高喊口号
print("冲鸭...【%s】" % self.name)
# 3. 让枪装填子弹
self.gun.add_bullet(50)
# 4.让枪发射子弹
self.gun.shoot()
# 创建枪的对象
ak47 = Gun("AK47")
ak47.add_bullet(50)
ak47.shoot()
# 创建士兵对象
xusanduo = Soldier("许三多")
xusanduo.fire() # 没有枪,打不了
xusanduo.gun = ak47 # 给士兵一把ak47的枪
xusanduo.fire()
身份运算符( == 类似Java中的equals,而 is(身份运算符) 却类似 java中的 ==);
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True
print(a is b) # False
私有属性和私有方法: 只需要在属性名或者方法名前面加上两个下划线(真的6…),私有属性只能在类的内部使用;
但是Python中没有真正意义的私有,这个私有只是伪私有。可以使用_类名__属性或者_类名__方法强制访问私有属性或方法;
class Woman:
def __init__(self, name):
self.name = name
self.__age = 18 # 加上两个_表示私有属性
def secret(self):
# 注意对象内部可以访问私有属性
print("%s 的年龄是 %d" % (self.name, self.__age))
xiaomei = Woman("小美")
# print(xiaomei.__age) # 报错,不能直接访问私有方法
xiaomei.secret() # 这个可以
# 但是也可以通过 " _类名__属性/方法" 来强制访问私有属性或方法
print(xiaomei._Woman__age) # 强制访问
输出:
小美 的年龄是 18
18
关于继承中的重写,和Java中差不多,直接覆盖即可;
class Animal:
def eat(self):
print("吃!")
def drink(self):
print("喝!")
def run(self):
print("跑!")
def sleep(self):
print("睡")
class Dog(Animal): # 继承直接加上括号,不需要extends 关键字
def bark(self):
print("汪汪汪!")
class XiaoTianQuan(Dog): # 继承可以传递,既继承了Animal也继承了Dog
def fly(self):
print("飞!")
def bark(self): # 重写方法
print("嗷嗷嗷!")
xiao_tian = XiaoTianQuan()
xiao_tian.eat()
xiao_tian.drink()
xiao_tian.bark()
xiao_tian.fly()
扩展相关方法中使用super()关键字,和Java也差不多;
class XiaoTianQuan(Dog): # 继承可以传递,既继承了Animal也继承了Dog
def fly(self):
print("飞!")
def bark(self): # 重写方法
super().bark() # 先调用父类的方法 #注意这个super()关键字在python2.x中没有
print("嗷嗷嗷!")
注意子类不能访问父类的私有属性
class A:
def __init__(self):
self.num1 = 3
self.__num2 = 33
def __test(self):
print("num1 = %d, num2 = %d" % (self.num1, self.__num2))
class B(A):
def demo(self): # 测试能不能访问父类的私有方法
# 访问父类的私有属性
print("访问父类的私有属性 %d" % self.__num2)
# 访问父类的私有方法
self.test()
a = A()
b = B()
b.demo() # 报错
但是子类可以通过公有方法间接的来访问父类的私有属性;
class A:
def __init__(self):
self.__num2 = 33
def __test(self):
print("__num2 = %d" % self.__num2)
def test(self):
# 访问自己类的 私有属性
print("私有属性__num2 = %d" % self.__num2)
# 访问自己类的 私有方法
self.__test()
class B(A):
def demo(self):
self.test() # 通过访问公共方法 test来间接访问 私有属性
b = B()
b.demo() # 报错
注意,使用多继承的时候,如果两个父类中有相同的方法,尽量避免使用多继承, 避免产生混淆。可以使用__mro__(方法搜索顺序)用于在多继承时,判断方法、属性的调用路径;
class A:
def test1(self):
print("A类中的test_1方法!")
def test2(self):
print("A类中的test_2方法!")
class B:
def test1(self):
print("B类中的test_1方法!")
def test2(self):
print("B类中的test_2方法!")
class C(A, B):
pass
c = C()
c.test1()
c.test2()
print(C.__mro__) # 输出C的继承路径
输出: