0
点赞
收藏
分享

微信扫一扫

python面向对象、单例设计、异常处理、导包

MaxWen 2022-06-17 阅读 103

在python中定义一个包含方法的类

class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass

self属于哪个对象调用的方法,self就是哪个对象的引用

创建对象
对象变量 = 类名()
对象变量存储的是类名创建对象在内存中的地址

python中允许在类的外部直接给对象添加属性,但是不推荐

class Student:
def run(self):
print("%s is running" % self.name)

stu1 = Student()
stu1.name = "xiaoming"
stu1.run() # ok

stu2 = Student()
stu2.run() # err

使用类名创建对象时:1、分配空间,2、调用__init__初始化对象
当一个对象从内存中销毁,会自动调用__del__方法
del关键字可以删除一个对象

在python中,使用print输出对象变量,默认情况下会输出这个变量引用的
对象是由哪个类创建的,以及在内存中的地址。

如果希望print输出对象变量时,能够打印自定义内容,就可以利用__str__内置方法
__str__方法必须返回一个字符串

class Student:

def __init__(self, name):
print("__init__方法")
# self.属性名 = 属性的初始值
self.name = name
print("%s" % self.name)

def __str__(self):
return "__str__方法 %s" % self.name

def __del__(self):
print("__del__方法")


stu = Student("xiaoming")
# print(stu) 输出<__main__.Student object at 0x000001B4F3E43828>
# print(stu) 输出__str__方法 xiaoming
示例

class HouseItem:

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

def __str__(self):
return "[%s] 占地 %.2f" % (self.name, self.area)


class House:

def __init__(self, house_type, area):
self.house_type = house_type
self.area = area

self.free_area = area

self.item_list = []

def __str__(self):
return ("户型:%s\n总面积:%.2f[剩余:%.2f]\n家具:%s"
% (self.house_type, self.area,
self.free_area, self.item_list))

def add_item(self, item):
print("要添加 %s" % item)

if item.area > self.free_area:
print("%s 无法添加" % item.name)
return

self.item_list.append(item.name)

self.free_area -= item.area


bed = HouseItem("item_01", 4)
print(bed)
chest = HouseItem("item_02", 2)
print(chest)
table = HouseItem("item_03", 5)
print(table)

my_home = House("type_01", 10)
print(my_home)

my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)
print(my_home)

定义没有初始值的属性, 可以设为None
None关键字表示什么都没有
表示一个空对象,没有方法和属性,是一个特殊的常量
可以将None赋值给任何一个变量
判断一个变量是否是空,要用is(身份运算符)

示例

class Gun:

def __init__(self, model):
self. model = model

self.bullet_count = 0

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

def shoot(self):
if self.bullet_count <= 0:
print("[%s] bullet_count not enough" % self.model)
return

self.bullet_count -= 1

print("[%s] shoot one...[left: %d]" % (self.model, self.bullet_count))


class Soldier:
def __init__(self, name):
self.name = name

self.gun = None

def fire(self):
if self.gun is None:
print("[%s] don't have gun" % self.name)
return

self.gun.add_bullet(50)

self.gun.shoot()


ak47 = Gun("AK47")

soldier = Soldier("xiaoming")
soldier.gun = ak47

soldier.fire()

私有属性和私有方法
在定义属性或方法时,在属性或方法名前增加两个下划线,定义的就是私有属性或方法
私有属性和方法在类的外部不可以直接访问

但是在python中,没有真正意义的私有
python解释器对私有属性和方法的处理方式:
在名称前面加上_ 后变为:_类名__名称

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

def __secret(self):
print("name: %s age; %s" % (self.name, self.__age))


stu = Student("xiaoming")
print(stu._Student__age)
stu._Student__secret()

单继承

class 类名(父亲类):
pass

建议在没有父类的时候,统一继承自object类

方法的重写
重写父类方法有两种情况:
1、覆盖父类的方法
2、对父类方法进行扩展

1、覆盖父类的方法
如果子类中重写了父类的方法,那么在使用子类对象调用方法时,会调用子类中重写的方法

2、对父类方法进行扩展(子类的方法实现中包含父类的方法实现)
使用步骤:
(1)在子类中重写父类方法
(2)在需要的位置使用super().父类方法(),来调用父类方法的执行
(3)代码其他位置针对子类需求,编写子类特有的代码实现

class Parent:
def test(self):
print("test_parent")

class Child(Parent):
def test(self):
print("test_child")
super().test()

c = Child()
c.test()

子类对象的方法中,不能直接访问父类的私有属性和方法
子类对象可以通过父类的公有方法简介访问私有属性或方法

class Parent:
def __init__(self):
self.__num1 = 10
self.__num2 = 20

def test(self):
print("test_parent")
print("%d %d" % (self.__num1, self.__num2))

class Child(Parent):
def test(self):
print("test_child")
super().test()

c = Child()
c.test()

多继承:子类拥有多个父类的属性和方法

class Child(Parent1, Parent2):
pass

使用多继承时,应尽量避免一个子类继承的两个父类中有同名的方法和属性

多态是不同的子类对象调用相同的父类方法,产生不同的执行结果
多态以继承和重写父类方法为前提

class Parent:
def __init__(self):
self.num = 10

def print_num(self):
print("parent---->%d" % self.num)

class Child(Parent):
def print_num(self):
print("child----->%d" % self.num)

def test(t):
t.print_num()

p = Parent()
test(p)
c = Child()
test(c)

python中类是一个特殊的对象,
在程序运行时,类同时会被加载到内存中,
程序运行时,类对象在内存中只有一份,用给一个类可以创建多个对象实例
有类属性和类方法

获取类属性,可以使用类名、对象名来获取类属性
如果使用对象.类属性=值的赋值语句,只会给对象添加一个类属性,不会影响到类属性的值

class Tool:
# 使用赋值语句定义类属性
count = 0

def __init__(self, name):
self.name = name
# 类属性
Tool.count += 1


tool1 = Tool("斧头")
print(Tool.count)
tool2 = Tool("匕首")
print(Tool.count)
print(tool1.count) # 也可以获取类属性

类方法语法

@classmethod
def 类方法名(cls):
pass

类方法需要修饰器@classmethod来标识
类方法第一个参数应该是cls
由那个类调用的方法,方法内的cls就是哪个类的引用
通过类名.调用类方法;调用类方法时,不需要传参cls
在方法内部可以通过cls.访问类的属性
也可以通过cls.调用其他的类方法

class Tool(object):
# 使用赋值语句定义类属性
count = 0

@classmethod
def show_tool_count(cls):
print(cls.count)
print(Tool.count)

def __init__(self, name):
self.name = name
# 类属性
Tool.count += 1


tool1 = Tool("斧头")
Tool.show_tool_count()

静态方法
如果需要在类中封装一个方法,这个方法不需要访问实例属性或调用实例方法
也不需要访问类属性或调用类方法
就可以把这个方法封装成一个静态方法

语法
@staticmethod
def 静态方法名():
pass

示例
class Test(object):
@staticmethod
def my_print():
print("hello world")

t = Test()
t.my_print()

单例设计模式
目的是让类创建对象,在系统中只有唯一的一个实例
每一次执行类名()返回的对象,内存地址是相同的

__new__方法
使用类名()创建对象时,python会先调用__new__方法为对象分配空间
__new__是一个有object基类提供的内置静态方法;
主要作用有两个:
1、在内存中为对象分配空间;2、返回对象的引用
python的解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法

重写__new__方法一定要return super()._ new _(cls)
否则pyhton解释器得不到分配了空间的对象的引用,就不会调用对象的初始化方法
注意:__new__是一个静态方法,在调用时需要主动传递cls参数

class MusicPlayer(object):
# *表示多值元组参数;**表示多值字典参数
def __new__(cls, *args, **kwargs):
print("创建对象分配空间")
# 为对象分配空间并返回
return super().__new__(cls)

def __init__(self):
print("播放器初始化")

player = MusicPlayer()
print(player)
单例设计,并且初始化动作只执行一次

class MusicPlayer(object):
# 定义第一个被创建对象的引用
instance = None
# 记录是否执行过初始化动作
init_flag = False

def __new__(cls, *args, **kwargs):
# 判断类属性是否是空对象
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
# 返回类属性保存的对象的引用
return cls.instance

def __init__(self):
# 判断是否执行过初始化动作
if MusicPlayer.init_flag:
return
# 如果没有执行过,就执行初始化动作
print("对象初始化")
# 修改类属性标记
MusicPlayer.init_flag = True


player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)

异常处理

try:
num = int(input("输入一个整数:"))
result = 8 / num
except ZeroDivisionError:
print("除0错误")
except ValueError:
print("输入类型错误")
except Exception as result:
print("未知错误: %s" % result)
else:
print("没有异常的奖励")
finally:
print("不管有没有异常,都会执行的代码")

异常的传递
当函数/方法执行出现异常,会将异常传递给函数/方法的调用一方

def demo1():
return int(input("输入整数:"))

def demo2():
return demo1()

try:
print(demo2())
except Exception as result:
print("位置错误:%s" % result)

主动抛出raise异常步骤
1、创建一个Exception对象
2、使用raise关键字抛出异常对象

def input_password():
pwd = input("输入密码:")
if len(pwd) >= 8:
return pwd
else:
# 可以使用错误信息字符串作为参数
ex = Exception("密码长度不够")
raise ex


try:
print(input_password())
except Exception as result:
print("错误:%s" % result)


__name__属性,可以做到测试模块代码只在测试情况下执行,而被导入时不会执行
__name__属性记录一个字符串,如果被其他文件导入,​​​__name__​​​就是模块名
如果是当前执行的程序,​​​__name__​​​ 就是​​__main__​

包是一个包含多个模块的特殊目录
目录下有一个特殊文件__init__.py
包名的命名方式和变量名一致,小写字母
使用import 包名可以一次性导入包中所有的模块

init.py
要在外界使用包中的模块,需要在__init__.py中指定对外界提供的模块列表

示例

test.py
import test_package
test_package.sent_message.sent("hello")
test_package.receive_message.receive()

test_package下__init__.py
# 对外界提供模块列表
# .: 从当前目录导入
from . import sent_message
from . import receive_message

test_package下sent_message.py
def sent(text):
print("正在发送:%s ..." % text)


test_package下receive_message.py
def receive():
print("接受短信成功")


举报

相关推荐

0 条评论