第四周 day20:属性/类方法/静态方法

本节主要内容:

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)

猜你喜欢

转载自www.cnblogs.com/mwj-blog1/p/9379172.html
今日推荐