广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
只让自己的对象能调用自己类中的方法
狭义上的封装 ——> 面向对象的三大特性之一
属性 和 方法都藏起来 不让你看见
""" 会用到私有的这个概念de场景 1.隐藏起一个属性 不想让类的外部调用 2.我想保护这个属性,不想让属性随意被改变 3.我想保护这个属性,不被子类继承 """
class Person: __key = 123 # 私有静态属性 def __init__(self,name,passwd): self.name = name self.__passwd = passwd # 私有属性 def __get_pwd(self): # 私有方法 return self.__passwd #只要在类的内部使用私有属性,就会自动的带上_类名 def login(self): # 正常的方法调用私有的方法 self.__get_pwd() alex = Person('alex','alex3714') print(alex._Person__passwd) # _类名__属性名 print(alex.get_pwd()) #这种会报错 print(alex._Person__get_pwd())
# 所有的私有 都是在变量的左边加上双下划綫 # 对象的私有属性 # 类中的私有方法 # 类中的静态私有属性 # 所有的私有的 都不能在类的外部使用
二、封装与扩展性:对象可以调用类方法和静态方法么? 可以 但一般情况下 推荐用类名调用
有一道题是这样的
class Room: def __init__(self,name,length,width): self.__name = name self.__length = length self.__width = width def get_name(self): return self.__name def set_name(self,new_name): if type(new_name) is str and new_name.isdigit()==False: self.__name=new_name else: print('名字修改不合法') def area_room(self): return self.__length * self.__width my_room=Room('my_room',100,100) print(my_room.get_name()) #my_room print(my_room.set_name('big_room')) #big_room print(my_room.area_room()) #10000
1.property:
是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值,内置装饰器函数 只在面向对象中使用
先看一个简单一点的用法:
from math import pi class Circle: def __init__(self,r): self.r = r @property def perimeter(self): return 2*pi*self.r @property def area(self): return self.r**2*pi c1 = Circle(5) print(c1.area) # 圆的面积 #表明上可以省掉一个调用 的括号 print(c1.perimeter) # 圆的周长
如果用property装饰一下上面的例题,会怎么样呢?已然变成了进阶版
class Room: def __init__(self,name,length,width): self.__name = name self.__length = length self.__width = width @property #在每个方法都装饰这个函数,那么在下面调用的时候就可以把方法伪装为属性调用啦 def name(self): return self.__name @name.setter #这里为了实现对neme的修改,所以用name.setter这个装饰,并且方法名要和被修改的name保持一致 def name(self,new_name): if type(new_name) is str and new_name.isdigit()==False: #判断修改的新名字是字符串并且不是数字,才能允许修改 self.__name=new_name #这里要修改的是私有属性name 所以要加上双下划线 else: return '名字修改不合法' @name.deleter #装饰删除name def name(self): del self.__name @property #普通装饰作用 def area_room(self): return self.__length * self.__width my_room=Room('my_room',100,100) print(my_room.name) #my_room my_room.name='big_room' print(my_room.area_room) #10000 print(my_room.name) #big_room
del my_room.name #删除了,如果再打印my_room.name会报错的
#计算圆的周长和面积 from math import pi class Circle: def __init__(self,r): self.c_r=r @property def perimeter(self): return 2*self.c_r*pi @property def area(self): return pi*self.c_r**2 circle_1=Circle(3) print(circle_1.perimeter) print(circle_1.area) #计算体脂数 class Person: def __init__(self,high,weigh): self.high=high self.weigh=weigh @property def BMI(self): return self.weigh/self.high**2 zzy=Person(1.58,51) print(zzy.BMI)
为什么要用property:
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,
这种特性的使用方式遵循了统一访问的原则
2.method 方法:
classmethod 类方法 **** 当方法操作值涉及静态属性,传cls 进行类的操作,而不是传self 就用classmethod
class Goods: __discount = 0.8 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price * Goods.__discount @classmethod # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象 def change_discount(cls,new_discount): # 修改折扣 默认传cls cls.__discount = new_discount apple = Goods('苹果',5) print(apple.price) Goods.change_discount(0.5) # Goods.change_discount(Goods) apple.change_discount(0.7) #3.5不推荐使用对象调用 print(apple.price) # 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
staticmethod 静态的方法 ***
:在完全面向对象的程序中,
如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法
当想写纯面向对象中写一个和类和对象无关的函数时候,不想默认传self 这时候用staticmethod
class Staticmethod_Demo(): role = 'dog' @staticmethod def func(): #()里面可以任意写参数,不用默认写self
print("当普通方法用") Staticmethod_Demo.func()
staticmethod练习
三、小结
# 类方法和静态方法 都是类调用的 # 对象可以调用类方法和静态方法么? 可以 但一般情况下 推荐用类名调用 # 类方法 有一个默认参数 cls 代表这个类 cls # 静态方法 没有默认的参数 就象函数一样