Python,封装概念与隐藏属性,property(装饰器),绑定方法与非绑定方法
封装
一, 什么是封装?
封装指的就是把数据与功能都整合到一起,听起来是不是很熟悉,没错,我们之前所说的”整合“二字其实就是封装的通俗说法。
二, 隐藏属性
(1)在定义类或者初始化对象时,在属性前加__,就会将该属性隐藏起来
但该隐藏起始只是一种变形_类名__属性名,并没有真的隐藏起来
例:
class Student:
__school = "oldboy" # _Student__school = "oldboy"
def __init__(obj, x, y, z):
obj.__name = x # obj._Student__name = x
obj.age = y
obj.gender = z
def __choose(self): # obj._Student__choose
print("%s 正在选课" %self.name)
stu_obj1 = Student("卢旺达",19, "male")
print(stu_obj1.__dict__)
结果:
{'_Student__name': '卢旺达', 'age': 19, 'gender': 'male'}
我们可以从结果中注意到__name在定义类初始化的时候,他就改变了。
改变格式就是我们上述所描述的格式。-------》_类名__属性名
name我们在外面定义__一个变量回事怎么样的呢,会改变吗?
(2)该变形操作是在类定义阶段扫描语法时发生的变形,类定义之后添加的__开头的属性不会发生变形
例2:
class Student:
__school = "oldboy" # _Student__school = "oldboy"
def __init__(obj, x, y, z):
obj.__name = x # obj._Student__name = x
obj.age = y
obj.gender = z
def __choose(self): # obj._Student__choose
print("%s 正在选课" %self.name)
stu_obj1 = Student("卢旺达",19, "male")
stu_obj1.__x=111
print(stu_obj1.__dict__)
print(stu_obj1.__x)
结果:
{'_Student__name': '卢旺达', 'age': 19, 'gender': 'male', '__x': 111}
111
我们可以从这个结果看出,在定义类初始化以后,在类的外面在去添加一个x变量等等,不会变成-------》_类名___属性名
(3)该隐藏是对外不对内的
例:
class Student:
__school = "oldboy" # _Student__school = "oldboy"
def __init__(obj, x, y, z):
obj.__name = x # obj._Student__name = x
obj.__age = y
obj.gender = z
def choose(self): # obj._Student__choose
print("%s 正在选课" % self.name)
def get_name(self):
print(self.__name) # print(self._Student__name)
def get_age(self):
print(self.__age)
stu_obj1 = Student("卢旺达",19, "male")
stu_obj1.get_name()# 调用这个函数我们去查询name的名字,注意class中的代码
stu_obj1.get_age()
结果:
卢旺达
19
我们可以从结果看出,在我们调用的类中的函数,他们内部的代码并不是_类名___属性名格式的,而是原来我们定义的那个,所以这个隐藏式对外部而言,对内部来说并不是隐藏的。
(4) 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
三, 隐藏属性的意义何在
把数据属性隐藏起来的意义是:
1、在类内开放接口,让外界使用者通过接口来操作属性值,
我们可以在接口之上附加任意的逻辑来严格控制外界使用者对属性的操作
参考上述代码。
2、把功能属性隐藏起来:隔离复杂度
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(装饰器)
1.什么是特性property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
class Peopel:
def __init__(self,name,age,hight,weight):
self.name=name
self.age=age
self.hight=hight
self.weight=weight
@property
def bim(self):
return print(self.weight/(self.hight ** 2))
a=Peopel('卢旺达',22,1.68,60)
print(a.bim)
结果
21.258503401360546
2.为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
完整现代的使用property
class Peopel:
def __init__(self,name,age,hight,weight):
self.__name=name
self.__age=age
self.hight=hight
self.weight=weight
@property
def bim(self):
return print(self.weight/(self.hight ** 2))
@property#第一遍调用
def age(self): #函数名
print('查看操作')
return self.__age
@age.setter #(赋值的意思)
def age(self,x): #函数名
print('赋值操作')
self.__age=x
@age.deleter # (删除的意思)
def age(self): #函数名
print('删除操作')
del self.__age
print('删除成功')
a=Peopel('卢旺达',22,1.68,60)
print(a.age)
a.age=18
print(a.age)
del a.age
从上述代码中我们可以发现,函数名相同,但是上述函数的装饰器只有一个是 @property
余下的装饰器都是以age为开头点出某些东西,
如需要输入参数的==.setter==
需要删除操作的话==.deleter==
运行结果:
查看操作
22
赋值操作
查看操作
18
删除操作
删除成功
访问控制
面向对象之绑定方法与非绑定方法
一, 绑定方法
(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):
- (1)绑定给对象的方法:类中定义的函数默认就是绑定给对象的方法,应该是由对象调用,会把对象当作第一个参数传入
- (2)绑定给类的方法:在类中的函数上加一个装饰器@classmethod,该函数就绑定给类了,应该是由类来调用,会把类当作第一个参数传入
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def tell_info(self):# 给对象的绑定
print("<%s:%s>" % (self.name, self.age))
@classmethod #给类的绑定
def f1(cls):
print(cls)
p1=People('egon',18)
p1.tell_info()
print(p1.tell_info)
print(People.f1)
People.f1()
<egon:18>
<bound method People.tell_info of <__main__.People object at 0x000002BEBE6B6A60>>
<bound method People.f1 of <class '__main__.People'>>
<class '__main__.People'>
二, 非绑定方法:
- 既不与类绑定也不与对象绑定,就是一个普通的函数,谁都可以来调用,没有自动传参的效果,在函数上添加装饰器@staticmethod
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def tell_info(self):
print("<%s:%s>" % (self.name, self.age))
@classmethod
def f1(cls):
print(cls)
@staticmethod
def f2(x,y,z):
print(x,y,z)
p1=People('egon',18)
# p1.tell_info()
# print(p1.tell_info)
# print(People.f1)
# People.f1()
print(p1.f2)
print(People.f2)
p1.f2(1,2,3)
People.f2(1,2,3)
结果:
<function People.f2 at 0x000001DEAFCE5A60>
<function People.f2 at 0x000001DEAFCE5A60>
1 2 3
1 2 3
上述结果我们可以看出,非绑定的方法,函数对象与类都可以去调用他,而且是没有自动传参的效果的。
三, 使用条件
我们按照自己的需求去决定使用的是绑定方法还是非绑定方法。
例如,我们需要建立以个MySQL,需要有ID号,IP地址和接口号
import uuid
import settings
class MySQL:
def __init__(self,ip,port):
self.mid = self.__create_id()
self.ip = ip
self.port = port
def tell_info(self):
print("%s:<%s:%s>" %(self.mid,self.ip,self.port))
@staticmethod
def __create_id():
return uuid.uuid4()
@classmethod
def from_conf(cls):
return cls(settings.IP, settings.PORT)
obj1=MySQL.from_conf()
obj1.tell_info()
###
settings.py 文件配置如下
IP = "127.0.0.1"
PORT = 3306
结果:
f7f939df-e83c-41f0-a136-74441ba69a41:<127.0.0.1:3306>
我们由代码可以看出,调用与类绑定的函数 from_conf 时就是相当于,产生一个对象,所以我们在调用以后,需要把他赋值给一个变量。
像__create_id 这个我们不想让外界去修改他的值的操作隐蔽了以后直接可以在
__init__方法中去调用他,而且我们也不需要去给他传参数,从而我们直接给他使用定位非绑定方法 @staticmethod