Python-Day06-面向对象进阶

    xiaoxiao2021-04-15  222

    Author: Seven_0507 Date: 2019-05-21

            今天主要总结了Python面向对象编程的进阶知识点,主要从属性、类中的方法、运算符重载、类之间的关系、继承和多态方面归纳总结。

    文章目录

    Python面向对象进阶1. 类属性与实例属性1.1 类属性1.2 实例属性1.3 类属性和实例属性混合1.4 修改类属性和实例属性的区别 2. @property包装器3. __slots__魔法4. 类中的方法4.1 实例方法4.2 类方法4.3 静态方法 4. 运算符重载5. 类之间的关系5.1 关联关系5.2 依赖关系 6. 继承7. 多态

    Python面向对象进阶

    1. 类属性与实例属性

    什么是类对象,实例对象

    类对象:类名

    实例对象:类创建的对象

    1.1 类属性

    # 类属性 class people: name = "Tom" # 公有的类属性 __age = 18 # 私有的类属性 p = people() print(p.name) # 实例对象 print(people.name) # 类对象 print(p.__age) #错误 不能在类外通过实例对象访问私有的类属性 print(people.__age) #错误 不能在类外通过类对象访问私有的类属性 Tom Tom --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-2-3efede2e003a> in <module> 8 print(people.name) # 类对象 9 ---> 10 print(p.__age) #错误 不能在类外通过实例对象访问私有的类属性 11 print(people.__age) #错误 不能在类外通过类对象访问私有的类属性 AttributeError: 'people' object has no attribute '__age'

    1.2 实例属性

    # 实例属性 class people: name = "tom" # 公有的类属性 p = people() p.age = 18 # 实例属性 print(p.name) print(p.age) # 实例属性是实例对象特有的,类对象不能拥有 print(people.name) # 类属性,可以调用 print(people.age) # 错误:实例属性,不能通过类对象调用 tom 18 tom --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-3-0c71d7231365> in <module> 10 11 print(people.name) # 类属性,可以调用 ---> 12 print(people.age) # 错误:实例属性,不能通过类对象调用 AttributeError: type object 'people' has no attribute 'age'

    1.3 类属性和实例属性混合

    # 类属性和实例属性混合 class people: name="tom" # 类属性:实例对象和类对象可以同时调用 def __init__(self,age): # 实例属性 self.age=age p=people(18) # 实例对象 p.sex="男" # 实例属性 print(p.name) # 类属性实例对象可以调用 print(p.age) # 实例属性是实例对象特有的,类对象不能拥有 print(p.sex) # 实例属性是实例对象特有的,类对象不能拥有 print(people.name) # 类对象 print(people.age) # 错误:实例属性,不能通过类对象调用 print(people.sex) # 错误:实例属性,不能通过类对象调用 tom 18 男 tom --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-4-3ef77090faf8> in <module> 13 14 print(people.name) # 类对象 ---> 15 print(people.age) # 错误:实例属性,不能通过类对象调用 16 print(people.sex) # 错误:实例属性,不能通过类对象调用 AttributeError: type object 'people' has no attribute 'age'

    1.4 修改类属性和实例属性的区别

    """ 如果在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用, 会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且如果通过 实例对象引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性 """ class Animal: name = "Panda" # 类属性 print(Animal.name) # 类对象引用类属性 p = Animal() print(p.name) # 实例对象引用类属性时,会产生一个同名的实例属性 p.name = "dog" # 修改的只是实例属性的,不会影响到类属性 print(p.name) # dog print(Animal.name) # panda # 删除实例属性 del p.name print(p.name) Panda Panda dog Panda Panda

    2. @property包装器

    """ --(1) 使用原有有方法定义访问器/修改器/删除器 """ class Car(object): def __init__(self, brand, max_speed): self.set_brand(brand) self.set_max_speed(max_speed) def get_brand(self): return self._brand def set_brand(self, brand): self._brand = brand def get_max_speed(self): return self._max_speed def set_max_speed(self, max_speed): if max_speed < 0: raise ValueError('Invalid max speed for car') self._max_speed = max_speed def __str__(self): return 'Car: [品牌=%s, 最高时速=%d]' % (self._brand, self._max_speed) # 用已有的修改器和访问器定义属性 brand = property(get_brand, set_brand) max_speed = property(get_max_speed, set_max_speed) car = Car('QQ', 120) print(car) # car.max_speed = -100 # 检查赋给属性的值是否正确,不符合输入要求会报错 car.max_speed = 320 car.brand = "Benz" print(car) print(Car.brand) print(Car.brand.fget) print(Car.brand.fset) Car: [品牌=QQ, 最高时速=120] Car: [品牌=Benz, 最高时速=320] <property object at 0x03F58A50> <function Car.get_brand at 0x03F4F468> <function Car.set_brand at 0x03F4F3D8> 属性访问器-getter属性修改器-setter属性删除器-deleter """ --(2)访问器/修改器/删除器——包装器 """ class Car(object): __slots__ = ('_brand', '_max_speed') # 限定自定义类型的对象只能绑定brand/max_speed属性 def __init__(self, brand, max_speed): self._brand = brand self._max_speed = max_speed # 访问器 - getter方法(把一个方法变成属性) @property def brand(self): return self._brand # 修改器 - setter方法(属性赋值) @brand.setter def brand(self, brand): self._brand = brand # 删除器 - deleter方法(删除属性) @brand.deleter def brand(self): del self._brand @property def max_speed(self): return self._max_speed @max_speed.setter def max_speed(self, max_speed): if max_speed < 0: raise ValueError('Invalid max speed for car') self._max_speed = max_speed def __str__(self): return 'Car: [品牌=%s, 最高时速=%d]' % (self._brand, self._max_speed) car = Car('QQ', 120) print(car) # car.max_speed = -100 # 检查赋给属性的值是否正确,不符合输入要求会报错 car.max_speed = 320 car.brand = "Benz" # car.current_speed = 80 # 会报错,使用__slots__属性限制只能绑定brand/max_speed属性 print(car) # del car.max_speed # 会报错,未提供删除器 del car.brand # 属性的实现 print(Car.brand) print(Car.brand.fget) print(Car.brand.fset) print(Car.brand.fdel) Car: [品牌=QQ, 最高时速=120] Car: [品牌=Benz, 最高时速=320] <property object at 0x03F5FFC0> <function Car.brand at 0x03F4F6A8> <function Car.brand at 0x03F4F660> <function Car.brand at 0x03F4F858>

    3. __slots__魔法

    class Person(object): # 限定Person对象只能绑定_name, _age和_gender属性 __slots__ = ('_name', '_age', '_gender') def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): if self._age <= 16: print('%s正在玩飞行棋.' % self._name) else: print('%s正在玩斗地主.' % self._name) def main(): person = Person('王大锤', 22) person.play() person._gender = '男' person.phone='13000000' # 此句报错,由于person定义时phone没有被放入__slots__中 if __name__ == '__main__': main() 王大锤正在玩斗地主. --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-38-f938be77850d> in <module> 34 35 if __name__ == '__main__': ---> 36 main() <ipython-input-38-f938be77850d> in main() 31 person.play() 32 person._gender = '男' ---> 33 person.phone='13000000' # 此句报错,由于person定义时phone没有被放入__slots__中 34 35 if __name__ == '__main__': AttributeError: 'Person' object has no attribute 'phone'

    4. 类中的方法

    4.1 实例方法

    若类中定义的方法是发送给对象的消息,则是实例方法,之前实例中我们在类中定义的方法都是对象方法。

    4.2 类方法

    # (1) 类方法的定义与调用 class people: country = "china" @classmethod def getCountry(cls): return cls.country p = people() print(p.getCountry()) # 实例对象调用类方法 print(people.getCountry()) # 类对象调用类方法 china china # (2) 通过类方法修改类属性 class people: country="china" @classmethod def getCountry(cls): return cls.country @classmethod def setCountry(cls,country): cls.country = country # 类方法的调用 p = people() print(p.getCountry()) # 实例对象调用类方法 print(people.getCountry()) # 类对象调用类方法 # 类方法修改类属性 p.setCountry("Japan") print(p.getCountry()) print(people.getCountry()) china china Japan Japan # (3) 类方法的应用 from time import time, localtime, sleep class Clock(object): """数字时钟""" def __init__(self, hour=0, minute=0, second=0): self._hour = hour self._minute = minute self._second = second @classmethod # now为类方法 def now(cls): ctime = localtime(time()) return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec) def run(self): """走字""" self._second += 1 if self._second == 60: self._second = 0 self._minute += 1 if self._minute == 60: self._minute = 0 self._hour += 1 if self._hour == 24: self._hour = 0 def show(self): """显示时间""" return 'd:d:d' % \ (self._hour, self._minute, self._second) def main(): # 通过类方法创建对象并获取系统时间 clock = Clock.now() count = 0 while True: print(clock.show()) sleep(1) clock.run() count += 1 if count == 6: break if __name__ == '__main__': main() 18:39:27 18:39:28 18:39:29 18:39:30 18:39:31 18:39:32

    4.3 静态方法

    # (1) 静态方法定义与调用 class people3: country = "china" @staticmethod def getCountry(): return people3.country # 在静态方法中引用类属性的话,必须通过类对象来引用 p = people3() print(p.getCountry()) # 实例对象调用静态方法 print(people3.getCountry()) # 类对象调用静态方法 china china # 静态方法的应用 from math import sqrt """ 我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长 未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不 是对象方法,这个方法是属于三角形类而并不属于三角形对象的 """ class Triangle(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c # 静态方法 @staticmethod def is_valid(a, b, c): return a + b > c and b + c > a and a + c > b # 实例方法 def perimeter(self): return self._a + self._b + self._c # 实例方法 def area(self): half = self.perimeter() / 2 return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c)) def main(): a, b, c = 3, 4, 1 # 静态方法和类方法都是通过给类发消息来调用的 if Triangle.is_valid(a, b, c): t = Triangle(a, b, c) print(t.perimeter()) # 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数 # print(Triangle.perimeter(t)) print(t.area()) # print(Triangle.area(t)) else: print('无法构成三角形.') if __name__ == '__main__': main() 无法构成三角形.

    4. 运算符重载

    """ 运算符重载:__gt__ / __lt__ """ class Student(object): def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name def study(self, course_name): print('%s正在学习%s.' % (self._name, course_name)) def watch_tv(self): if self._age < 18: print('%s只能观看《熊出没》.' % self._name) else: print('%s正在观看《死神来了》.' % self._name) # 重载大于(>)运算符 def __gt__(self, other): return self._age > other._age # 重载小于(<)运算符 def __lt__(self, other): return self._age < other._age if __name__ == '__main__': stu1 = Student('五月猴', 27) stu1.study('Python程序设计') stu1.watch_tv() stu2 = Student('王二小', 15) stu2.study('思想品德') stu2.watch_tv() print(stu1 > stu2) print(stu1 < stu2) 五月猴正在学习Python程序设计. 五月猴正在观看《死神来了》. 王二小正在学习思想品德. 王二小只能观看《熊出没》. True False """ 运算符重载 - 自定义分数类 """ from math import gcd class Rational(object): def __init__(self, num, den=1): if den == 0: raise ValueError('分母不能为0') self._num = num self._den = den self.normalize() def simplify(self): x = abs(self._num) y = abs(self._den) factor = gcd(x, y) if factor > 1: self._num //= factor self._den //= factor return self def normalize(self): if self._den < 0: self._den = -self._den self._num = -self._num return self def __add__(self, other): new_num = self._num * other._den + other._num * self._den new_den = self._den * other._den return Rational(new_num, new_den).simplify().normalize() def __sub__(self, other): new_num = self._num * other._den - other._num * self._den new_den = self._den * other._den return Rational(new_num, new_den).simplify().normalize() def __mul__(self, other): new_num = self._num * other._num new_den = self._den * other._den return Rational(new_num, new_den).simplify().normalize() def __truediv__(self, other): new_num = self._num * other._den new_den = self._den * other._num return Rational(new_num, new_den).simplify().normalize() def __str__(self): if self._num == 0: return '0' elif self._den == 1: return str(self._num) else: return '(%d/%d)' % (self._num, self._den) if __name__ == '__main__': r1 = Rational(2, 3) print(r1) r2 = Rational(6, -8) print(r2) print(r2.simplify()) print('%s + %s = %s' % (r1, r2, r1 + r2)) print('%s - %s = %s' % (r1, r2, r1 - r2)) print('%s * %s = %s' % (r1, r2, r1 * r2)) print('%s / %s = %s' % (r1, r2, r1 / r2)) (2/3) (-6/8) (-3/4) (2/3) + (-3/4) = (-1/12) (2/3) - (-3/4) = (17/12) (2/3) * (-3/4) = (-1/2) (2/3) / (-3/4) = (-8/9)

    5. 类之间的关系

    5.1 关联关系

    """ 对象之间的关联关系 """ from math import sqrt class Point(object): def __init__(self, x=0, y=0): self._x = x self._y = y def move_to(self, x, y): self._x = x self._y = y def move_by(self, dx, dy): self._x += dx self._y += dy def distance_to(self, other): dx = self._x - other._x dy = self._y - other._y return sqrt(dx ** 2 + dy ** 2) def __str__(self): return '(%s, %s)' % (str(self._x), str(self._y)) class Line(object): def __init__(self, start=Point(0, 0), end=Point(0, 0)): self._start = start self._end = end @property def start(self): return self._start @start.setter def start(self, start): self._start = start @property def end(self): return self.end @end.setter def end(self, end): self._end = end @property def length(self): return self._start.distance_to(self._end) if __name__ == '__main__': p1 = Point(3, 5) print(p1) p2 = Point(-2, -1.5) print(p2) line = Line(p1, p2) print(line.length) line.start.move_to(2, 1) line.end = Point(1, 2) print(line.length) (3, 5) (-2, -1.5) 8.200609733428363 1.4142135623730951

    5.2 依赖关系

    """ 对象之间的依赖关 """ class Car(object): def __init__(self, brand, max_speed): self._brand = brand self._max_speed = max_speed self._current_speed = 0 @property def brand(self): return self._brand def accelerate(self, delta): self._current_speed += delta if self._current_speed > self._max_speed: self._current_speed = self._max_speed def brake(self): self._current_speed = 0 def __str__(self): return '%s当前时速%d' % (self._brand, self._current_speed) class Student(object): def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name # 学生和车之间存在依赖关系 - 学生使用了汽车 def drive(self, car): print('%s驾驶着%s欢快的行驶在去西天的路上' % (self._name, car._brand)) car.accelerate(30) print(car) car.accelerate(50) print(car) car.accelerate(50) print(car) if __name__ == '__main__': stu = Student('王小二', 15) car = Car('QQ', 120) stu.drive(car) 王小二驾驶着QQ欢快的行驶在去西天的路上 QQ当前时速30 QQ当前时速80 QQ当前时速120

    6. 继承

    """ (1) 继承示例 -继承的语法 -调用父类方法 -子类中定义特有的属性和方法 """ class Person(object): """人(Person父类)""" def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): print('%s正在愉快的玩耍.' % self._name) def watch_tv(self): if self._age >= 18: print('%s正在观看死神来了.' % self._name) else: print('%s只能观看《熊出没》.' % self._name) class Student(Person): """学生(子类继承Person父类)""" def __init__(self, name, age, grade): super().__init__(name, age) self._grade = grade # 定义自己特有的grade属性 @property # 定义自己特有的grade方法 def grade(self): return self._grade @grade.setter def grade(self, grade): self._grade = grade # 定义自己特有的study方法 def study(self, course): print('%s的%s正在学习%s.' % (self._grade, self._name, course)) class Teacher(Person): """老师(子类继承Person父类)""" def __init__(self, name, age, title): super().__init__(name, age) self._title = title # 定义自己特有的title属性 @property # 定义自己特有的title方法 def title(self): return self._title @title.setter def title(self, title): self._title = title # 定义自己特有的teach方法 def teach(self, course): print('%s%s正在讲%s.' % (self._name, self._title, course)) def main(): stu = Student('王二小', 15, '初三') stu.study('数学') # 调用子类方法 stu.watch_tv() # 调用父类方法 t = Teacher('五月猴', 27, '研究僧') t.teach('Python程序设计') # 调用子类方法 t.watch_tv() # 调用父类方法 if __name__ == '__main__': main() 初三的王二小正在学习数学. 王二小只能观看《熊出没》. 五月猴研究僧正在讲Python程序设计. 五月猴正在观看死神来了. """ (2) 多重继承 - 菱形继承(钻石继承) - C3算法(替代DFS的算法) """ class A(object): def foo(self): print('foo of A') class B(A): """B(子类继承A父类)""" pass class C(A): """C(子类继承A父类)""" def foo(self): print('foo fo C') class D(B, C): """D(子类继承B,C父类)""" pass class E(D): """E(子类继承D父类)""" def foo(self): print('foo in E') super().foo() # 继承父类方法 super(B, self).foo() # 继承B父类方法 super(C, self).foo() # 继承C父类方法 if __name__ == '__main__': d = D() d.foo() print('-'*50) e = E() e.foo() foo fo C -------------------------------------------------- foo in E foo fo C foo fo C foo of A """ (3) 多重继承应用 - 通过多重继承可以给一个类的对象具备多方面的能力 - 这样在设计类的时候可以避免设计太多层次的复杂的继承关系 """ class Father(object): def __init__(self, name): self._name = name def gamble(self): print('%s在打麻将.' % self._name) def eat(self): print('%s在大吃大喝.' % self._name) class Monk(object): def __init__(self, name): self._name = name def eat(self): print('%s在吃斋.' % self._name) def chant(self): print('%s在念经.' % self._name) class Musician(object): def __init__(self, name): self._name = name def eat(self): print('%s在细嚼慢咽.' % self._name) def play_piano(self): print('%s在弹钢琴.' % self._name) # 试一试下面的代码看看有什么区别 # class Son(Monk, Father, Musician): # class Son(Musician, Father, Monk): class Son(Musician, Father, Monk): def __init__(self, name): Father.__init__(self, name) Monk.__init__(self, name) Musician.__init__(self, name) son = Son('王大锤') son.gamble() # 调用继承自Father的eat方法 son.eat() son.chant() son.play_piano() 王大锤在打麻将. 王大锤在细嚼慢咽. 王大锤在念经. 王大锤在弹钢琴.

    7. 多态

    # 多态 from abc import ABCMeta, abstractmethod class Pet(object, metaclass=ABCMeta): """ 宠物(Pet父类) Pet被创建为一个抽象类,就是不能够创建对象的类,这种类是专门为让其他类去继承它 通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果 """ def __init__(self, nickname): self._nickname = nickname @abstractmethod def make_voice(self): """发出声音(Pet父类定义原始方法)""" pass class Dog(Pet): """狗(Dog子类继承Pet父类)""" def make_voice(self): # 对父类中make_voice方法进行重写 print('%s: 汪汪汪...' % self._nickname) class Cat(Pet): """猫(Cat子类继承Pet父类)""" def make_voice(self): # 对父类中make_voice方法进行重写 print('%s: 喵...喵...' % self._nickname) def main(): pets = [Dog('旺财'), Cat('凯蒂')] for pet in pets: pet.make_voice() if __name__ == '__main__': main() 旺财: 汪汪汪... 凯蒂: 喵...喵...

    最新回复(0)