类中: ①特征被称为属性;②行为被称为方法;③三要素:类名、属性、方法;
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的继承路径
输出: