【python学习笔记】面向对象之封装

封装

① 第一个层面的封装:类本身就是一种封装

②第二个层面的封装:类中定义私有的,只有在类的内部使用,外部无法访问,命名变化,只是遵守约定,实际还是可以访问

#####python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class People:
	#star = 'earth'  #内部外部随便调用
	#_star = 'earth' #内部可以调用,但是只是约定,要调用还是可以的
	__star = 'earth'
	def __init__(self,id,name,age,salary):
		print('-->>',self.__star)  #内部就可以访问了
		self.id = id
		self.name = name
		self.age = age
		self.salary = salary

	def get_id(self):
		print('我的id是【%s】' % self.id)  #整个类内部所有的方法和属性封装在一起,直接访问类调用即可
	#访问函数,外部可以通过函数访问到私有的属性
	def get_star(self):
		print(self.__star)
#print(People.__dict__) #类的属性方法

p1 = People('123456789','ID Card',18,10000)

#增加下划线前
print(p1.star) #earth
print(p1._star) #earth,单下划线外部可以调用

#增加下划线后
#print(p1.__star) #报错,外部访问不了,不能通过__star访问到
print(People.__dict__)  #属性字典里面:'_People__star': 'earth',因此可以访问
print(p1._People__star)  #earth,py对__star重命名了 {'_People__star': 'earth'}
print(People._People__star) #earth
print(People.__star) ##报错,外部访问不了,不能通过__star访问到

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

#正常情况
>>> 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,height):
		self.name = name
		self.owner = owner
		self.__width = width
		self.__length = length
		self.__height = height

	#访问函数
	def tell_area(self): #求面积
		return self.__width * self.__length

r1 = Room('别墅','laowang',100,100,10)
#area = r1.__width * r1.__length #私有属性隐藏,外部访问不了
area = r1.tell_area() #调用访问函数间接从外部访问到私有属性
print(area)

######求体积
class Room:
	def __init__(self,name,owner,width,length,height):
		self.name = name
		self.owner = owner
		self.__width = width
		self.__length = length
		self.__height = height

	#访问函数
	def tell_area(self): #求面积
		return self.__width * self.__length * self.__height #外部调用感知不到,仍然使用该方法,但是功能已经变了
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

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()

property的概念

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

class People:
	def __init__(self,name,weight,height):
		self.name = name
		self.weight = weight
		self.height = height

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

p1 = People('laowang',75,1.8)
print(p1.bmi) #23.148148148148145
import math

class Circle:
	def __init__(self,radius): #圆的半径
		self.radius = radius

	@property
	def area(self):
		return math.pi * self.radius ** 2 #计算面积

	@property
	def perimeter(self):
		return 2 * math.pi * self.radius

c = Circle(10)

print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行
print(c.perimeter)

为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

当类里面的属性设置为私有时,在python中通过property方法可以实现统一的访问,设置set、get、delete方法(接口)进行访问

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    def getname(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    def setname(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    def delname(self):
        raise TypeError('Can not delete')

    name=property(getname,setname,delname) #不如装饰器的方式清晰

总结

1.通过封装明确内部和外部

2.通过继承和多态在语言层面上支持了归一化设计

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值