面向对象之封装

Posted plf-jack

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象之封装相关的知识,希望对你有一定的参考价值。

封装(实际封装python中的封装只是一个约定)

第一层面的封装:类就好像一个袋子,这就是一种封装

第一阶段:

# 如果我们要定义学生jack如何定义?
name = 'jack'
age = 17
sex = '男'
这三个变量可以用来形容jack这个人(当然你也可以使用字典,列表去描述).但是我们用三个变量去形容这个人,有什么弊端?
    弊端:太零散,如果学生太多,需要有很多变量去描述
为了解决这个问题,因此才有了类。

第二阶段:

class Student(object):

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

one = Student('jack',17,'男') # 这里的one就相当于一个学生jack,所有的属性都封装到了one变量中。这里的Student类,相当于一个模板。只要给定它name,age,sex,它就能创建出一个学生对象。
two = Student('aaa',16,'男')
three = Student('bbb',15,'女')
four = Student('ccc',14,'男')
five = Student('ddd',13,'女')
print(f'姓名:one.name   年龄:one.age    性别:one.sex')
姓名:jack   年龄:17    性别:男

到这里,不知道你是否已经体会到使用类封装的便利没!

第二层面的封装:类中定义私有的,只有类内部使用,外部无法访问(比如_(杠) __(杠杠) )

第一阶段:

class Student(object):

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


one = Student('plf',18,'男')
one.name = 'who'
one.age = -28
one.sex = '人妖'
print(f'姓名:one.name   年龄:one.age    性别:one.sex')
姓名:who   年龄:-28    性别:人妖

==问题:==我们在外部能随意访问到对象one的属性,并且随意修改,这样数据是不安全的,因为我们需要将属性隐藏起来。那我们应该如何去做了?

第二阶段:

class Student(object):

    def __init__(self,name,age,sex):
        self.__name = name
        self.__age = age
        self.__sex = sex

one = Student('plf',18,'男')

print(one._Student__name)
print(one._Student__age)
print(one._Student__sex)

one._Student__age = 20  
print(one._Student__age)


rint(one.__name)       # 报错,无该属性
print(one.name)         # 报错,无该属性
plf
18
男
20

此时发现,我们虽然不能使用one.name或者one.__name访问到该属性。但是我们可使用one._Student__age访问到对象的age属性并且能修改。说明python在设置私有属性的时候,只是把属性的名字换成了其他的名字。

==总结:==

? 类中以_或者__的属性,都是私有属性,禁止外部调用。虽然我们可以通过特殊的手段获取到,并且赋值,但是最好不要这么做(约定俗成)

==问题:==现在我将name,age,sex设置为私有属性,但是我又想让他们通过我指定的接口去访问或者修改我的属性,应该如何实现了?

第三阶段:

Student(object):

    def __init__(self,name,age,sex):
        self.__name = name
        self.__age = age
        self.__sex = sex

    def get_name(self):
        return self.__name


    def set_name(self,name):
        if len(name) > 1 :
            self.__name = name
        else:
            print("name的长度必须要大于1个长度")

    def get_age(self):
        return self.__age

    def set_age(self, age):
        if age > 0 and age < 150:
            self.__age = age
        else:
            print("输入的年龄必须要大于0,小于150岁")

one = Student('plf',18,'男')

one.set_name('a')       # 通过自己设置接口,可以有效规避脏数据
print(one.get_name())       # 通过接口获取数据


one.set_age(-9)         # 通过自己设置接口,可以有效规避脏数据
print(one.get_age())    # 通过接口获取数据
name的长度必须要大于1个长度
plf
输入的年龄必须要大于0,小于150岁
18

这样我们就自定义了自己属性的接口,它的好处在于:规避脏数据

问题:使用接口设置获取数据 和 使用点方法(one.name = 18 或者print(one.name))设置数据相比, 点方法使用更方便,我们有什么方法达到 既能使用点方法,同时又能让点方法直接调用到我们的接口了? 其他python已经帮我们实现了,让我们一起看一下吧!

第四阶段:

class Student(object):

    def __init__(self,name,age,sex):
        self.__name = name
        self.__age = age
        self.__sex = sex

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,name):
        if len(name) > 1 :
            self.__name = name
        else:
            print("name的长度必须要大于1个长度")

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age > 0 and age < 150:
            self.__age = age
        else:
            print("输入的年龄必须要大于0,小于150岁")


one = Student('plf',18,'男')

one.name = '张三'
print(one.name)

one.age = 170
print(one.age)
张三
输入的年龄必须要大于0,小于150岁
18

总结:

1. 接口名必须和属性名相同,才能使用 @property 装饰器. 
2. 凡是赋值语句,就会触发set方法。获取属性值,会触发get方法

以上是关于面向对象之封装的主要内容,如果未能解决你的问题,请参考以下文章

python之面向对象之封装

面向对象之封装和继承

面向对象三大特性之封装

面向对象三大特性之封装

面向对象之:封装,多态

Python面向对象之封装