Python-Day06-面向对象进阶 - Go语言中文社区

Python-Day06-面向对象进阶


Author: Seven_0507
Date: 2019-05-21

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

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 '%02d:%02d:%02d' % 
               (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:
            
                        
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/KEEP_GIONG/article/details/90417796
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢