面向对象之封装

Posted 胸不平$怎平天下

tags:

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

1. 将变化隔离; 

2. 便于使用;
3. 提高复用性; 
4. 提高安全性


#封装
#广义上的封装: 属一个类的静态和动态属性,总是出现在一个类中
  # 使用的永远用类名或者对象名调用
#狭义上的封装:就是把变量方法私有化,在类的外部以及子类中不能直接使用了

【封装原则】

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

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

私有变量:
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print(\'from A\')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
复制代码

 

这种自动变形的特点:

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

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

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

 

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

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

2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形

 

私有方法:

 

常情况 >>> 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

 

封装与扩展性:

#类的设计者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


#使用者
>>> r1=Room(\'卧室\',\'egon\',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area


#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,
               只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()

 

一个静态属性property本质就是实现了get,set,delete三种方法:

 

 

#房屋计算:面积价格
#房屋计算:面积价格
class Room:
    def __init__(self,owner,price,length,width,height):
        self.owner = owner
        self.__price_sing = price #房子单价
        self.__length = length
        self.__width = width
        self.height = height

    def get_area(self): #面积
        return self.__length * self.__width

    def get_price(self): # 面积 X 价格 == 总价格
        return self.__price_sing * self.get_area()

alex = Room(\'alex\',1000000,98,20,15)
print(alex.get_area())  #输出房子总面积
print(alex.get_price())  #输出房子总价钱

 

##############################################################################
#类中函数补充的三个点#
# 内置函数
   
#property *****
   
# classmethod ***
   
# staticmethod *
 

 

# 类 能够计算人体的BMI指
class Person:
    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)
alex = Person(\'sb\',1.75,85)
print(\'您的体脂率为:\',alex.bmi)
    #您的体脂率为: 27.755102040816325

 

 


class Wapper: 
  # a = 123
  # __b= 456
  # __no = \'不\'
  def __it(self):
    print( \'in it\')
    #print(__b)

c = Wapper()
c._Wapper__it() print(Wapper._Wapper__no) #在类外部调用__no私有变量 类名._类名__no
print(Wapper.__dict__) #打印出wapper这个类里面的对象,属性
# S.__B=\'alex\'
# print(S.__B.__dict__)



 
#圆形类计算
from math import pi class Cir: def __init__(self,r): self.r = 10 def area(self): return self.r*self.r*pi def pim(self): return 2
c= Cir()
print(\'面积为:\',c.area)
print(\'周长为:\',c.area)


#圆形类计算
from math import pi
class Corcle:
    def __init__(self,r):
        self.r = r
    @property
    def area(self):
        return self.r * self.r *pi
    @property
    def propen(self):
        return  2*pi * self.r
c = Corcle(105)
print(\'圆的面积为:\',c.area)
#圆的面积为: 34636.05900582747

print(\'圆的周长为:\',c.propen)
#圆的周长为: 659.7344572538566

 



#xxx.setter #给属性name 或者私有变量 重新赋值
class Foo:
    def __init__(self,name):
        self.__name = name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self,new_name):  #给name重新设一个函数里面的属性为私有
        if type(new_name) ==str:  #判断新new_name是否为字符串形式
            self.__name = new_name #如果不是的话就把__name 私有 == new_name
alex = Foo(\'alex\')  #d对象调用Foo类名 后进行传值(alex)
print(alex.name)

alex.name = 123   #1.对象名重新给类复制一个新的变量123。
                  # 2: # 为了迎合属性的设置方式

print(alex.name)

 



##########################@name.setter 方法##################  
删除操作
class A:
    pass
a = A()
a.name =\'sb\'
# print(a.name)
print(a.__dict__)
#{\'name\': \'sb\'}
del a.name         #删除a对象中的属性
print(a.__dict__)  #已经删除a对象中的属性

 

 
class Fo:
    def __init__(self,name):
        self.__name = name  #name变量为私有
    @property  #伪装方法名

    def name(self):
        return self.__name   #给name函数名 返回一个 上级name的私有__name
    @name.setter      #给name这个方法,函数名重新赋值

    def  name(self,new_name):  #定义一个新的new_name
        if type(new_name) ==str:  #判断这个new_name是否为str类型
            self.__name =new_name
    @name.deleter #为删除方法名定义一个del

    def name(self):
        del self.__name
# alex =Fo(\'alex,sb\')
# del alex.name
# print(\'alex.name\')

 

 
# 商品  价格 原价 打折 = 折后价#################
class Goods:
    def __init__(self,name,price,discount): #传入属性名
        self.name = name
        self.__price = price   #私有变量 价钱
        self.discount = discount  #折扣价格
    @property   #伪装方法名(函数名)
    def price(self):
        return self.__price * self.discount  #给price return 单价X折扣的返回值
apple = Goods(\'apple\',5,0.9) #给apple对象传入属性
print(\'apple的价格为:\',apple.price)
    #apple的价格为: 4.5
 
##################################@classmethod 方法####################
class Good:
    __discount = 0.9
    def __init__(self,name,price):
        self.name = name
        self.__price = price
    @property

    def price(self):
        return self.__price * Good.__discount

    @classmethod #将一个普通方法装饰为Good类方法重新装饰__私有属性
    def change_discount(cls,new_dis):
        #香烟打折 (将cls,new_dis 重新装饰私有变量)
        cls.__discount = new_dis
        # cls通过上面的装饰后 现在定义__discount 改为new_dis新类


Good.change_discount(1)    #通过classmethod 装饰后现在可以 用类名+方法名装饰私有变量
cig =Good(\'cigrette\',20)  #也可以通过cig对象来给叫香烟 cigrette 这个属性名 更改价格
print(cig.price)           # 通过Good.change_discount(1) 为方法名 折扣为1 * 原价 == 20
cig.change_discount(0.2)   #通过给实例化给方法名赋值 0.2折扣 X原价后
print(cig.price)           #输出结果==4.0

#类方法是被@classmethod装饰的特殊方法
    #被装饰之后,方法默认接受 类 作为新的参数
    #之后所有的操作都只能和 类中静态变量或私有变量相关 而不应该和对象相关
# 类名 和对象名 都可以直接调用方法
 
 

#########################@staticmethod方法#############################

 class Student:
#     def __init__(self,name):
#         self.name = name
#     @staticmethod #装饰一个方法不需要self参数 也不需要cls的参数的函数方法名
#     def login(a,b,c):
#         user = input(\'username\')
#         pwd = input(\'passwd\')
#         if user == \'alex\' and pwd == \'123\':
#             obj =Student(usr)
#             return obj
# ret =Student.login(1,2,3)
print(ret)

                                                            对象的更多说明 :

 



 


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

Python面向对象之:三大特性:继承,封装,多态。

19.Python面向对象之:三大特性:继承,封装,多态。

面向对象之:三大特性:继承(已讲),封装,多态

Java面向对象之封装

python之路之前没搞明白4面向对象(封装)

面向对象之:封装,多态,以及类的约束