Python基础——类属性、类方法、异常

一、实例属性和类属性

1、类属性

  • 类属性是所有的是实例对象共用的属性
  • 它可以通过实例对象和类对象来获取
  • 类属性不能通过实例对象来修改!!!
  • 想修改类属性时,需要访问到该类属性

2、实例属性

  • 实例属性:每创建一个实例对象,都会在实例对象上添加这个属性

3、实例方法

  • 实例方法:存在于类对象Person中
  • python的类,带括号是实例化(如p = Person(‘张三’, 18)),不带括号是赋值(如p = Person)
  • 类的实例化只有一种方式,就是实例化的时候,需要带括号,这个括号根据实际情况可以为空,也可以传参
class Person(object):
    # 类属性money,是所有的是实例对象共用的属性
    money = 10000

    def __init__(self, name, age):
        # name和age称为实例属性:每创建一个实例对象,都会在实例对象上添加这个属性
        self.name = name
        self.age = age

    def test(self):
        # test(self)是实例方法:存在于类对象Person中
        print('我是test方法')


p = Person('张三', 18)  # 实例对象p:根据实例创建出来的对象
print(hex(id(p)))  # p指向的内存空间   0x7fe018163070
p1 = Person('李四', 23)  # 实例对象p1
print(hex(id(p1)))  # p1指向的内存空间   0x7fd04829c7c0
print(hex(id(Person)))  # 类对象:Person类指向的内存空间   0x7fd511444170

# money是类属性,它可以通过实例对象和类对象来获取
print(p.money)  # 可以通过实例对象来获取类属性   10000
print(p1.money)  # 10000
print(Person.money)  # 可以通过类对象来获取类属性   10000

# 类属性不能通过实例对象来修改!!!
# p.addr = '上海'  # python支持动态属性,给实例对象 p 添加一个 addr 属性
p.money = 20000  # 不会修改类属性 money,而是给实例对象 p 添加了一个 money 属性
print(p.money)  # 20000
print(p1.money)  # 10000
print(Person.money)  # 10000

# 想修改类属性时,需要访问到该类属性
p1.money = 100
Person.money = 3000
print(p.money)  # 3000
print(p1.money)  # 100
print(Person.money)  # 3000

在这里插入图片描述

二、实例方法、类方法和静态方法

1、实例方法

  • 当实例对象调用实例方法的时候,会自动的把实例对象 p 传递给 test 函数里 self参数;
  • 类对象也可以调用实例方法,但是,不会自动的给方法的 self 传参类;
  • 类对象调用实例方法的时候,需要手动的给方法的self传参,不推荐使用

2、类方法

  • 使用 @classmethod 装饰器来说明;
  • 有一个参数,参数是 cls,表示的类对象(def demo(cls)) ;
  • cls 参数,表示的是类对象,类方法一般配合类属性使用;
  • 只能访问类属性,不能访问到实例属性;
  • 类方法可以通过类对象、和实例对象来调用;
  • 需要使用类属性时候,使用类方法

3、静态方法

  • 使用 @staticmethod 装饰器
  • 函数不需要任何的参数(def foo()):;
  • 可以理解为一个普通的函数,直接附着到了一个对象上;
  • 默认不能够访问到类属性,不能访问到实例属性;
  • 既不需要访问类属性,也不需要使用实例属性,使用静态方法
class Person(object):
    __type = '人类'  # 私有的类属性,只能在类内部使用,类 外部无法访问

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def test(self):
        print('我是{}'.format(self.name))

    @classmethod
    def demo(cls):
        # print(cls)  # <class '__main__.Person'>是一个类对象
        # print('我是demo方法,我是一个类方法')
        # return Person.__type
        return cls.__type  # 类方法demo访问类类对象的一个私有属性
        # print(cls is Person)


    @staticmethod
    def foo():
        print('我是Foo函数')
        print(Person.__type)  # 人类,可以通过类对象访问类属性
        # print(p.name)  # 不能访问到实例属性,因为创建该方法时,还没有实例化一个对象


def bar():
    print('呵呵')


p = Person('jerry', 12)  # 此时p指向类一段内存空间
# test方法,需要使用实例对象来调用
# 1、当实例对象调用实例方法的时候,会自动的把实例对象 p 传递给 test 函数里 self参数
p.test()  # 此时self会指向p指向到这段内存空间,打印 我是jerry

# 2、类对象也可以调用实例方法,但是,不会自动的给方法的 self 传参
# 类对象调用实例方法的时候,需要手动的给方法的self传参
Person.test(p)  # 不推荐使用,需要手动传参p

# p.demo()  # True内存空间一样,cls和person
Person.demo()  # 类方法可以通过类对象来调用
print(p.demo())  # 类方法还可以通过实例对象来调用,打印"人类"

p.foo()  # 我是Foo函数,需要用实例对象或类对象来调用类方法
Person.foo()  # 我是Foo函数
# print(Person.__type)  # 外部访问会出错

三、__new__方法

  • __new__根据类对象申请一段内存空间,并返回 return object.new(cls)
  • __init__方法填入数据,自动把 __init__里的 self 参数指向第一步里申请好的内存空间
class Person(object):
    def __new__(cls, *args, **kwargs):
        print('__new__方法被调用了!!!')

        # 根据类对象申请一段内存空间
        return object.__new__(cls)

    def __init__(self, name, age):
        print('__init__方法被调用了!!!')
        self.name = name
        self.age = age


# 1. 调用 __new__ 方法申请内存
# 2. 调用 __init__ 方法填入数据,自动把 __init__ 里的 self 参数指向第一步里申请好的内存空间
# 3. 把 p 指向申请好的那块内存空间
p = Person('zhangsan', 18)
print(p)  # 如果没有申请内存,打印p时为None,return后,<__main__.Person object at 0x7fafd82544f0>

三、单例设计模式

  • 单例设计模式:第一次创建时候是什么样子,后续创建到所有都一样;
  • 加判断是否是第一次使用逻辑后,如果是,那后续都同第一次
class Person(object):
    __instance = None  # 私有属性

    __is_first = True  # 判断是否是第一次调用

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:  # 如果类属性值为空,即if cls.instance == None,则申请一段内存空间给到instance,如果再次申请时,instance已有值,不再申请空间
            cls.__instance = object.__new__(cls)  # 把申请到的内存空间给到instance(类对象.类属性:可以访问到类属性)
        return cls.__instance

    def __init__(self, name, age):
        if self.__is_first:
            self.name = name
            self.age = age
            self.__is_first = False

    def test(self):
        print(Person.__is_first)


p1 = Person('zhangsan', 18)  # p1先调用__new__,申请内存空间
p2 = Person('lisi', 20)  # p2创建时,instance已有值,不再申请内存空间,p1和p2指向同一块内存空间
# p3 = Person('王五', 21)

print(p1 is p2)  # 加了__new__方法中到一段逻辑后,结果为True,指向同一块内存空间
print(hex(id(p1)))  # 0x7fe44829c4f0
print(hex(id(p2)))  # 0x7fe44829c4f0
print(p1.name)  # lisi    zhangsan
print(p2.name)  # lisi    zhangsan   p2指向同一块内存空间后,会调用__init__初始化,修改name为lisi,如果加了判断是否是第一次使用逻辑后,均打印zhangsan
# 单例设计模式:第一次创建时候是什么样子,后续创建到所有都一样
p2.test()  # True,类属性__is_first只被使用过一次if self.__is_first:,后续改到都是实例属性

在这里插入图片描述

四、射击游戏

# 1、使用Gun类可以创建枪对象,枪有三个属性:
# 型号model:字符串、    杀伤力damage:整数    子弹数量bullet_count:整数,枪初始没有子弹
# 调用add_bullents方法可以增加子弹数量
# 调用shoot方法可以给参数敌人对象造成伤害
# 如果没有子弹,则提示玩家并且返回;如果有子弹,则子弹数量减少,调用敌人都hurt方法,给敌人造成伤害
# 2、使用Player类可以创建 警察对象 和 土匪对象,玩家有三个属性:
# 姓名name:字符串、   血量hp:整数    枪gun:使用Gun类创建都对象,玩家初始没有枪

# 调用hurt方法可以让玩家当前收到参数enemy_gun的伤害,具体流程如下:
# 1)玩家血量  减去 枪对象  的damage 伤害度
# 2)判断修改后的玩家血量
# 如果  血量 <= 0,  提示  玩家挂了,否则,提示  玩家受伤以及当前血量

# 调用fire方法可以向参数enemy开火,具体流程如下:
# 1)判断自己是否有武器,如果没有直接返回
# 2)检查自己的枪 是否有子弹,如果没有,自动装填子弹
# 3)让自己的枪调用shoot方法,并传递要设计的敌人对象


class Gun(object):
    def __init__(self, model, damage, bullet_count=0):
        self.model = model
        self.damage = damage
        self.bullet_count = bullet_count

    def add_bullet(self, count):
        self.bullet_count += count

    def shoot(self, x):
        if self.bullet_count <= 0:
            print('没有子弹,不能开枪')
            return
        self.bullet_count -= 1
        print('开了一枪,还剩{}发子弹'.format(self.bullet_count))
        x.hurt(self)


class Player(object):
    def __init__(self, name, hp, gun=None):  # 初始化没有枪,gun=None
        self.name = name
        self.hp = hp
        self.gun = gun

    def hurt(self, enemy_gun):
        if self.hp <= 0:
            print('已经死了,就不要再鞭尸了!!!')
            return
        self.hp -= enemy_gun.damage
        print('{}被{}打了,掉了{}血,还剩{}血'.format(self.name, enemy_gun.model, enemy_gun.damage, self.hp))

    def fire(self, enemy):
        if not self.gun:
            print('你还没有枪!')
            return
        if not self.gun.bullet_count:  # if self.gun.bullet_count==0
            print('没有子弹,自动装填子弹!')
            self.gun.add_bullet(30)  # 添加30发子弹

        self.gun.shoot(enemy)  # 将参数传过去,shoot()也需要添加x接收参数


gun1 = Gun('m416', 10)
p1 = Player('张警官', 100, gun1)  # 创建对象时,直接给gun1,也可以p1.gun=gun1
# p1.gun = gun1
p2 = Player('王土匪', 80)
# print(hex(id(gun1)))
# print(hex(id(policezhang)))
# print(hex(id(badwang)))
p1.fire(p2)
# for i in range(10):#循环,打10发子弹
#     p1.fire(p2)
# 调用fire方法时,def fire(self, enemy)中self指的时p1,即谁调用指的便是谁,
# 然后走到self.gun.shoot(enemy),即self.gun=p1.gun=gun1,即gun1调用shoot()方法,def shoot(self, x)中self指gun1
# x.hurt(self)此时self指gun1,即将gun1传过去,传到hurt中
# def hurt(self, enemy_gun),即gun1指hurt中的enemy_gun,x指hurt中的self,x调用的hurt方法,x指p2王土匪

五、异常处理

1、异常处理的基本语句

try except as

import os

file_name = '05-射击游戏案例.py'
if os.path.exists(file_name):  # os模块中path
    file = open(file_name, encoding='utf-8')
    print(file.read())
else:
    print('你要操作的文件不存在')

try:
    1 / 0
    file = open('test.txt', encoding='utf-8')
except:  # 不管有什么问题,都会到except中
    print('出问题了!要操作的文件不存在')

# 处理指定的错误
try:
    2 / 0
    file = open('test.txt', encoding='utf-8')
except FileNotFoundError:  # 只处理文件不存在到异常,执行 到2/0时,程序会崩溃
    print('出问题了!文件不存在异常')

# 处理多个指定的错误
try:
    1 / 0
    file = open('test.txt', encoding='utf-8')
except (FileNotFoundError, ZeroDivisionError):
    print('出错了!,文件不存在异常或除数为0异常')

# 出错时用变量e保存,会保存出错类型
try:
    1 / 0
    file = open('test.txt', encoding='utf-8')
except (FileNotFoundError, ZeroDivisionError) as e:
    print(e)  # division by zero
    # print(type(e))  # <class 'ZeroDivisionError'>

2、finally

  • try…finally…保证finally代码块里的内容一定会被执行;
  • 如果一个函数里有finally语句,finally语句里的代码也一定会执行;
file = open('01-实例属性和类属性.mp4', 'rb')

try:
    while True:
        content = file.read(1024)
        print(content)
        if not content:
            break
finally:  # 保证finally代码块里的内容一定会被执行
    print('文件被关闭了')
    file.close()
def test(a, b):
    try:
        c = a + b
        return c
    finally:
        return 'hehe'

# test 函数执行了多个return语句,后一个return会覆盖前一个return
print(test(1, 2))  # hehe  不是3

3、with关键字的使用

  • with关键字能够自动帮忙执行 close 方法,但不能处理异常;
  • with 是上下文管理器,with后面的对象,要有 __enter__和 __exit__方法;
  • 不是任意的一个代码都能放到 with关键字后面;
  • 如果要在 with 后面,对象必须要实现 __enter__和 __exit__方法
  • 读取文件异常中断时(打开文件和关闭文件),使用with,可以自动把文件关闭;
  • socket通信时(需要打开和关闭),也可以用with
with open('test.txt') as f:
    f.read()  # 读取文件时中断了,文件不能关闭,用了with上下文管理器后,可以自动把文件关闭
class Demo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def test(self):
        1 / 0
        print('我是test方法')

    def __enter__(self):
        print('我是enter方法,我被执行了')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('我是exit方法,我被执行了')
        print('exc_type={},exc_val={},exc_tb={}'.format(exc_type, exc_val, exc_tb))


d = Demo('lisi', 18)
d.test()  # 程序报错,但不会执行__enter__()和__exit__()方法
with Demo('zhangsan', 15) as d:
    d.test()  # 程序会报错,但会执行__enter__()和__exit__()方法

4、抛出异常

  • 使用raise抛出异常:一旦执行了raise语句,raise后面的语句将不能执行

常见的异常:
ValueError
FileNotFoundError
ZeroDivisionError
TypeError
SyntaxError
StopIteration
PermissionError
NameError
ModuleNotFoundError

def do_cal():  # 函数可能会出现异常
    num1 = int(input('请输入一个数字:'))
    if num1 < 0:
        raise ValueError  # 主动抛出一个异常,ValueError是系统自带的异常
    x = pow(num1, 0.5)
    print(x + 5)


try:
    do_cal()
except ValueError as e:
    print('程序出现了错误!')

5、自定义异常

1、自定义异常

class NegativeSqrtError(BaseException):  # 自定义异常NegativeSqrtError
    def __str__(self):
        return '负数不能开方!!!'


def do_cal():
    num1 = int(input('请输入一个数字:'))
    if num1 < 0:
        raise NegativeSqrtError  # 抛出自定义异常
    x = pow(num1, 0.5)
    print(x)


try:
    do_cal()
except NegativeSqrtError as e:  # 捕获自定义异常
    # print('程序出现了错误!')
    print(e)

2、例子
让用户输入密码,如果密码的长度不满足 [6,11] 位,抛出 PasswordError
打印错误信息时,输出内容是 ‘密码长度必须是6到11位!!!’

class LengthError(Exception):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return '密码长度必须是{}到{}位!!!'.format(self.x, self.y)  # 占位


def get_password():
    min_length = 6
    max_length = 11

    password = input('请输入您的密码:')
    if len(password) < min_length or len(password) > max_length or password.isdigit() == False:
        # raise LengthError  # 抛出异常的时候,不止可以抛出一个类对象,还可以抛出一个实例对象
        raise LengthError(min_length, max_length)  # 抛出实例对象,还可以传参
    return password


try:
    pwd = get_password()
    print(pwd)
except Exception as e:
    print(e)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值