python -- 属性方法/类方法/静态方法
主要内容:
1.属性
2.类方法
3.静态方法
一.属性
属性(@property):将方法伪装成属性(将动词伪装成名词),代码上没有什么提升,只是更符合逻辑上的思想,更合理.
配套装饰器:
1,修改 @属性名.setter **
2,删除 @属性名.deleter *
属性的初识
#需求一:求一个人的体质指数bmi
#缺点:指数bmi是一个数值,传统意义上一般理解为名词,一般设置为静态变量,但代码的实现过程中将bmi作为动态变量来用了,不方便理解,不合理
#改进:想办法把bmi当做属性来用(外部)
#解决:使用@property 来把方法伪装成变量,代码无实质提升,但外部可以直接把bmi当做静态变量看待
class Bmi: def __init__(self,name,hight,weight): self.name=name self.__hight=hight #身高私有化 self.__weight=weight #体重私有化 def bmi(self): bmi=round(self.__weight/(self.__hight**2),2) print("%s健康指数为%s" % (self.name,bmi)) p = Bmi("小花", 1.75, 70) p.bmi()
#需求二:将一个人实例化,将类中age()方法伪装成静态变量
class Person: def __init__(self,name,age): self.name=name if type(age) is int: #判断传入的年龄参数是否是int self.__age=age #对象里自动封装成_Person__age else: print("您输入的年龄类型有误") @property #年龄在一般人看来是静态变量,但是这里是方法,所以为了合理性,将age()函数调用伪装成age,执行的时候()不需要 #用到装饰器@property def age(self): return self.__age @age.setter #修改年龄的时候,人家以为这是个静态变量,想在外部直接 对象.属性 直接修改,但这实际上是个方法, # 所以修改的时候还需要继续伪装,继续用装饰器@属性名.setter,, # 一遇到想要修改属性的操作,比如p.age=20,就自动执行装饰器@age.setter下面的方法 def age(self,aa): #修改年龄的值 if type(aa) is int: #判断修改的字符串是否是int self.__age=aa else: print("您输入的年龄类型有误") @age.deleter def age(self): del self.__age # 删除对象中的age #普通版本(输出部分) #正确输入int类型的age p=Person("小花",18) print(p.age()) #年龄不是int型,报错 p=Person("小花","18") print(p.age()) # 进阶版本 # 年龄在思想上一般认为是名词,静态变量,但在上面是函数,调用的时候要使用 对象age() # 现在伪装一下,将方法伪装成静态变量,所以使用的时候直接是 对象.age
# @property 是将一个方法伪装成属性,代码本身没有什么提升 # @方法名.setter 是用来修改伪装的方法(属性)的时候自动执行的 # @属性名.deleter 用来删除属性,自动执行
# property的使用 : 类似于bmi这种,area,周长.... *** # @age.setter ** # @age.deleter * # 接上面的代码: #1.属性的修改 p=Person("小花",18) print(p.age) # 结果是18 # # 相当于print(p.age()),但这时候age()已经通过装饰器@property 伪装成了属性 p.age=20 # 用户想要修改年龄 # # 但age实际是一个方法,所以想改的时候必须再加一个装饰器@age.setter,在装饰器下面的age()方法中通过p.__age去修改 print(p.age) # 结果是修改后的结果20 #2.属性的删除 del p.age # 自动执行上面的装饰器@age.deleter
二.类方法
类方法(@classmethod): 通过类名调用的方法,类方法中第一个参数约定俗称cls,python自动将类名(类空间)传给cls.
cls只接受类空间.
# 类方法 class A: def func(self): #通过 对象.方法 引用,将对象名(对象空间)传给self print(self) @classmethod #类方法,类本身可以直接调用 def func1(cls): #cla是类方法默认的参数,传进来的是类(类空间),谁(某个类)调用传谁的空间 print(cls) #实例化一个A类的对象a1 a1=A() #通过对象a1调用类的普通方法 # 类不能直接调用自己的方法 a1.func() #<__main__.A object at 0x0000009AD39376D8> 此时self传入的是a1,也就是对象的空间 #通过类调用类的普通方法,必须将对象作为参数传给self A.func(a1) #<__main__.A object at 0x000000EB942F76D8> #如果想通过类名调用自己的普通方法,只有把自己的对象作为参数传给self,这样self接收的就是对象的空间 #类调用自身的类方法,cls=A(类A的空间) A.func1() #<class '__main__.A'> 类方法可以通过类名调用,传入的是类的空间 #对象调用类的类方法,获得的是cls还是类本身,cls接收的是类的空间 a1.func1() #<class '__main__.A'>
类方法的应用场景:
1.类中有些方法不需要对象的参与.
2.对类中的静态变量进行改变,要用类方法,类可以直接调用自己的类方法
3.继承中,父类得到子类的类空间,对子类的变量修改
# 场景1.类中有些方法不需要对象的参与. class A: name="alex" count=1 @classmethod #类方法 def func(cls): #想要得到"alex2",直接通过类就可以调用,不需要对象参与 return cls.name+str(cls.count+1) # A.func(1) #报错 cls接收的是类空间,不能是1 a1=A() #通过对象调用类的类方法 print(a1.func()) #alex2 #通过类调用类的类方法 print(A.func()) #alex2
# 场景2, 对类中的静态变量进行改变,要用类方法. class A: name="alex" count=1 @classmethod def func(cls): cls.name="taibai" cls.count=2 A.func() print(A.name) #taibai print(A.count) #2
#场景3:继承中,父类得到子类的类空间,并可以任意修改子类空间的所有内容
#(1)类通过访问自己的类方法,间接的修改子类空间的内容
#错误的
class A: name="alex" @classmethod def func(cls): print(cls) cls.age=20 return cls.age class B(A): age=10 print(A.func(B)) #报错 ,A.func(),cls默认接收的是A的类空间,但是后面又有一个参数,上面的func()里面没有多余的形参去接收 #如果想要print(A.func(B))执行
#修改方法:(在func()方法中多增加一个参数)
#正确的
class A: name="alex" @classmethod def func(cls,b): #cls=B(类B的空间) print(cls) #<class '__main__.A'> b.age=20 #修改类B 的静态变量 return b.age class B(A): age=10 print(A.func(B)) #20
需求:不通过类方法,想让我的父类的某个方法得到子类的类空间里面的任意值.
方法:直接让子类的对象间接的调用父类的方法,把子类的对象的空间传给父类的方法,然后通过对象查看子类的任意值(不能修改)
# 不通过类方法,想让我的父类的某个方法得到子类的类空间里面的任意值. class A: name="alex" def func(self): #b1.func(), 所以func()中self的值是b1,也就是b1对象的空间 print(self) #<__main__.B object at 0x00000093BABE76D8> #b1的内存地址 print(self.age) #22 #b1先在自己的对象空间里找,没有age,然后从自己的类B中找,找到了age=22 self.age=18 #相当于b1.age=18 由于对象只能查看自己类中的内容,但不能修改,这一步相当于b1在自己的对象空间中增加了属性age=18 print(B.__dict__) #{'__module__': '__main__', 'age': 22, 'f1': <function B.f1 at 0x000000C3C76C9A60>, '__doc__': None} #可以看出类B的空间里并没有修改age的值 print(self.__dict__)#{'age': 18} #实际是在对象自己的对象空间里增加了age=18 print(self.age) #18 #对象b1从自己的空间里找到了age=18 class B(A): age=22 def f1(self): print(666) b1=B() #实例化B类的对象b1 b1.func() #b1对象先在自己的空间里找func()方法,找不到,继续通过自己的类B找,也找不到.最后通过B类找父类B,找到func()执行 # print(b1) #<__main__.B object at 0x0000003986FF76D8> #对象b1的内存地址 # print(B) #<class '__main__.B'> #类B的内存地址
三.静态方法
静态方法:
是指在类中的而某一个方法上加上@staticmethod
作用:
1.使代码块:清晰
2.增加了代码的复用性
总结: 静态方法主要是用来放一些方法,方法的逻辑属于类,但是又和类本身没有交互,从而形成了静态方法,主要是让静态方法放在此类的名称空间之内,从而能够更加有组织性。
# 在定义静态方法的时候,和模块中的方法没有什么不同
# 最大的不同就在于静态方法在类的命名空间之中,并且在声明静态方法的时候,使用的标记为@staticmethod,表示为静态方法
# 在调用静态方法的时候,可以使用类名或者是实例名来进行调用,一般使用类名来进行调用
静态方法和类方法的区别:
1)静态方法无需传入self参数,类成员方法需传入代表本类的cls参数;
2)从第1条,静态方法是无法访问实例变量的,而类成员方法也同样无法访问实例变量,但可以访问类变量;
3)静态方法有点像函数工具库的作用,而类成员方法则更接近类似Java面向对象概念中的静态方法。
class A: @staticmethod #静态方法,可以不用传参 def login(username, password): if username == 'alex' and password == 123: print('登录成功') else: print('登录失败...') A.login('alex',1234)