python基础17-19面向对象编程入门

1.面向对象编程入门

类和对象

在面向对象编程中,类是一个抽象的概念,对象是一个具体的概念。我们把同一类对象的共同特征抽取出来就是一个类,比如我们经常说的人类,这是一个抽象概念,而我们每个人就是人类的这个抽象概念下的实实在在的存在,也就是一个对象。简而言之,类是对象的蓝图和模板,对象是类的实例,是可以接受消息的实体。
一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类。

定义类
#类
class Student:
    #方法
    def study(self, course_name):
        print(f'学生正在学习{course_name}.')
    def play(self):
        print(f'学生正在玩游戏.')
创建和使用对象
stu1 = Student()
stu2 = Student()
print(stu1)    # <__main__.Student object at 0x10ad5ac50>
print(stu2)    # <__main__.Student object at 0x10ad5acd0> 
print(hex(id(stu1)), hex(id(stu2)))    # 0x10ad5ac50 0x10ad5acd0

变量其实保存的是一个对象在内存中的逻辑地址(位置),通过这个逻辑地址,我们就可以在内存中找到这个对象。
stu3 = stu2这样的赋值语句并没有创建新的对象,只是用一个新的变量保存了已有对象的地址。
调用方式

# 通过“类.方法”调用方法,第一个参数是接收消息的对象,第二个参数是学习的课程名称
Student.study(stu1, 'Python程序设计')    # 学生正在学习Python程序设计.
# 通过“对象.方法”调用方法,点前面的对象就是接收消息的对象,只需要传入第二个参数
stu1.study('Python程序设计')             # 学生正在学习Python程序设计.
Student.play(stu2)    # 学生正在玩游戏.
stu2.play()           # 学生正在玩游戏. 

初始化方法

如果要给学生对象定义属性,我们可以修改Student类,为其添加一个名为__init__的方法。在我们调用Student类的构造器创建对象时,首先会在内存中获得保存学生对象所需的内存空间,然后通过自动执行__init__方法,完成对内存的初始化操作,也就是把数据放到内存空间中。所以我们可以通过给Student类添加__init__方法的方式为学生对象指定属性,同时完成对属性赋初始值的操作,正因如此,__init__方法通常也被称为初始化方法。

打印对象

魔术方法或者魔法方法 以__开头
在类中放置__repr__魔术方法来做到

2.面向对象编程进阶

可见性和属性装饰器

__name表示私有属性,_name表示受保护属性

class Student:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def study(self, course_name):
        print(f'{self.__name}正在学习{course_name}.')
stu = Student('王大锤', 20)
stu.study('Python程序设计')
print(stu.__name)
动态属性

目前流行的Python和JavaScript都是动态语言,除此之外如PHP、Ruby等也都属于动态语言,而C、C++等语言则不属于动态语言”。需要提醒大家的是,对象的方法其实本质上也是对象的属性,如果给对象发送一个无法接收的消息,引发的异常仍然是AttributeError。

#动态添加属性
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
stu = Student('王大锤', 20)
# 为Student对象动态添加sex属性
stu.sex = '男'

如果不希望在使用对象时动态的为对象添加属性,可以使用Python的__slots__魔法。对于Student类来说,可以在类中指定__slots__ = ('name', 'age'),这样Student类的对象只能有nameage属性,如果想动态添加其他属性将会引发异常

class Student:
    __slots__ = ('name', 'age')
    def __init__(self, name, age):
        self.name = name
        self.age = age
stu = Student('王大锤', 20)
# AttributeError: 'Student' object has no attribute 'sex'
stu.sex = '男'
区分静态方法和类方法
 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

    # @classmethod
    # def is_valid(cls, a, b, c):
    #     """判断三条边长能否构成三角形(类方法)"""
    #     return a + b > c and b + c > a and a + c > b

对象方法、类方法、静态方法都可以通过类名.方法名的方式来调用,区别在于方法的第一个参数到底是普通对象还是类对象,还是没有接受消息的对象。静态方法通常也可以直接写成一个独立的函数,因为它并没有跟特定的对象绑定。

区分继承和多态

提供继承信息的类叫做父类(超类、基类),得到继承信息的类叫做子类(派生类、衍生类)

class Person:
    """人类"""
    def __init__(self, name, age):
        self.name = name
        self.age = age 
    def eat(self):
       print(f'{self.name}正在吃饭.')    
    def sleep(self):
        print(f'{self.name}正在睡觉.')
class Student(Person):
    """学生类"""
    def __init__(self, name, age):
        # super(Student, self).__init__(name, age)
        super().__init__(name, age)
    
    def study(self, course_name):
        print(f'{self.name}正在学习{course_name}.')
class Teacher(Person):
    """老师类"""
    def __init__(self, name, age, title):
        # super(Teacher, self).__init__(name, age)
        super().__init__(name, age)
        self.title = title
    
    def teach(self, course_name):
        print(f'{self.name}{self.title}正在讲授{course_name}.')
stu1 = Student('白元芳', 21)
stu2 = Student('狄仁杰', 22)
teacher = Teacher('武则天', 35, '副教授')
stu1.eat()
stu2.sleep()
teacher.teach('Python程序设计')
stu1.study('Python程序设计')

子类继承父类的方法后,还可以对方法进行重写(重新实现该方法),不同的子类可以对父类的同一个方法给出不同的实现版本,这样的方法在程序运行时就会表现出多态行为(调用相同的方法,做了不同的事情)

面对对象编程应用

案例1:扑克游戏。说明:简单起见,我们的扑克只有52张牌(没有大小王),游戏需要将52张牌发到4个玩家的手上,每个玩家手上有13张牌,按照黑桃、红心、草花、方块的顺序和点数从小到大排列,暂时不实现其他的功能。
类和类之间的关系可以粗略的分为is-a关系(继承)、has-a关系(关联)和use-a关系(依赖)
Python中没有声明枚举类型的关键字,但是可以通过继承enum模块的Enum类来创建枚举类型,代码如下所示

from enum import Enum
class Suite(Enum):
   """花色(枚举)"""
   SPADE, HEART, CLUB, DIAMOND = range(4)
   
for suite in Suite:
   print(f'{suite}: {suite.value}')

定义牌类

class Card:
    """牌"""
    def __init__(self, suite, face):
        self.suite = suite
        self.face = face
    def __repr__(self):
        suites = '♠♥♣♦'
        faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
        # 根据牌的花色和点数取到对应的字符
        return f'{suites[self.suite.value]}{faces[self.face]}'
        
     def __lt__(self, other):
        # 花色相同比较点数的大小
        if self.suite == other.suite:
            return self.face < other.face
        # 花色不同比较花色对应的值
        return self.suite.value < other.suite.value

定义扑克类

import random
class Poker:
    """扑克"""
    def __init__(self):
        # 通过列表的生成式语法创建一个装52张牌的列表
        self.cards = [Card(suite, face) for suite in Suite
                      for face in range(1, 14)]
        # current属性表示发牌的位置
        self.current = 0
    def shuffle(self):
        """洗牌"""
        self.current = 0
        # 通过random模块的shuffle函数实现列表的随机乱序
        random.shuffle(self.cards)
    def deal(self):
        """发牌"""
        card = self.cards[self.current]
        self.current += 1
        return card
    @property
    def has_next(self):
        """还有没有牌可以发"""
        return self.current < len(self.cards)

玩家类

class Player:
    """玩家"""
    def __init__(self, name):
        self.name = name
        self.cards = []
    def get_one(self, card):
        """摸牌"""
        self.cards.append(card)
    def arrange(self):
        self.cards.sort()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值