Python-面向对象之封装

1、封装

封装就是指的是把数据和功能整合起来,封装类与对象我们可以较严格的控制它们的访问,做到隐藏它们和开放关联访问的接口。

2、隐藏

Python中Class可以采用双下划线开头的方式将属性隐藏(设置成私有的),这只是一种变形的操作,类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成“_类名__属性名”的形式。

class Foo:
    __N = 0  # 变形为_Foo__N

    def __init__(self):  # 定义函数时,会检测函数语法,所以__开头的属性也会变形
        self.__x = 10  # 变形为self._Foo__x

    def __f1(self):  # 变形为_Foo__f1
        print('__f1 run')

    def f2(self):  # 定义函数时,会检测函数语法,所以__开头的属性也会变形
        self.__f1()  # 变形为self._Foo__f1()


print(Foo.__N)  # 报错AttributeError:类Foo没有属性__N
print(Foo._Foo__N)  # 知道底层原理我们即可以通过“_类名__属性名”的形式访问
# 0
obj = Foo()
print(obj.__x)  # 报错AttributeError:对象obj没有属性__x

注意:

  1. 在定义类或者初始化对象时,在属性前加__,就会将该属性隐藏起来;但该隐藏起始只是一种变形,并没有真的隐藏起来,只是检测语法时自动变成了“_类名__属性名”的形式;
  2. 该变形操作是在类定义阶段扫描语法时发生的变形,类定义之后添加的__开头的属性不会发生变形;
  3. 该隐藏是对外不对内。

3、开放接口

定义属性是为了使用的,隐藏并不是目的

1.1 隐藏数据属性

将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行加以控制

class Student:
    __school = "oldboy"  # _Student__school = "oldboy"

    def __init__(obj, x, y, z): # #将名字和年纪都隐藏起来
        obj.__name = x  # obj._Student__name = x
        obj.__age = y
        obj.gender = z
        
# 对外提供访问信息的接口
    def __choose(self):  # obj._Student__choose
        print("%s 正在选课" % self.name)

#对外提供设置查看信息的接口,并附加类型检查的逻辑
    def get_name(self):
        print(self.__name)  # print(self._Student__name)

    def set_age(self,x):
        if type(x) is not int:
            print("年龄必须是整型,傻叉")
            return
        self.__age = x

    def get_age(self):
        print(self.__age)

    def del_age(self):
        del self.__age

stu_obj1 = Student("冯疯子", 18, "female")

# stu_obj1.set_age("asfdasfdasfafd") # 年龄不为整型 打印失败结果
stu_obj1.set_age(19) # 可正常修改
stu_obj1.get_age() # 取年龄

1.2 隐藏函数属性

目的的是为了隔离复杂度,例如ATM程序的取款功能,该功能有很多其他功能组成,比如插卡、身份认证、输入金额、打印小票、取钱等,而对使用者来说,只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

总结隐藏属性与开放接口,本质就是为了明确地区分内外,类内部可以修改封装内的东西而不影响外部调用者的代码;而类外部只需拿到一个接口,只要接口名、参数不变,则无论设计者如何改变内部实现代码,使用者均无需改变代码。这就提供一个良好的合作基础,只要接口这个基础约定不变,则代码的修改不足为虑。

4、property

Python专门提供了一个装饰器property,可以将类中的函数“伪装成”对象的数据属性,对象在访问该特殊属性时会触发功能的执行,然后将返回值作为本次访问的结果,另外property还提供设置和删除属性的功能;

# 三种使用案例
# 例1
class People:
    def __init__(self, name, height, weight):
        self.name = name
        self.height = height
        self.weight = weight

    @property
    def bmi(self):
        return self.weight / (self.height ** 2)


p = People('egon', 1.81, 70)
p.height = 1.84
print(p.bmi())

# 例2
class Student:
    __school = "oldboy"  # _Student__school = "oldboy"

    def __init__(obj, x, y, z):
        obj.__name = x
        obj.__age = y
        obj.gender = z

    def get_name(self):
        print("访问控制")
        return self.__name

    def set_name(self,x):
        print("赋值控制")
        self.__name = x

    def del_name(self):
        print("删除控制")
        del self.__name

    def get_age(self):
        return self.__age

    def set_age(self, x):
        if type(x) is not int:
            print("年龄必须是整型,傻叉")
            return
        self.__age = x

    def del_age(self):
        print("不让删")


    age = property(get_age, set_age, del_age)
    name = property(get_name, set_name, del_name)


stu_obj1 = Student("冯疯子", 18, "female")

# print(stu_obj1.age)
# stu_obj1.age = "19"
# del stu_obj1.age
# print(stu_obj1.age)


print(stu_obj1.name)
# stu_obj1.name="EGON"
# del stu_obj1.name

# 例3:
class Student:
    __school = "oldboy"  # _Student__school = "oldboy"

    def __init__(obj, x, y, z):
        obj.__name = x
        obj.__age = y
        obj.gender = z

    @property
    def name(self):
        print("访问控制")
        return self.__name

    @name.setter
    def name(self, x):
        print("赋值控制")
        self.__name = x

    @name.deleter
    def name(self):
        print("删除控制")
        del self.__name


stu_obj1 = Student("冯疯子", 18, "female")

stu_obj1.name

5、staticmethod、classmethod

类中的定义的函数
绑定方法: 谁来调用就会将谁当作第一个参数传入

  1. 绑定给对象的方法:类中定义的函数默认就是绑定给对象的方法,应该是由对象调用,会把对象当作第一个参数传入
  2. 绑定给类的方法:在类中的函数上加一个装饰器@classmethod,该函数就绑定给类了,应该是由类来调用,会把类当作第一个参数传入

非绑定方法: 既不与类绑定也不与对象绑定,就是一个普通的函数,谁都可以来调用,没有自动传参的效果,
在函数上添加装饰器@staticmethod

import uuid
import settings

class MySQL:
    def __init__(self,ip,port):
        self.mid = self.__create_id() # 接受生成的地址
        self.ip = ip
        self.port = port

    def tell_info(self): # 输入内容
        print("%s:<%s:%s>" %(self.mid,self.ip,self.port))

    @staticmethod 
    def __create_id():  # 用uuid模块生成独立地址
        return uuid.uuid4()  # 返回生成的地址

    @classmethod
    def from_conf(cls): # 绑定给类
        return cls(settings.IP, settings.PORT) # 返回对象

# obj = MySQL("10.10.11.11",3306)
# obj.tell_info()


obj1=MySQL.from_conf()
obj1.tell_info()

猜你喜欢

转载自blog.csdn.net/msmso/article/details/107820339
今日推荐