一、封装
隐藏属性
封装:封装是面向对象三大特性之一。在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其含义是其他程序无法调用。要了解封装,离不开“私有化”,就是将类或者是函数中的某些属性限制在某个区域之内,外部无法调用。
1、在封装的基础上,我们可以将装到对象或者类中的属性给隐藏起来
注意:
(1)在定义类或者初始化对象时,在属性前加__(双下划线),就会将该属性隐藏起来,但该隐藏其实只是pycharm把这个变量名变为另一个命名方式,并没有真的隐藏起来,如
class Student:
__school = 'MIT'
stu1 = Student()
print(stu1.__school) # AttributeError: 'Student' object has no attribute '__school'
print(Student.__dict__) # __school变成了_Student__school
----------------------------
{'__module__': '__main__', '_Student__school': 'MIT', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
(2)该变形操作是在类定义阶段扫描语法时发生的变形,类定义之后添加的__开头的属性不会发生变形
class Student:
__school = 'MIT'
stu1 = Student()
stu1.__name = 'yang'
print(stu1.__name)
-----------------
yang
(3)该隐藏是对外不对内(正是基于这一点,我们可以通过方法来访问隐藏的属性)
class Student:
__school = 'MIT'
def get_school(self):
print(self.__school)
stu1 = Student()
stu1.get_school()
------------------------
MIT
(4)在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
隐藏属性的意义
1、把数据属性隐藏起来的意义是:我们可以使用接口(其实就是函数),把我们想让使用者使用的功能加以限制,比如我们可以先在函数里经过一系列的逻辑运算,来控制外界使用者对属性的操作。以下例子,为实现对输入年龄的类型做控制,正在原来的方法中,age没办法控制输入的类型,可以是int,也可以是str,如age='haavavlvl'
class Student:
__school = "MIT"
def __init__(obj, name, age, gender):
obj.__name = name # obj._Student__name = x
obj.__age = age
obj.gender = gender
def get_name(self):
print(self.__name) # print(self._Student__name)
def set_age(self,x):
if type(x) is not int:
print("年龄必须是整型")
return
self.__age = x
def get_age(self):
print(self.__age)
def del_age(self):
del self.__age
stu_obj1 = Student("yang", 18, "male")
stu_obj1.get_name()
stu_obj1.set_age("asfdasfdasfafd")
stu_obj1.set_age(19)
stu_obj1.get_age()
print(stu_obj1.__dict__)
------------------------------
yang
年龄必须是整型
19
{'_Student__name': 'yang', '_Student__age': 19, 'gender': 'male'}
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()
# 此时用户(即其他程序员)只需要调取一个对象下的功能就完成了一系列的操作
atm=ATM()
atm.withdraw()
至此,我们就通过封装的隐藏属性与提供接口实现了创建对象时属性的控制
property(特性)
Python内置的@property装饰器负责把一个方法变成属性调用:
# 例1计算bmi指数
class People:
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)
p = People('egon', 1.81, 70)
p.height = 1.84
# 不加装饰器property时
print(p.bmi())
# 加装饰器时候
print(p.bmi)
#例2:property的老式用法
class Student:
__school = "MIT"
def __init__(obj, x, y, z):
obj.__name = x
obj.__age = y
obj.gender = z
def get_name(self):
print("访问控制")
return self.__name
def set_name(self,x):
print("赋值控制")
self.__name = x
def del_name(self):
print("删除控制")
del self.__name
def get_age(self):
return self.__age
def set_age(self, x):
if type(x) is not int:
print("年龄必须是整型,傻叉")
return
self.__age = x
def del_age(self):
print("不让删")
age = property(get_age, set_age, del_age)
name = property(get_name, set_name, del_name)
stu_obj1 = Student("yang", 18, "male")
# print(stu_obj1.age)
# stu_obj1.age = "19"
# del stu_obj1.age
# print(stu_obj1.age)
print(stu_obj1.name)
# stu_obj1.name="EGON"
# del stu_obj1.name
# 例3:property的新式用法
class Student:
__school = "MIT"
def __init__(obj, x, y, z):
obj.__name = x
obj.__age = y
obj.gender = z
@property
def name(self):
print("访问控制")
return self.__name
@name.setter
def name(self, x):
print("赋值控制")
self.__name = x
@name.deleter
def name(self):
print("删除控制")
del self.__name
stu_obj1 = Student("冯疯子", 18, "female")
stu_obj1.name
类方法(classmethod)与静态方法(staticmethod)
1、类中定义的函数默认就是绑定给对象的方法,应该由对象调用,会把对象当做第一个参数
2、若使用classmethod装饰器,就会把函数绑定给类,pycharm会自动帮你传一个形参,cls,表示该函数绑定给类,应该由类来调用,会把类当做第一个参数
@classmethod
def f1(cls):
print(cls)
3、若使用静态方法static装饰器,表示不与类绑定也不与对象绑定,就是普通函数,需要什么参数就传什么参数
@staticmethod
def f2(x,y,z):
print(x,y,z)
具体要使用方法,就要看具体的场景了。