Python面向对象 | 封装

封装 :

  广义上的 :把属性函数都放到类里,只有这个类的对象才能使用类里的方法

  狭义上的 :定义私有成员私有变量和私有方法

封装原则:

  • 将不需要对外提供的内容都隐藏起来;

  • 隐藏对象的属性和实现细节,提供公共方法对其访问。

在python中用双下划线开头的方式将属性隐藏起来。所谓私有,就是不能在类的外面去引用它

 

定义一个私有的名字:就是在私有的名前面加两条下划线 __N = 'aaa'

# 私有类的静态变量
class A:
    __N = 'aaa'  # 静态变量
    def func(self):
        print(A.__N)  # 在类的内部使用正常

a = A()
a.func()        # aaa
print(A.__N)    # 在类的外部直接用 报错

那么__N真的私有的吗?

class A:
    __N = 'aaa'             # 静态变量
    def func(self):
        print(A.__N)        # 在类的内部使用正常

print(A.__dict__)

'''
执行输出:
{'__module__': '__main__', '_A__N': 'aaa', 'func': <function A.func at 0x000002CD16B9C048>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
'''

从输出的结果中,可以看到_A__N在外部,依然可以调用,只不过,存储的的时候,做了变形

print(A._A__N)   # 禁止调用,这样是不规范的

执行输出: aaa

在类的内部 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字

 

私有属性

class B:
    def __init__(self,name):
        self.__name = name

tony = B('Tony')
# print(tony.__name)            # AttributeError: 'B' object has no attribute '__name'
print(tony._B__name)            # Tony

私有方法

class C:
    def __wahaha(self):
        print('wahaha')

    def ADCa(self):             # 在里面定义方法,调用私有方法
        self.__wahaha()

c = C()
# c.__wahaha()                    # AttributeError: 'C' object has no attribute '__wahaha'
c._C__wahaha()                  # wahaha
c.ADCa()                        # wahaha

总结:

  • 在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__;

  • 类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式;

  • 在类中,可以使用self.__x的形式调用。外部无法调用,因为变形了。

面试题

class D:
    def __func(self):          # 变形为 _D__func
        print('in func')

class E(D):                  # E继承了D
    def __init__(self):     # 执行初始化方法
        self.__func()          # 变形为 _E__func

e = E()                     # AttributeError: 'E' object has no attribute '_E__func'

执行到self.__func()时,变形为_E__func此时E里面找不到这个方法,执行报错

 

私有的名字不能被子类继承

查看当前范围内的变量、方法和定义的类型列表

class D:
    def __func(self):  # 变形为 _D__func
        print('in func')

class E(D):
    def __init__(self):
        pass

e = E()
print(e.__dir__()) 

执行输出:
['__ge__', '__gt__', '__new__', '__reduce_ex__', '__reduce__', '__dict__', '__le__', '__eq__', '__sizeof__', '__format__',     '__getattribute__', '_D__func', '__hash__', '__str__', '__init__', '__module__', '__subclasshook__', '__weakref__', '__repr__',     '__lt__', '__setattr__', '__ne__', '__class__', '__dir__', '__delattr__', '__doc__']

从输出结果中,可以看出。_D__func就是D里面的__func方法。在内存中存储的值,已经变形了。

既然这样的话,那么就可以调用__func方法了

class D:
    def __func(self):  # 变形为 _D__func
        print('in func')

class E(D):
    def __init__(self):
        self._D__func()

e = E() # in func

但是不建议这么写,既然是私有属性,不能这么做。

面试题:下面的代码执行输出in D还是in E ?

class D:
    def __init__(self):
        self.__func()

    def __func(self):
        print('in D')

class E(D):
    def __func(self):
        print('in E')

e = E()                 # in D

 执行到第8部的时候,它需要找的是_D__func,所以结果输出in D

 

私有的名字,在类内使用的时候,就是会变形成_该类名__方法名

以此为例 :没有双下换线会先找E中的func,但是有了双下划线,会在调用这个名字的类D中直接找_D__func

class F:pass
F.__name = 'Tony'       # 是不是在创建私有属性?不是
print(F.__name)         
print(F.__dict__)       

'''
执行输出:
Tony
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'F' objects>, '__weakref__': <attribute '__weakref__' of 'F' objects>, '__doc__': None, '__name': 'Tony'}
'''

what? 它为啥不是私有属性?

  •   在类的外部,它不会发生变形只有在类的内部,才关心双下划线

  •   变形只在类的内部发生在类的外部,禁止访问私有属性

java中的对比

  • public 公有的 在类的内部可以使用,子类可以使用,外部可以使用 python中所有正常的名字;
  • protect 保护的 在类的内部可以使用,子类可以使用,外部不可以使用 python中没有;
  • private 私有的 只能在类的内部使用,子类和外部都不可以使用 python中的__名字;

 

python私有的用法

  • 当一个方法不想被子类继承的时候;

  • 有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用;

 

描述一个房子:这个例子,将长宽高隐藏起来的,外部知道名字,价格,面积就可以了。

class Room:
    def __init__(self, name, price, length, width, height):
        self.name = name
        self.price = price
        self.__length = length                          # 隐藏长
        self.__width = width                            # 隐藏宽
        self.__height = height                          # 隐藏高

    def area(self):
        return self.__length * self.__width


r = Room('鹏鹏', 100, 2, 1, 0.5)
print(r.name)
print(r.price)
print(r.area())

'''
执行输出:
鹏鹏
100
2
'''

用户名和密码问题,将密码保护起来

class Person:
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd

    def __show_pwd(self):
        li = []
        for i in self.__pwd:
            i = ord(str(i))  # 查看ascii码对应的顺序
            li.append(str(i))

        my_secret_pwd = ''.join(li)
        return my_secret_pwd

a = Person('xiao','42423')
ret = a._Person__show_pwd()    # 外部调用私有方法
print(ret)                      # 5250525051

 类中的私有成员:

  •   私有的静态属性
  •   私有的对象属性
  •   私有的方法

 

为什么要定义私有变量?

  •   不想让你看到这个值
  •   不想让你修改这个值
  •   不想让子类继承某些方法和属性
class Goods:
    __discount = 0.7
    
    def __init__(self,name,price):
        self.name = name
        self.__price = price
        
    def price(self):
        return self.__price * Goods.__discount      # 返回修改后的价格
    
apple = Goods('apple',10)
print(apple.price())                                # 7.0
class User:
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd
        self.pwd = self.get_pwd()

    def get_pwd(self):
        return hash(self.__pwd)     # 给密码加密
    
ming = User('ming','ming123')
print(ming.pwd)                     # 5504467288710963649

私有变量不能在类外部被定义:只能定义出一个名字叫__X的普通属性,不是私有成员

class A:
    __country = 'China'
print(A.__dict__)   
A.__language = 'English'
print(A.__dict__)   
'''
执行输出:
{'__module__': '__main__', '_A__country': 'China', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
{'__module__': '__main__', '_A__country': 'China', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, '__language': 'English'}
'''

私有变量不能被继承。因为子类在调用时,对象名字变为 _子类名__变量名,永远找不到父类中的 _父类名__变量名

class A:
    __country = 'China'
    def __init__(self,name):
        self.__name = name
class B(A):
    print(__country)            #程序报错,NameError: name '_B__country' is not defined
    def get_name(self):
        return self.__name      #程序报错, AttributeError: 'B' object has no attribute '_B__name'
b = B('ming')
b.get_name()

猜你喜欢

转载自www.cnblogs.com/Summer-skr--blog/p/11801415.html