---恢复内容开始---
# 类与对象的名称空间 class Game_role: name = "LOL" year = 2012 def __init__(self, name, ad, hp): self.name = name self.ad = ad self.hp = hp def attack(self, obj2): Game_role.area = "德玛西亚" print("%s攻击了%s, %s掉了%s血,还剩%s血" % (self.name, obj2.name, obj2.name, self.ad, obj2.hp-self.ad)) p1 = Game_role("盖伦", 10, 100) p2 = Game_role("剑豪", 20, 80) print(p1.attack(p2)) p1.armor = 90 print(p1.__dict__) # 对象的属性不仅可以在 __init__ 添加,还能再其他地方添加 p2.attack(p1) print(Game_role.__dict__) # 类的属性,不仅在类内部添加,还可以在类的外部添加 Game_role.year = 6 print(Game_role.__dict__) p1 = Game_role("盖伦", 10, 100) print(p1.name) # 这里不是打印 LOL,而是 盖伦 # 实例化对象先从对象本身的空间找name,没有的话就找类里面的name # 因为对象空间中存在一个类对象指针,所以对象可以找到类中的变量以及方法 # 类名只能找到类中的变量及方法,或者父类中找,不能找对象中的属性 # 对象与对象之间原则上是不能相互访问的 print(p1.year) # 6 p3 = Game_role("提莫", 30, 60)
# 一. 类名称空间与对象的名称空间 # 类一创建在内存中就会创建该类的名称空间,用来存储类中定义的所有名字,这些名字都是类的属性 # 类的属性有两种: # 1. 静态属性——直接在类中定义的变量 # 2. 动态属性就是定义在类中的方法 # 类的数据属性对于所有对象来说是共享的 class Person: language = "人类语言" age = 18 def __init__(self): pass def attack(self, a): pass p1 = Person() p2 = Person() print(id(p1.language), id(p2.language)) # 2645986525440 2645986525440 print(id(p1.age), id(p2.age)) # 1700162848 1700162848 # 注意这里并不是p1改变了类的静态属性,对象只能查看 # 因此相当于在该对象的内存中开辟了一个空间,存放对象的age属性与值20的对应关系 p1.age = 20 print(p1.age) # 20 print(p2.age) # 18 print(id(p1.age), id(p2.age)) # 1700162912 1700162848 # 而类的动态属性是绑定到所有对象的 # 因此这里对象p1调用 attack 方法时可以把自己传进去 # p1.attack(p1) 不会报错 # 总结: # 创建一个对象实例就会创建一个该对象实例的名称空间 # 存放对象实例的名字,称为对象实例的属性 # obj.name 会从 obj 的名称空间找name, 找不到就去类中找,再找不到就找父类...最后找不到抛出异常
# 组合 # 计算有多少对象调用一个类 class A: count = 0 def __init__(self): A.count += 1 obj = A() obj1 = A() print(A.count) # 组合:将一个对象封装到另一个对象的属性中 class Game_role: def __init__(self, name, ad, hp): self.name = name self.ad = ad self.hp = hp def attack(self, obj2): print("%s攻击了%s, %s掉了%s血,还剩%s血" % (self.name, obj2.name, obj2.name, self.ad, obj2.hp-self.ad)) class Weapen: def __init__(self, name, ad): self.name = name self.ad = ad def weapen_attack(self, p1, p2): p2.hp -= self.ad + p1.ad # 这里会受到人和枕头的伤害 print("%s利用%s攻击了%s,%s还剩%s血" % (p1.name, self.name, p2.name, p2.name, p2.hp)) p1 = Game_role("盖伦", 10, 100) p2 = Game_role("剑豪", 20, 80) # p1.attack(p2) pillow = Weapen("枕头", 2) pillow.weapen_attack(p1, p2) # 这里有个奇怪的地方,即武器是发起者,应该是人作为发起者才合理
# 为了让程序看起来合理,即要人来作为发起者,可以这样: class Game_role: def __init__(self, name, ad, hp): self.name = name self.ad = ad self.hp = hp def attack(self, obj2): print("%s攻击了%s, %s掉了%s血,还剩%s血" % (self.name, obj2.name, obj2.name, self.ad, obj2.hp-self.ad)) def equip_weapen(self, w): self.w = w # 封装属性,给一个对象封装一个属性,该属性是另一个类的对象 class Weapen: def __init__(self, name, ad): self.name = name self.ad = ad def weapen_attack(self, p1, p2): p2.hp -= self.ad + p1.ad # 这里会受到人和枕头的伤害 print("%s利用%s攻击了%s,%s还剩%s血" % (p1.name, self.name, p2.name, p2.name, p2.hp)) p1 = Game_role("盖伦", 10, 100) p2 = Game_role("剑豪", 20, 80) # p1.attack(p2) pillow = Weapen("枕头", 2) pillow.weapen_attack(p1, p2) print(p1.__dict__) # {'name': '盖伦', 'ad': 10, 'hp': 100} p1.equip_weapon(666) print(p1.w) # 666 print(p1.__dict__) # {'name': '盖伦', 'ad': 10, 'hp': 100, 'weapen': 666} # 给人物装备武器 p1.equip_weapen(pillow) # 对象p1调用类 Game_role 的方法 equip_weapen
# 而 equip_weapen 返回的是一个形参 w # p1调用它的时候,相当于给p1增加了一个属性w,而这里这个属性接收的实参是pillow
print(p1.__dict__)
# {'name': 'a', 'ad': 20, 'hp': 100, 'w': <__main__.Weapen_1 object at 0x00000166EB9D8D68>}
# 也就是说,p1.w = pillow p1.w.weapen_attack(p1, p2) # 盖伦利用枕头攻击了剑豪,剑豪还剩68血 # 这样看起来就是p1发起的攻击,这样就具备了合理性 # 组合的好处 # 1. 使代码更合理 # 2. 类与类之间的耦合性增强(耦合性也不是越强越好)
# 二. 面向对象的三大特性: # 继承 # 多态 # 封装 # 继承 # 继承是一种创建新类的方式,新建的类可以继承一个或多个父类 # 父类又称为基类或超类,新建的类称为子类或派生类 class Animal: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age class Person: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age class Cat: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age class Dog: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age # 可以看出上面每个类中有很多相同的属性
class Animal: type_name = "动物类" def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age def eat(self): print("吃东西") # Animal: 父类 # Person, Cat, Dog: 子类 class Person(Animal): # type_name = "人类" def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age class Cat(Animal): pass class Dog(Animal): pass # 子类可以调用父类的属性和方法 Person.eat(111) print(Person.type_name) # 动物类 # 如果子类中也有 type_name 这个变量,则只调用它自己的属性 print(Person.type_name) # 人类
# 对象:
# 实例化对象
p1 = Person("小春", "男", 28)
# 这里Person类并没有 __init__ 但p1会调用父类的 __init__
print(p1.__dict__) # {'name': '小春', 'sex': '男', 'age': 28}
p1.type_name = 666
# 对象不能更改的属性,所以这里其实是对象给自己封装了一个属性
print(p1) # <__main__.Person object at 0x0000025E6C038C88>
p1.eat() # 吃东西
# p1.eat() 会从 p1 的名称空间找eat(), 找不到就去类中找,再找不到就找父类...最后找不到抛出异常
# 继承又分为单继承和多继承 # 定义父类1 class Parent_Class1: pass # 定义父类2 class Parent_Class2: pass # 单继承,基类是Parent_Class1,派生类是 Sub_Class1 class Sub_Class1(Parent_Class1): pass # 多继承 class Sub_Class2(Parent_Class1, Parent_Class2): pass # 继承查看方法: # __base__只查到从左到右继承的第一个父类 print(Sub_Class1.__bases__) # <class '__main__.Parent_Class1'> print(Sub_Class2.__bases__) # (<class '__main__.Parent_Class1'>, <class '__main__.Parent_Class2'>) # 如果没有指定基类, Python的类会默认继承 object 类,object是所有类的基类,它提供了一些常见方法(如__str__)的实现 print(Parent_Class1.__bases__) # (<class 'object'>,) print(Parent_Class2.__bases__) # (<class 'object'>,)
# 继承的重要性——减少代码重用 # 单继承 # 如果一个实例化对象既要执行子类方法,又要执行父类方法 # 方法一; class Animal: type_name = "动物类" def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age def eat(self): print("吃东西") class Person(Animal): # type_name = "人类" def __init__(self, name, sex, age, mind): Animal.__init__(self, name, sex, age) self.mind = mind class Cat(Animal): def __init__(self, name, sex, age, clmib): Animal.__init__(self, name, sex, age) self.clmib = clmib class Dog(Animal): def __init__(self, name, sex, age, look): Animal.__init__(self, name, sex, age) self.look = look p1 = Person("小春", "男", 28, "有思想") print(p1.__dict__) # {'name': '小春', 'sex': '男', 'age': 28, 'mind': '有思想'} c1 = Cat("土豆", "女", 2, "爬树") print(c1.__dict__) # {'name': '土豆', 'sex': '女', 'age': 2, 'clmib': '爬树'} d1 = Dog("大嘴", "女", 3, "看门") print(d1.__dict__) # {'name': '大嘴', 'sex': '女', 'age': 3, 'look': '看门'} # 方法二:super class Animal: type_name = "动物类" def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age def eat(self): print("吃东西") class Person(Animal): # type_name = "人类" def __init__(self, name, sex, age, mind): super().__init__(name, sex, age) self.mind = mind def eat(self): # 如果都有 eat(),则要先执行父类的话,应该这样写 super().eat() print("%s 吃饭" % self.name) class Cat(Animal): def __init__(self, name, sex, age, clmib): super().__init__(name, sex, age) self.clmib = clmib class Dog(Animal): def __init__(self, name, sex, age, look): super().__init__(name, sex, age) self.look = look p1 = Person("小春", "男", 28, "有思想") print(p1.__dict__) # {'name': '小春', 'sex': '男', 'age': 28, 'mind': '有思想'} c1 = Cat("土豆", "女", 2, "爬树") print(c1.__dict__) # {'name': '土豆', 'sex': '女', 'age': 2, 'clmib': '爬树'} d1 = Dog("大嘴", "女", 3, "看门") print(d1.__dict__) # {'name': '大嘴', 'sex': '女', 'age': 3, 'look': '看门'} p1.eat() # 吃东西 # 小春 吃饭
---恢复内容结束---