面向对象之封装
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)
对象的更多说明 :
以上是关于面向对象之封装的主要内容,如果未能解决你的问题,请参考以下文章