一:封装
造对象、整合程序,就已经用到了封装的思想。
在封装的基础上,我可以将装到对象或者类中的属性给隐藏起来。
注意:
(1)在定义类或者初始化对象时,在属性前加__,就会将该属性隐藏起来
但该隐藏起始只是一种变形_类名__属性名
,并没有真的隐藏起来(2)该变形操作是在类定义阶段扫描语法时发生的变形,类定义之后添加的__开头的属性不会发生变形
(3)该隐藏是对外 不对内的
(4) 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
1.将数据和功能的属性隐藏
class People:
def __init__(self, name, age, gender):
self.__name = name # 通过加双下划线__的方法来隐藏属性名
self.age = age
self.gender = gender
def __choose(self): # obj._Student__choose
print("%s 正在选课" % self.__name)
p1 = People('xxq', 18, 'male') # 实例化对象p1,并且传值
# print(p1.name)
# AttributeError: 'People' object has no attribute 'name'
# 属性错误:'People'对象没有'name'属性
print(p1.age)
# 18
print(p1.gender)
# male
# print(p1.__choose())
# AttributeError: 'People' object has no attribute '__choose'
# 属性错误:'People'对象没有'__choose'属性
print(p1.__dict__)
# {'_People__name': 'xxq', 'age': 18, 'gender': 'male'}
# 此时,name属性名并未真正地被隐藏,而是进行了变形:_People(类名)__name(属性名)
print(p1._People__name) # 依旧可以通过:p1(对象名)._People__name(变型后的属性名) 来访问
# xxq
print(p1._People__choose()) # 依旧可以通过:p1(对象名)._People__name(变型后的属性名) 来访问
# xxq 正在选课
2.将隐藏的属性通过接口调用
class People:
def __init__(self, name, age, gender):
self.__name = name # 通过加双下划线__的方法来隐藏属性名
self.age = age
self.gender = gender
def show_name(self): # 虽然不能在外部直接调用,但是可以在类内部的函数调用,然后外部调用函数,间接访问
print(self.__name)
p1 = People('xxq', 18, 'male') # 实例化对象p1,并且传值
p1.show_name()
# xxq
3.隐藏属性的意义何在
把数据属性隐藏起来的意义是:在类内开放接口,让外界使用者通过接口来操作属性值,我们可以在接口之上附加任意的逻辑
来严格控制外界使用者对属性的操作
二:property
装饰器
1.BMI(体质指数)例子
BMI指数(又称身体质量指数),是用体重公斤数除以身高米数平方得出的数字,是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。用户可根据测试结果安排更加合理的膳食营养和锻炼。健康人生从此开始。
class People:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
def bmi(self):
out_bmi = self.weight / (self.height ** 2)
return (f'您的BMI指数为:{out_bmi}')
p = People('xxq', 1.8, 70)
print(p.bmi())
# 您的BMI指数为:21.604938271604937
在上述例子中,实例化了一个对象p,但是bmi其实是一个功能函数,但是最后输出的时候,是b.bmi()
,而bmi则像是一个数据属性,不应该加括号。
此时,就需要一个property
装饰器来把这个函数伪装成一个数据属性
class People:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
out_bmi = self.weight / (self.height ** 2)
return (f'您的BMI指数为:{out_bmi}')
p = People('xxq', 1.8, 70)
print(p.bmi)
# 您的BMI指数为:21.604938271604937
例子:查、改、删
class People:
def __init__(self, name, age, gender):
self.name = name # 通过加双下划线__的方法来隐藏属性名
self.__age = age
self.gender = gender
@property
def show_age(self):
print(f'年龄:{self.__age}')
def set_age(self, x):
if type(x) is not int:
print("年龄必须是整型,傻叉")
else:
self.__age = x
print(f'修改成功,修改后年龄为:{self.__age}')
@property
def del_age(self):
print('想啥呢,怎么可能让你删呢!')
p1 = People('xxq', 18, 'male') # 实例化对象p1,并且传值
p1.show_age
# 年龄:18
p1.set_age(20)
# 修改成功,修改后年龄为:20
p1.del_age
# 想啥呢,怎么可能让你删呢!
进阶 - 完全伪装
class People:
def __init__(self, name, age, gender):
self.name = name # 通过加双下划线__的方法来隐藏属性名
self.__age = age
self.gender = gender
def show_age(self):
print(f'年龄:{self.__age}')
def set_age(self, x):
if type(x) is not int:
print("年龄必须是整型,傻叉")
else:
self.__age = x
print(f'修改成功,修改后年龄为:{self.__age}')
def del_age(self):
del self.__age
print('哟!删库跑路啊,等着坐牢吧!!!')
age = property(show_age, set_age, del_age)
p1 = People('xxq', 18, 'male') # 实例化对象p1,并且传值
p1.age
# 年龄:18
p1.age = 20
# 修改成功,修改后年龄为:20
del p1.age
# 哟!删库跑路啊,等着坐牢吧!!!
三:绑定方法 与 非绑定方法
1.绑定方法:谁来调用就会将谁当作第一个参数传入
1.绑定给对象的方法:类中定义的函数默认就是绑定给对象的方法,应该是由对象调用,会把对象当作第一个参数传入
2.绑定给类的方法:在类中的函数上加一个装饰器
@classmethod
,该函数就绑定给类了,应该是由类来调用,会把类当作第一个参数传入
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def tell_info(self):
print(f'姓名:{self.name},年龄:{self.age}')
@classmethod # 装饰类的装饰器
def f1(cls):
print(cls)
@staticmethod # 装饰静态方法的装饰器
def f2(x, y, z):
print(x, y, z)
p1 = People('xxq', 18)
p1.tell_info()
# 姓名:xxq,年龄:18
print(p1.tell_info)
# <bound method People.tell_info of <__main__.People object at 0x000002480E572A58>>
print(People.f1)
# <bound method People.f1 of <class '__main__.People'>>
People.f1()
# <class '__main__.People'>
print(p1.f2)
# <function People.f2 at 0x000001EB3FED2F28>
print(People.f2)
# <function People.f2 at 0x000001EB3FED2F28>
p1.f2(1, 2, 3)
# 1 2 3
People.f2(1, 2, 3)
# 1 2 3
2.非绑定方法:既不与类绑定也不与对象绑定,就是一个普通的函数,谁都可以来调用,没有自动传参的效果
在函数上添加装饰器
@staticmethod
settings.py
IP = "127.0.0.1"
PORT = 3306
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)
# obj = MySQL("10.10.11.11",3306)
# obj.tell_info()
obj1 = MySQL.from_conf()
obj1.tell_info()
# a62da398-6d2d-47b6-8105-ac2ca4d95828:<127.0.0.1:3306>