在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("接受短信成功")