python练习生|面向对象——慢慢构建(类的初始化、封装、@property装饰器)
一.类的初始化(init())
1.特殊方法
- 我们在类中可以定义⼀些特殊⽅法,也称为魔术⽅法。
- 这些特殊⽅法都是如__xxx__()这种形式。
- 相对于普通方法需要调⽤,特殊方法会在特定时候⾃动调⽤。
2.特殊方法__init__()的用法
- init()对新创建的对象进行初始化操作,是初始化魔术方法。
- 下面我们举例介绍:
#__init__()方法
class Person():
def __init__(self):
print("奥利给!!!")
n1 = Person()
n1.__init__()
- 由上面两幅图对比图可知,魔术方法__init__()进了自动调用。
- 上面这幅图是上一篇博客在进行类对象中 方法的构建 以及 self 参数使用时举的例子,从图我们可以看出实例对象 n1和n2都有属性的赋值,但是实例对象n3则是调用了类对象中的参数值。如果我们对类对象中的参数进行“掩饰”,则会显示实例对象n3缺乏 name 属性而报错。
- 针对于此,我们可以了解到,name属性是必须的,但是各个name有不同(属性的私有性),所以难免的我们再添加name的时候容易遗忘。那么我们就可以运用特殊方法__init__(),对代码进行改进。从而减少这种报错。
#改进前
class Person():
name = '李云龙'
def Speak(self):
print('%s的意大利炮'%self.name)
print('{}的意大利炮'.format(self.name))
n1 = Person()
n1.Speak()
# 改进中
class Person():
def __init__(self):
self.name = '李云龙'
def Speak(self):
print('%s的意大利炮' % self.name)
print('{}的意大利炮'.format(self.name))
n1 = Person()
n1.Speak()
- 虽然两个代码块输出的值相同,但是其内部却发生了大变化。
- 改进前的name属性代码如果忘了添加,则会报错,而改进中的代码相当于是n1的私有代码,相当于进行了一个赋值操作。减少了这种报错,但是从图我们也可以看出,虽然使用了魔术方法,但是,代码输出形式依然单一,如果输出其他人需要对name属性进行更改。由此,我们诞生了一个问题,可否更好的‘私有赋值’?
思考一下,我们实现“私有赋值”,其实就是调用自己,那么,我们把上面代码
def __init__(self):
self.name = '李云龙'
中的“李云龙”,改为实例对象赋值的name岂不是就可以了? 改法如下:
- 由代码报错可得,第58行缺失一个参数。其实缺失的参数就是name(李云龙)
# #改进后
class Person():
def __init__(self,name):
self.name = name
def Speak(self):
print('%s的意大利炮' % self.name)
n1 = Person('李云龙')
n1.Speak()
3.类的基本结构
#类的基本结构
class 类名([父类]):
公共属性...
#对象的初始化方法
def __init__(self、...):
代码块
#对象的其他方法
def method1(self、...):
代码块
...
二.封装
1.封装的引入
- 当我们在其中加入一行代码时,再来看输出值
class Person():
def __init__(self,name):
self.name = name
def Speak(self):
print('%s的意大利炮' % self.name)
n1 = Person('李云龙')
n1.name = '春天'
n1.Speak()
- 之前博客写到我们对于属性的改变可以使用 对象.属性名 的形式对属性值进行改变。
- 但是,你是否觉得,这些值改的太随便,太任意了?
- 我们都知道,封装是⾯向对象的三⼤特性之⼀.
- 封装就是隐藏对象中的一些属性或方法,这些属性或方法不希望被外界访问。
- 通过封装 ,属性不能像之前那样可以随意更改
- 通过封装 ,属性不能改为任意的值
2.封装方式
(1).属性名的修改
- 我们通过对对象的属性名进行修改,从而提高数据的安全性(修改为外部不知道的属性名)
- 举个栗子:
#属性名的修改
class Dog():
def __init__(self,name):
self.hidden_name = name
def Speak(self):
print('请叫我%s'%self.hidden_name)
d = Dog('金毛')
d.Speak()
d.name = '哈士奇'
d.Speak()
d.hidden_name = '哈士奇'
d.Speak()
- 不同于以往的代码书写方式,我们将平时所写的 self.name 改为了外部不知道的 self.hidden_name ,所以,在使用 d.name 对属性进行更改时,无法对属性进行更改。
(2).getter和setter方法的使用
- 我们在进行属性的更改时,使用 getter和setter 方法使外部能够访问到属性并进行更改。
#getter和setter方法对属性进行更改
class Dog():
def __init__(self,name):
self.hidden_name = name
def Speak(self):
print('请叫我%s'%self.hidden_name)
#通过方法 get_name 获取name
def get_name(self):
return self.hidden_name
#通过方法 set_name 修改name
def set_name(self,name):
self.hidden_name = name
d = Dog('金毛')
d.Speak()
print(d.get_name())
d.set_name('萨摩耶')
d.Speak()
(3).(__属性)方式的封装(一般不推荐)
- 可以为对象属性使用双下划线的形式来进行封装,__XXX 。
- __XXX是对象的隐藏属性,隐藏属性只能在类的内部进行访问,无法通过对象访问。
- 隐藏属性其实是python自动给属性起了另外的名字,这个名字叫做( _类__属性名 )
class Dog():
def __init__(self,name):
self.__name = name
def Speak(self):
print('请叫我%s'%self.__name)
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
d = Dog('哈士奇')
d.Speak()
# print(d.__name) # AttributeError: 'Dog' object has no attribute '__name'
print(d._Dog__name) # 哈士奇
- 注:这种封装方式其实也是对属性名进行更改的方式,而且比较麻烦,不正规, 一般不推荐 使用 双下划线 形式进行属性的封装。
(4).(_属性)方式的封装
- 一般对私有属性进行封装,都是以 _开头 的形式
class Dog():
def __init__(self,name):
self._name = name
def Speak(self):
print('请叫我%s'%self._name)
def get_name(self):
return self._name
def set_name(self,name):
self._name = name
d = Dog('哈士奇')
print(d._name)
3.封装的作用
- 使⽤封装,虽然增加了类在定义时的复杂程度,但也提高了数据的安全性。
- 隐藏属性名,使调⽤者⽆法随意的修改对象中的属性。
- 增加了getter()和setter()⽅法,很好控制属性是否只读。
- 使⽤setter()设置属性,可以增加数据的验证,确保数据是正确的。
- 使⽤getter()⽅法获取属性,使⽤setter()⽅法设置属性。可以在读取属性和修改属性的同时做⼀些其他的处理。
三.@property装饰器
1.装饰器的作用
- 我们可以使⽤@property装饰器来创建只读属性。
- @property装饰器会将⽅法转换为相同名称的只读属性。
2.装饰器的用法
class Person():
def __init__(self,name):
self._name = name
@property
#我们通过@property来获取方法name的属性值,并把方法name作为属性名
def name(self):
print('获得了名字')
return self._name
#通过setter方法对获取的属性值进行修改 格式为@属性名.setter
@name.setter
def name(self,name):
print('修改了名字')
self._name = name
p = Person('李云龙')
print(p.name)
p.name = '赵刚'
print(p.name)
- 首先,通过 @property对方法name 进行 属性值的获取 (其实就是get_name),只不过是只读属性。然后将被装饰方法的名字作为属性名
- 其次,通过 @属性名.setter 的方式(其实就是set_name) 对属性值进行修改(设置)
- 最后,进行属性值的输出。
ps: 当然,还有一个deleter,没有说。其实用法与setter相同。只不过是删除属性值。
这里是引用
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
引用结束