面向对象高级特性

博客介绍了Python中类属性和实例属性的定义与区别,类方法、实例方法和静态方法的定义及使用,还讲解了property属性的作用。阐述了单例模式的概念和实现方法,最后给出了小游戏设计、按奇偶排序数组、电话号码字母组合等应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一) 类属性和实例属性

1.定义
类属性:是类拥有的属性,它被类对象的实例对象的实例对象所共有的,在内存中只有一个内存。
实例属性(对象属性):实例化对象所拥有的属性(有多少个对象,就有多少份属性)
类方法:是类拥有的方法,它被类的对象所调用。
当对象没有所具有的属性时,调用类的属性

在这里插入图片描述
调用person1 ,person2 , person3的country 属性,当对象没有country属性的时候调用类的country属性,当对象有country 属性的时候,调用自己的country 属性

运行结果如下:
在这里插入图片描述
实例属性(对象属性):
实验代码如下:

在这里插入图片描述
self.name , self.age , self.gender 都是实例属性(有多少个对象,就存储多少个)

运行结果如下:

在这里插入图片描述

ps: 此处由于运用的编译工具具有自优化功能,因此,此处的地址显示的是一样的。其实应该是每一个年龄对应一个地址。(可以在Linux 中实现)

2.类属性与类方法不同点:(具体见下表)
(1)定义方面
(2) 工作占用的内存不一样
(3) 调用的方法不一样

类属性对象属性
定义类属性直接定义在里面定义时要与对象要与对象绑在一起
工作的内存只存一份,与对象的个数无关内存占用有多少个对象就存储多少份
调用方法为:类名.属性名 或 对象名.属性名调用方法为:对象名.属性名

(二)类方法,实例方法,静态方法

1.定义
实例方法: 默认传递的第一个参数是实例对象。该参数一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法),调用:只能由实例对象调用
类方法:默认传递的第一个参数是当前的类 使用装饰器@classmethod,该参数名一般约定为“cls”class的缩写,调用: 实例对象和类对象都能调用
静态方法:使用装饰器@staticmethod,参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法; 调用: 实例对象和类对象都能调用
2.使用方法
1)类方法:第一个参数必须是类对象,且cls 是形参,可以修改成其他变量名,但一般都用‘cls’
并且,类方法可以通过实例对象和类对象去访问
2)静态方法:一般会用装饰器 @staticmethod来标识为静态方法,静态放法不需要多定义参数,且能通过实例对象和类对象去访问

eg .
类方法的应用

class Date(object):
    def __init__(self, year=2019, month=6, day=17):
        self.year = year
        self.month = month
        self.day = day

    def echo(self):
        print("%s--%s--%s" % (self.year, self.month, self.day))

    @classmethod
    def as_string(cls, str):
        month, day, year = str.split('/')
        d1 = cls(year, month, day)
        return d1


d = Date()
d.echo()
str = '3/17/2019'
d1 = Date.as_string(str)
d1.echo()

运行结果为:
在这里插入图片描述
第一个结果是因为,在第一次调用的时候没有定义值,因此返回的就是默认值。
第二个结果在调用,有自己赋予值,因此返回的是调用后的结果。

静态方法的应用

class Date(object):
    def __init__(self, year=2019, month=6, day=17):
        self.year = year
        self.month = month
        self.day = day

    def echo(self):
        print("%s--%s--%s" % (self.year, self.month, self.day))

   @staticmethod
    def is_vaild(str):
        month, day, year = map(int, str.split('/'))
        return year>0 and 0<month <= 12 and 0 < day <= 31


d = Date()
d.echo()
print(Date.is_vaild('17/13/2019'))

运行结果为:
在这里插入图片描述
第一个结果是因为,在第一次调用的时候没有定义值,因此返回的就是默认值。
第二个结果是判断输入的年月日是否为合法的。

(三) property 属性

1) python内置的 @property 装饰器就是负责把一个方法变成属性调用的
2) @property 本身又创建了另一个装饰器@state.setter ,负责把一个setter 方法变成属性赋值,于是,我们就拥有了一个可控的属性操作
3) @property 广泛应用于类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样程序运行的过程中就减少了很多出错的可能性
eg:

 import time
    
    
   class Date(object):
        def __init__(self, year=None, month=None, day=None):
            self._year = year
            self._month = month
            self._day = day
    
        # 类属性 :获取类属性的方法: 对象名.属性名
        @property
        def month(self):
            if 0 < self._month < 12:
                return self._month
    
        # 设置属性装饰器,当设置属性时简洁: 对象名.属性名 = 新的值
        @month.setter
        def month(self, month):
            if 0 < self._month <= 12:
                self._month = month
                return True
    
        # 就删除属性装饰器,当删除时 简洁: del 对象名.属性名
        @month.deleter
        def month(self):
            del self._month
    
    
    d = Date(2019, 10, 10)
    print(d.month)
    d.month = 3
    print("正在修改月份")
    print(d.month)
    
    del d.month
    print("正在删除月份")

运行结果为:
在这里插入图片描述

(四)单例模式

  1. 定义: 单例模式是一个类只能构建一个对象的设计模式
  2. 如何理解: 实际上就是在打开一个文件的时候,打开一个就会弹出一个会话框,但要是每一次打开的都是同一个文件,那么要是一个文件打开多次,就会在不同的会话框显示就会使使用者混乱,不清楚到底哪个爱是真实的状态,并不方便我们的使用,因此要采用单例模式。eg: 一个系统只能有一个窗口管理或者是文件系统。
  3. 单例模式的实现方法 ——装饰器:@singleton
    @singleton 是用来装饰类的装饰器: 在实例化类时,只实例化 一个对象

eg:在学生名单中添加学生

def singleton(cls):
    instances = {}

    def wrapper(*args, **kwargs):
        if cls in instances:
            return instances[cls]
        else:
            obj = cls(*args, **kwargs)
            instances[cls] = obj
        return obj

    return wrapper


@singleton
class Student(object):
    pass


s1 = Student()
s2 = Student()
print(s1, s2)

运行结果为:
在这里插入图片描述ps :如果没有运用单例模式的装饰器,那么打印出来的s1和s2 的存储地址是不同的,即使他们里面的东西是相同的。 因此使用单例模式,就可以避免这个问题

(五)应用

1.小游戏设计 ————聪聪吃热狗(单人版 , 双人版)
游戏简述:一款聪聪吃热狗游戏,你可以自己调节通过↑↓←→控制聪聪的位置, 聪聪移动时会消耗能量 10, 游戏中吃到热狗分数加1, 能量加20,最后的目标就是称霸世界咯, 吃掉 所有的热狗即游戏胜利。王思聪能量消耗完毕即游戏失败。
游戏目标: 不断的吃掉热狗,不断的强大起来吧

实验代码:

import random
import time
import pygame
import sys
from pygame.locals import *

width = 640
height = 480
pygame.init()
screen = pygame.display.set_mode([width, height])
pygame.display.set_caption('聪聪吃热狗')
# 设置背景
background = pygame.image.load("./img/bg.jpg").convert_alpha()
congImg = pygame.image.load("./img/congcong.jpg").convert_alpha()
hotdogImg = pygame.image.load("./img/hotdog.jpg").convert_alpha()

# 背景音乐
pygame.mixer_music.load("./img/game_music.mp3")
pygame.mixer_music.play(loops=0, start=0.0)

# 成绩显示
count = 0
font = pygame.font.SysFont("arial", 40)
score = font.render("score %d" % count, True, (255, 255, 255))
status = font.render("Gaming", True, (255, 255, 255))
# 得到聪聪图片的宽度和高度
w_width = congImg.get_width() - 5
w_height = congImg.get_height() - 5
# 得到热狗图片的宽度和高度
y_width = hotdogImg.get_width() - 5
y_height = hotdogImg.get_height() - 5
fpsClock = pygame.time.Clock()  # 创建一个新的Clock对象,可以用来跟踪总共的时间


class cong():
    def __init__(self):
        self.power = 100
        # 聪聪的坐标
        self.x = random.randint(0, width - w_width)
        self.y = random.randint(0, height - w_height)

        # 聪聪移动的方法:移动方向均随机 第四条

    def move(self , new_x , new_y):
            # 判断移动后是否超出边界
        if new_x < 0:
            self.x = 0 - new_x
        elif new_x > width:
            # self.x=width-(new_x-width)
              self.x = 0
        else:
                # 不越界则移动聪聪的位置
             self.x = new_x
        if new_y < 0:
             self.y = 0 - new_y
        elif new_y > height:
                # self.y=height-(new_y-height)
                self.y = 0
        else:
                # 不越界则移动聪聪的位置
            self.y = new_y
        self.power -= 1  # 聪聪每移动一次,体力消耗1

        def eat(self):
            self.power += 20  # 聪聪吃掉热狗,乌龟体力增加20
            if self.power > 100:
                self.power = 100  # 聪聪体力100(上限)


class Hotdog:
    def __init__(self):
        # 热狗坐标
        self.x = random.randint(0, width - y_width)
        self.y = random.randint(0, height - y_height)

    def move(self):
        new_x = self.x + random.choice([-10])
        if new_x < 0:
            self.x = width
        else:
            self.x = new_x


congcong = cong()  # 生成聪聪
hotdog = []  # 生成10 - 40个热狗
hotdogs = [Hotdog() for i in range(10,40)]

# pygame有一个事件循环,不断检查用户在做什么。事件循环中,如何让循环中断下来(pygame形成的窗口中右边的插号在未定义前是不起作用的)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == KEYDOWN:
            # 通过上下左右方向键控制聪聪的动向
            if event.key == pygame.K_LEFT:
                congcong.move(congcong.x - 10, congcong.y)
            if event.key == pygame.K_RIGHT:
                congcong.move(congcong.x + 10, congcong.y)
            if event.key == pygame.K_UP:
                congcong.move(congcong.x, congcong.y - 10)
            if event.key == pygame.K_DOWN:
                congcong.move(congcong.x, congcong.y + 10)

    screen.blit(background, (0, 0))  # 绘制背景图片
    screen.blit(score, (500, 20))  # 绘制分数
    screen.blit(status, (0, 20))  # 绘制分数
    # 绘制热狗
    for item in hotdogs:
        screen.blit(hotdogImg, (item.x, item.y))
        # pygame.time.delay(100)
        item.move()  # 热狗的移动
    screen.blit(congImg, (congcong.x, congcong.y))  # 绘制聪聪

    # 判断游戏是否结束:当聪聪体力值为0或者热狗的数量为0游戏结束
    if congcong.power < 0:
        print("Game Over: Turtle power is 0")
        # 显示游戏状态
        status = font.render("Game Over: Congcong power is 0", True, (255, 255, 255))
        pygame.display.update()  # 更新到游戏窗口
        time.sleep(1)
        sys.exit(0)
    elif len(hotdogs) == 0:
        status = font.render("Game Over:Hotdog is empty", True, (255, 255, 255))
        pygame.display.update()  # 更新到游戏窗口
        sys.exit(0)
    for item in hotdogs:
          # 判断聪聪和热狗是否碰撞?
        if ((congcong.x < item.x + y_width) and (congcong.x + w_width > item.x)
                and (congcong.y < item.y + y_height) and (w_height + congcong.y > item.y)):
            hotdogs.remove(item)  #热狗被吃掉
            # 吃热狗音乐
            # eatsound.play()
            count = count + 1  # 累加
            score = font.render("score %d" % count, True, (255, 255, 255))
            # print("吃掉一个热狗")
            # print("聪聪最新体力值为 %d" %congcong.power)

    pygame.display.update()  # 更新到游戏窗口
    fpsClock.tick(10)  # 通过每帧调用一次fpsClock.tick(10),这个程序就永远不会以超过每秒10帧的速度运行

效果展示:
在这里插入图片描述

进阶双人版游戏
玩家1 : 通过 ↑↓←→ 来控制上下左右
玩家2 : 通过W,A,S,D 来控制上下左右

运行代码如下:

import random
import time
import pygame
import sys
from pygame.locals import *

width = 640
height = 480
pygame.init()
screen = pygame.display.set_mode([width, height])
pygame.display.set_caption('聪聪吃热狗')
# 设置背景
background = pygame.image.load("./img/bg.jpg").convert_alpha()
congImg1 = pygame.image.load("./img/congcong.jpg").convert_alpha()
congImg2 = pygame.image.load("./img/congcong.jpg").convert_alpha()
hotdogImg = pygame.image.load("./img/hotdog.jpg").convert_alpha()

# 背景音乐
pygame.mixer_music.load("./img/game_music.mp3")
pygame.mixer_music.play(loops=0, start=0.0)

# 成绩显示
count1 = 0
count2 = 0
font = pygame.font.SysFont("arial", 40)
score1 = font.render("score %d" % count1, True, (255, 255, 255))
score2 = font.render("score %d" % count2, True, (255, 255, 0))
status = font.render("Gaming", True, (255, 255, 255))
# 得到聪聪图片的宽度和高度
w_width = congImg1.get_width() - 5
w_height = congImg1.get_height() - 5
# 得到热狗图片的宽度和高度
y_width = hotdogImg.get_width() - 5
y_height = hotdogImg.get_height() - 5
fpsClock = pygame.time.Clock()  # 创建一个新的Clock对象,可以用来跟踪总共的时间


class cong():
    def __init__(self):
        self.power = 100
        # 聪聪的坐标
        self.x = random.randint(0, width - w_width)
        self.y = random.randint(0, height - w_height)

        # 聪聪移动的方法:移动方向均随机 第四条

    def move(self, new_x, new_y):
        # 判断移动后是否超出边界
        if new_x < 0:
            self.x = width
        elif new_x > width:
            # self.x=width-(new_x-width)
            self.x = 0
        else:
            # 不越界则移动聪聪的位置
            self.x = new_x
        if new_y < 0:
            self.y = height
        elif new_y > height:
            # self.y=height-(new_y-height)
            self.y = 0
        else:
            # 不越界则移动聪聪的位置
            self.y = new_y
        self.power -= 1  # 聪聪每移动一次,体力消耗1

        def eat(self):
            self.power += 20  # 聪聪吃掉热狗,聪聪体力增加20
            if self.power > 100:
                self.power = 100  # 聪聪体力100(上限)


class Hotdog:
    def __init__(self):
        # 热狗坐标
        self.x = random.randint(0, width - y_width)
        self.y = random.randint(0, height - y_height)

    def move(self):
        new_x = self.x + random.choice([-10])
        if new_x < 0:
            self.x = width
        else:
            self.x = new_x


congcong1 = cong()  # 生成聪聪
congcong2 = cong()
hotdog = []  # 生成10 - 40个热狗
hotdogs = [Hotdog() for i in range(10 ,40)]

# pygame有一个事件循环,不断检查用户在做什么。事件循环中,如何让循环中断下来(pygame形成的窗口中右边的插号在未定义前是不起作用的)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == KEYDOWN:
            # 通过上下左右方向键控制聪聪的动向
            if event.key == pygame.K_LEFT:
                congcong1.move(congcong1.x - 10, congcong1.y)
            if event.key == pygame.K_RIGHT:
                congcong1.move(congcong1.x + 10, congcong1.y)
            if event.key == pygame.K_UP:
                congcong1.move(congcong1.x, congcong1.y - 10)
            if event.key == pygame.K_DOWN:
                congcong1.move(congcong1.x, congcong1.y + 10)
            if event.key == pygame.K_a:
                congcong2.move(congcong2.x - 10, congcong2.y)
            if event.key == pygame.K_d:
                congcong2.move(congcong2.x + 10, congcong2.y)
            if event.key == pygame.K_w:
                congcong2.move(congcong2.x, congcong2.y - 10)
            if event.key == pygame.K_s:
                congcong2.move(congcong2.x, congcong2.y + 10)
    screen.blit(background, (0, 0))  # 绘制背景图片
    screen.blit(score1, (500, 20))  # 绘制分数
    screen.blit(score2, (0, 20))  # 绘制分数
    # 绘制热狗
    for item in hotdogs:
        screen.blit(hotdogImg, (item.x, item.y))
        # pygame.time.delay(100)
        item.move()  # 热狗移动
    screen.blit(congImg1, (congcong1.x, congcong1.y))  # 绘制聪聪
    screen.blit(congImg2, (congcong2.x, congcong2.y))  # 绘制聪聪

    # 判断游戏是否结束:当聪聪体力值为0或者热狗的数量为0游戏结束
    if congcong1.power < 0 or congcong2.power < 0:
        print("Game Over: Turtle power is 0")
        # 显示游戏状态
        status = font.render("Game Over: Turtle power is 0", True, (255, 255, 255))
        pygame.display.update()  # 更新到游戏窗口
        time.sleep(1)
        sys.exit(0)
    elif len(hotdogs) == 0:
        status = font.render("Game Over: Fish is empty", True, (255, 255, 255))
        pygame.display.update()  # 更新到游戏窗口
        sys.exit(0)
    for item in hotdogs:
               # 判断热狗和聪聪是否碰撞?
        if (((congcong1.x < item.x + y_width) and (congcong1.x + w_width > item.x)
             and (congcong1.y < item.y + y_height) and (w_height + congcong1.y > item.y))):
            hotdogs.remove(item)  # 热狗被吃掉
            # 吃热狗音乐
            # eatsound.play()
            count1 = count1 + 1  # 累加
            score1 = font.render("score %d" % count1, True, (255, 255, 255))
        if (((congcong2.x < item.x + y_width) and (congcong2.x + w_width > item.x)
             and (congcong2.y < item.y + y_height) and (w_height + congcong2.y > item.y))):
            hotdogs.remove(item)  #热狗被吃掉
            # 吃热狗音乐
            # eatsound.play()
            count2 = count2 + 1  # 累加
            score2 = font.render("score %d" % count2, True, (255, 255, 255))
     
    pygame.display.update()  # 更新到游戏窗口
    fpsClock.tick(10)  # 通过每帧调用一次fpsClock.tick(10),这个程序就永远不会以超过每秒10帧的速度运行

实验效果:
在这里插入图片描述

2. 按奇偶排序数组
给定一个非负整数数组 A ,返回一个数组,在该数组中 ,A 的所有偶元素之后跟着所有奇元素。
解法一:
实验代码为:

a = input("请输入需要验证的数组 :").split(' ')
li = list(map(int, a))


def isodd(num):
    return num % 2 == 0


sorted_num = sorted(li, key=lambda x: 1 if isodd(x) else 0)
print(sorted_num)

运行结果为:
在这里插入图片描述
解法二:
代码如下:

a = input("请输入需要验证的数组 :").split(' ')
li = list(map(int, a))
li1 = []
li2 = []


def isodd(num):
    if num % 2 == 0:
        li1.append(num)
    else:
        li2.append(num)
    print(li1 + li2)


for i in li:
    isodd(i)

运行结果如下:
在这里插入图片描述

3.电话号码的字母组合
在这里插入图片描述

实验代码如下:

class Number(object):
    def keyboard(self, digits):
                 # 创建字母对应的字符列表的字典
        dic = {2: ['a', 'b', 'c'],
               3: ['d', 'e', 'f'],
               4: ['g', 'h', 'i'],
               5: ['j', 'k', 'l'],
               6: ['m', 'n', 'o'],
               7: ['p', 'q', 'r', 's'],
               8: ['t', 'u', 'v'],
               9: ['w', 'x', 'y', 'z'],
               }
        # 存储结果的数组
        ret_str = []
        if len(digits) == 0:
            return []

        if len(digits) == 1:
            return dic[int(digits[0])

        result = self.keyboard(digits[1:])
        # result是一个数组列表,遍历后字符串操作,加入列表
        for r in result:
            for j in dic[int(digits[0])]:
                ret_str.append(j + r)
        return ret_str


if __name__ == '__main__':
    m = Number()
    print(m.keyboard('45'))

运行结果为:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值