本文章最初发布在 XJHui’s Blog,未经允许,任何人禁止转载!
注意:最新修改版本已发布在 这里,点击前往查看!
私有化属性
有些属性不想让别人随意修改或者防止被意外修改,就要对属性进行私有化
基本概述
定义:
为了保证属性安全(不能被随意修改),可以将属性定义为私有属性
使用场景:
- 属性不想被类的外部直接调用
- 属性值不想随意被改变
- 不想被子类继承
语法:
1
2class Person:
__name = '张三' # 属性名前加两个下划线将该属性私有化
使用私有属性
案例:验证实例属性私有化后在类的外部不可调用
1
2
3
4
5
6
7
8
9
10
11class Person:
def __init__(self):
self.name = '张三' # 实例属性
self.__age = 17 # 私有属性
pass
pass
p1 = Person()
print(p1.name) # 打印实例属性运行结果:
1
print(p1.age) # 打印私有属性
运行结果:
案例:验证私有化属性可在类的内部调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Person:
def __init__(self):
self.name = '张三'
self.__age = 17
pass
def printData(self): # 实例方法,打印私有属性age
print(self.__age)
pass
p1 = Person()
p1.printData() # 通过调用实例方法,验证在类的内部可直接访问私有属性运行结果:
总结:将属性私有化后,就不可以在类的外部访问了,但内部使用不受任何影响
私有化属性可继承性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Person: # 父类
def __init__(self):
self.__name = '张三'
pass
pass
class Teacher(Person): # 子类调用父类
def test(self): # 子类中打印父类中的私有属性
print(self.__name)
t1 = Teacher()
t1.test()运行结果:
总结:父类的私有属性不可被子类继承
私有化方法
有些重要的方法,不允许外部调用或防止子类意外重写,可以把普通方法设置成私有化方法
语法规则
1 | class Animal: |
使用私有化方法
案例:验证私有方法不可被外部直接访问且不可被继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Animal:
def __showInfo(self):
print('这是动物类!')
pass
pass
class Bird(Animal):
pass
b1 = Bird()
b1.__showInfo()运行结果:
案例:私有方法在类的内部可正常访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Animal:
def __showInfo(self):
print('这是动物类!')
pass
def printData(self):
self.__showInfo()
pass
class Bird(Animal):
pass
b1 = Bird()
b1.printData()运行结果:
总结:
- 私有方法不可被外部访问且不可被继承
- 私有方法在类内部可正常访问
命名规范
- 头单下划线:保护类变量(不常用) _name
- 头双下划线:私有属性【方法】 __name
- 头尾双下划线:魔术方法【系统所有】,不可自定义 _init_
- 尾单下划线: 避免变量名与关键字冲突时可使用 class_
Property属性
获取和修改私有属性的值
方法一:调用set方法
1 | class Animal: |
运行结果:
方法二:使用Property属性函数
Property属性函数可以通过点语法来获取、修改私有属性的值
1 | class Animal: |
运行结果:
单例模式
实现整个系统中某个类的实例只创建一次
应用场景
网站登录(例如淘宝网,只允许一个账号同时浏览)
创建单例对象
1 | class People(object): |
运行结果:
错误与异常处理
引入
1 | age = 10 |
上面代码中,未定义name而直接输出,程序会报错如下:
程序报错导致整个程序结束,因此age不能正常显示。
有没有办法可以输出错误内容并使程序正常运行?有,异常处理。
异常处理
try…except
1
2
3
4
5
6age = 10
try:
print(name) # 准备捕获异常的代码
except NameError as msg: # except后跟错误类型,as将结果重定向
print('【{}】 异常'.format(msg))
print(age)运行结果:
拓展:如果可能有多种错误类型怎么办?
try跟随多个except语句
1
2
3
4
5
6
7l1 = ['hello', 1, True]
try:
print(l1[10])
except NameError as msg:
print('【{}】 异常'.format(msg))
except IndexError as msg:
print('【{}】 异常'.format(msg))运行结果:
方法二:捕获所有异常(万能)
1
2
3
4
5l1 = ['hello', 1, True]
try:
print(l1[10])
except Exception as msg:
print(msg)运行结果:
错误栈:
1
2
3
4
5
6
7
8
9
10
11
12def A(data):
return data / int(data)
def B(data):
return A(data) * 10
def Func(data):
B(data)
Func(0)分析:上面出现多个函数嵌套调用,每个函数中都需要写try…except?答案是:不需要
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16def A(data):
return data / int(data)
def B(data):
return A(data) * 10
def Func(data):
try:
B(data)
except Exception as msg:
print(msg)
Func(0)运行结果:
原理:
- 如果在函数中出现错误,则会将该错误返回到上一层,直至最顶层
- 如果错误出现在最顶层,则程序会结束
总结:合适位置添加try…except可以极大的减少代码量
else:
当try中未出现错误,会执行else语句
1
2
3
4
5
6
7
8
9
10def Func(data):
try:
print(int(10 / int(data))) # try里面是可以输出内容的
except Exception as msg:
print(msg)
else:
print('程序无异常!')
Func(5)运行结果:
finally:
无论是否报错都会执行的语句
1
2
3
4
5
6
7
8
9
10def Func(data):
try:
print(int(10 / int(data))) # try里面是可以输出内容的
except Exception as msg:
print(msg)
finally:
print('程序运行结束!')
Func(5)运行结果:
注意:虽然finally在这里显得很多余,但用其释放资源很方便。
自定义错误
直接或间接继承Exception类或者Error类
案例:当字符长度超过5时,抛出异常
1 | class LenError(Exception): # 继承Exception类 |
运行结果:
动态属性和方法
动态属性
支持实例属性和类属性的添加
添加实例属性:
通过实例对象添加
1
2
3
4
5
6
7
8
9
10
11
12class Student:
def __init__(self, name, age):
self.name = name # 初始方法定义实例变量
self.age = age
def __str__(self):
return '【{}】今年【{}】岁了。'.format(self.name, self.age)
zyh = Student('张艳华', 20)
zyh.weight = '101' # 动态添加实例属性
print(zyh.weight)运行结果:
动态添加的属性仅对该实例对象有效,验证:
1
2
3
4
5
6
7
8
9
10
11
12
13class Student:
def __init__(self, name, age):
self.name = name # 初始方法定义实例变量
self.age = age
def __str__(self):
return '【{}】今年【{}】岁了。'.format(self.name, self.age)
zyh = Student('张艳华', 20)
zyh.weight = '101' # 动态添加实例属性
wh = Student('王浩', 19)
print(wh.weight)运行结果:
添加类属性:
通过类对象添加
1
2
3
4
5
6
7
8
9class Student:
def __init__(self, name, age):
self.name = name # 初始方法定义实例变量
self.age = age
zyh = Student('张艳华', 20)
Student.weight = 101 # 动态添加类属性
print(zyh.weight)运行结果:
动态方法
原理是把一个外部函数通过转换(types.MethodType())使其成为实例方法
添加实例方法:
通过实例对象添加,仅对该实例对象有效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import types # 导入用来转换的types包
class Student:
def __init__(self, name, age):
self.name = name # 初始方法定义实例变量
self.age = age
def func(self): # 自定义的一个外部函数,self不能忘记
print('【{}】今年【{}】岁了!'.format(self.name, self.age))
zyh = Student('张艳华', 20)
zyh.printData = types.MethodType(func, zyh) # 实例对象.方法名=types.MethodType(外部函数名, 实例对象)
zyh.printData() # 实例对象.方法名(调用定义的实例方法)运行结果:
添加类方法和静态方法:
通过类对象实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Student:
def __init__(self, name, age):
self.name = name # 初始方法定义实例变量
self.age = age
def func(cls):
print('这是一个类方法!')
Student.testFunc = func # 动态添加类方法(通过类对象实现的),(类对象.方法名=外部方法名)
zyh = Student('张艳华', 20)
zyh.testFunc() # 验证类方法是否添加成功(实例对象调用类方法)运行结果:
注意:
- 静态方法同理(外部方法,要满足静态方法的条件)
- 类、静态方法不需要导入types包
_slots_
限制属性
添加属性(未使用slots方法):
1
2
3
4
5
6
7
8class Student:
pass
xm = Student()
xm.name = '小明' # 动态添加实例属性
xm.age = 19
print(xm.name, xm.age)运行结果:
限制属性添加(使用slots方法):
1
2
3
4
5
6
7
8
9class Student: # 使用slots方法限制属性的添加,字符串类型的属性名放入元组中,逗号分隔
__slots__ = ('name') # 仅允许添加一个名为name的属性
pass
xm = Student()
xm.name = '小明' # 动态添加实例属性
xm.age = 19
print(xm.name, xm.age)运行结果:
节省内存
dict存放所有属性(消耗内存):
1
2
3
4
5
6
7
8class Student:
pass
xm = Student()
xm.name = '小明' # 动态添加实例属性
xm.age = 19
print(xm.__dict__) # dict默认存放所有属性及其值运行结果:
使用slots后dict会被删除(节省内存):
1
2
3
4
5
6
7
8
9class Student:
__slots__ = ('name', 'age')
pass
xm = Student()
xm.name = '小明' # 动态添加实例属性
xm.age = 19
print(xm.__dict__) # dict默认存放所有属性及其值运行结果:
继承关系
案例1:父类限制属性(name,age),子类不限制,验证slots的限制不可继承
1 | class Student: # 父类 |
运行结果:
案例2:父类限制属性(name,age),子类限制属性(sex),验证slots的限制为其并集(父类+子类)
1 | class Student: # 父类 |
运行结果:
总结:
- 若子类无slots方法,则不继承slots
- 若子类有slots方法,slots的限制为其并集(父类+子类)
不足之处,欢迎留言,会及时回复,及时更正!
创作不易,感谢支持!