python之路---封装

【封装】

         隐藏对象的属性和实现细节,仅对外提供公共访问方式。

【好处】 

1. 将变化隔离; 

2. 便于使用;

3. 提高复用性; 

4. 提高安全性;

【封装原则】

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

      2. 把属性都隐藏,提供公共方法对其访问。

                                 私有变量和私有方法                             

 私有变量                              

class Person:
    def __init__(self,name):
        self.__name = name
    def __eat(self):
        print( "{} is pig".format(self.__name))     # 类里可以使用私有属性
p = Person('femgyu')
# print(p.__name)       # 无法调用私有方法
print(p._Person__name)  # fengyu         变形后可以调用,但是这种方法不提倡,因为私有属性或方法就不应该在类外面调用
# p.__eat()             # 无法调用私有方法
p._Person__eat()        # femgyu is pig  变形后可以调用,但是这种方法不提倡,因为私有属性或方法就不应该在类外面调用

这种自动变形的特点:

1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

3.在子类定义的__x不会覆盖父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

针对上面的3,有一道经典面试题

class A:
    def __init__(self):
        self.__func()
    def __func(self):
        print('A')
class B(A):
    def __func(self):
        print('B')
B()


# 对比下面的代码

class A:
    def __init__(self):
        self.func()
    def func(self):
        print('A')
class B(A):
    def func(self):
        print('B')
B()

这种变形需要注意的问题是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

2.变形的过程只在类的内部定义私有属性(或方法)时生效,在类外部定义私有属性(或方法)时,不会变形

class Person:
    def __init__(self,name):
        self.__name = name
    def __eat(self):
        print( "{} is pig".format(self.__name))     # 类里可以使用私有属性
p = Person('femgyu')
print(p.__dict__)
p.__age = 20
print(p.__dict__)

# 打印结果如下:
{'_Person__name': 'femgyu'}
{'_Person__name': 'femgyu', '__age': 20}

 私有方法                                          

在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B
 

#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

                               三个装饰器函数                                    

 property属性            将方法伪装成属性                           

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

class Student(object):
    def get_score(self):
        return self.score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self.score = value
s = Student()
s.set_score(99)
print(s.get_score())

# 可以任意修改分数
s.score = 1000
print(s.get_score())

这显然不合逻辑。

class Student(object):
    def get_score(self):
        return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
s = Student()
s.set_score(60)
print(s.get_score())

# 设为私有属性后,就不可以随便修改分数了
s.__score = 1000
print(s.get_score())

但是,上面的调用方法略显复杂,没有直接用属性这么直接简单。

还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

@property的实现比较复杂,我们先考察如何使用:

  把一个getter方法变成属性,只需要加上@property就可以了,

  此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值。

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
s = Student()

# 将方法变成属性进行赋值
s.score = 60
print(s.score)

s.__score = 1000
print(s.score)

  classmethod               (类方法)              

类方法:类中的方法传入类cls,不传对象self

    类中的方法不需要对象去调用,不需要去实例化一个对象,直接用类名调用

class A():
    role = 'dog'

    @classmethod
    def func(cls):
        print(cls.role)

A.func()

 staticmethod                    (静态方法)            

静态方法:类中的方法不需要传入对象self或者类cls

       直接用类名或对象名调用

静态方法就是在类里面定义的普通函数,但也是该类的局部函数。

class A:
    role = 'dog'

    @staticmethod
    def func():
        print(A.role)

A.func()
原文地址:https://www.cnblogs.com/yanyufeng/p/9630113.html