day 22 封装 + property + classmethod + staticmethod
面向对象的三大特性:继承 多态 封装
封装:()
广义上的:
狭义上的:会为一种现象起一个专属它的名字
把函数和属性封装到一个非全局的命名空间
class A:
__N = 'aaa' 静态变量
print(A.__N)
python
1.public
2.private
java(完全是面向对象的语言)
1.public
2.protect
3.private
定义一个私有的名字:就是在私有的名字面前加上双下划线 __N = 'aaa'
所谓私有就是不能再类的外面引用它
class A:
# __N = 'aaa' # 静态变量
# def func(self):
# print(A.__N) # 在类的内部使用正常
#
# a = A()
# a.func()
# print(A.__N) # 在类的外部直接使用 报错
class A:
__N = 'aaa'
def func(self):
print(A.__N)
print(A.__dict__)
print(A._A__N)
#{'func': <function A.func at 0x0000011B197637B8>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '_A__N': 'aaa', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'A' objects>}
#aaa
# 一个私有的名字 在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到。
# python对其的名字进行了修改: _类名__名字
# 只不过在类的外部调用 :需要“_类名__名字”去使用
# 在类的内部可以正常的使用名字
_A__N
# 在类内 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字
# 私有的名字,在类内使用的时候,就是会变形成_该类名__方法名
# 以此为例 :没有双下换线会先找E中的func
# 但是有了双下划线,会在调用这个名字的类D中直接找_D__func
# 变形只在类的内部发生
# class D: # def __init__(self): # self.__func() # def __func(self): # print('in D') # # class E(D): # def __func(self): # print('in E') # e = E()
# class F:pass
# print(F.__dict__)
# F.__name = 'aaa'
# f = F()
# print(f.__name)
# print(F.__dict__)
# class F:pass # print(F.__dict__) # F.__name = 'aaa' # f = F() # print(f.__name) # print(F.__dict__) # class F: # def ADC(self): # self.__name = 'alex' # # f = F() # f.ADC() # print(F.__dict__) # print(f.__dict__)
这个实例说明:在对象中创建的静态属性
Java中的对比:
public 共有的: 在类的内部可以使用,子类可以使用,在类的外部也可以使用 python中所有正常的名字
protect 保护的:在类的内部可以使用,子类可以使用,在类的外部不可使用 python中没有
private 私有的: 在类的内部可以使用,字类和在类的外部都不可使用。 python中的__名字
私有的用法:
当一个方法不想被子类继承的时候:
有些属性和方法不希望从外部调用,只希望从内部调用
# 人体BMI指数 # 体质指数(BMI)=体重(kg)÷身高^2(m) # 写一个类 描述人体BMI指数 class Person: def __init__(self,name,weight,height): self.name = name self.__height = height self.__weight = weight # self.bmi = self.__weight / self.__height ** 2 # self.bmi = self.cal_BMI() def cal_BMI(self): return self.__weight / self.__height ** 2 @property def bmi(self): return self.__weight / self.__height ** 2 p = Person('大表哥',92,1.85)
# print(p.cal_BMI())
# p.cal_BMI() # bmi是一个名词
# print(p.bmi) # bmi是一个名词
# p._Person__weight = 90
# print(p.bmi)
# 将一个方法伪装成一个属性
# 并不会让你的代码有什么逻辑上的提高
# 只是从调用者的角度上换了一种方式,使之看起来更合理
# @property 能够将一个方法伪装成一个属性
# 从原来的的对象名.方法名(),变成了对象名.方法名
# 只是让代码变的更美观
注意:如果出现了重名的名字:程序就会报错
# 将方法伪装成属性,方法中一般涉及的都是一些计算过程 # from math import pi # class Circle: # def __init__(self,r): # self.r = r # @property # def area(self): # return self.r**2*pi # # @property # def perimeter(self): # return 2*pi*self.r # c = Circle(10) # print(c.area) # print(c.perimeter) # c.r = 15 # print(c.area) # print(c.perimeter)
因为property不能传参,所有如果还想要将动态函数名改为名词性函数名,就需要用到名词性函数名.settle
方法伪装成的属性的修改 # class Person: # def __init__(self,n): # self.__name = n # 私有的属性了 # @property # def name(self): # return self.__name # # @name.setter # 重要程度 *** # def name(self,new_name): # if type(new_name) is str: # self.__name = new_name # else: # print('您提供的姓名数据类型不合法') # # p = Person('alex') # print(p.name) #def name(self): # p.name = 'alex_sb' #def name(self,new_name): # print(p.name) #def name(self): # p.name = 123 #def name(self,new_name): # print(p.name) #def name(self):
# 方法伪装成的属性的删除
class Person:
def __init__(self,n):
self.__name = n # 私有的属性了
@property # 重要程度 ****
def name(self):
return self.__name
# @name.deleter
# def name(self):
# print('name 被删除了')
# @name.deleter # 重要程度*
# def name(self):
# del self.__name
# p = Person('alex')
# print(p.name)
# del p.name # 只是执行了被@name.deleter装饰的函数
# print(p.name)
#@property --> func 将方法伪装成属性,只观看的事儿
#@func.setter --> func 对伪装的属性进行赋值的时候调用这个方法 一般情况下用来做修改
#@func.deleter --> func 在执行del 对象.func的时候调用这个方法 一般情况下用来做删除 基本不用
# 商品的 折扣
# 有一个商品 : 原价 折扣
# 当我要查看价格的时候 我想看折后价
# class Goods:
# def __init__(self,name,origin_price,discount):
# self.name = name
# self.__price = origin_price
# self.__discount = discount
#
# @property
# def price(self):
# return self.__price * self.__discount
# @price.setter
# def price(self,new_price):
# if type(new_price) is int or type(new_price) is float:
# self.__price = new_price
# apple = Goods('apple',5,0.8)
# print(apple.price)
# # 修改苹果的原价
# apple.price = 8
# print(apple.price)
class Goods:
__discount = 0.8
def __init__(self,name,origin_price):
self.name = name
self.__price = origin_price
@property
def price(self):
return self.__price * Goods.__discount
@classmethod
def change_discount(cls,new_discount): # 类方法 可以直接被类调用 不需要默认传对象参数 只需要传一个类参数就可以了
cls.__discount = new_discount
Goods.change_discount(1) # 不依赖对象的方法 就应该定义成类方法 类方法可以任意的操作类中的静态变量
apple = Goods('apple',5)
banana = Goods('banana',8)
print(apple.price)
print(banana.price)
# 折扣变了 店庆结束 恢复折扣
# apple.change_discount(1) # 如果要改变折扣 是全场的事情 不牵扯到一个具体的物品 所以不应该使用对象来调用这个方法
# print(apple.price)
# print(banana.price)
# staticmethod
# 当一个方法要使用对象的属性时 就是用普通的方法
# 当一个方法要使用类中的静态属性时 就是用类方法
# 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法
# def login():
# user= input('user :')
# if user == 'alex':print('success')
# else :print('faild')
#
# login()
class Student:
def __init__(self,name):pass
@staticmethod
def login(a): # login就是一个类中的静态方法 静态方法没有默认参数 就当成普通的函数使用即可
user = input('user :')
if user == 'alex':
print('success')
else:
print('faild')
Student.login(1)
# 完全面向对象编程
# 先登录 后 实例化
# 还没有一个具体的对象的时候 就要执行login方法
# 使用什么样的方法要看具体用到了哪些名称空间中的变量
# 当一个方法要使用对象的属性时 就是用普通的方法
# 当一个方法要使用类中的静态属性时 就是用类方法
# 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法