zoukankan      html  css  js  c++  java
  • Python学习日记(二十六) 封装和几个装饰器函数

    封装

    广义上的封装,它其实是一种面向对象的思想,它能够保护代码;狭义上的封装是面向对象三大特性之一,能把属性和方法都藏起来不让人看见

    私有属性

    私有属性表示方式即在一个属性名前加上两个双下划线

    class Fighter:
        def __init__(self,name,hp,atk,speed):
            self.name = name
            self.__hp = hp                      #私有属性  变形成self._Fighter__hp
            self.__atk = atk                    #私有属性  变形为self._Fighter__atk
            self.__speed = speed                #私有属性  变形为self._Fighter__speed
    f1 = Fighter('AKK-18',1500,200,300)
    print(f1.__dict__)                          #{'name': 'AKK-18', '_Fighter__hp': 1500, '_Fighter__atk': 200, '_Fighter__speed': 300}

    python的私有属性只是在代码的级别给加了一层密,不允许你直接去访问这些私有属性,像你去打印一个私有属性它的结果就是报错,或者你想尝试修改一个私有属性的时候,结果并不能修改成功

    f1.__hp = 1000
    print(f1.__dict__)                          #{'name': 'AKK-18', '_Fighter__hp': 1500, '_Fighter__atk': 200, '_Fighter__speed': 300, '__hp': 1000}

    因为上面的私有属性都已经变形成_类名__属性名的格式,我们这样写,相当于直接给self添加了一个新的'键名'__hp,所以在类的外部调用双下划线就不行

    那如何访问我们的私有属性呢?我们可以看到上面的私有属性都被变形成了_类名__属性名的形式,那么我们可以这样去访问:

    print(f1._Fighter__hp)                      #1500
    print(f1._Fighter__atk)                     #200
    print(f1._Fighter__speed)                   #300

    但光这样走这样的捷径是不完美的,我们可以在类内部添加一个get_value函数来获得那些私有属性

    class Fighter:
        def __init__(self,name,hp,atk,speed):
            self.name = name
            self.__hp = hp                      #私有属性
            self.__atk = atk                    #私有属性
            self.__speed = speed                #私有属性
        def get_value(self):
            return self.__hp,self.__atk,self.__speed        #只要在类内部使用私有属性就会自动带上'_类名’
    f1 = Fighter('AKK-18',1500,200,300)
    print(f1.__dict__)                          #{'name': 'AKK-18', '_Fighter__hp': 1500, '_Fighter__atk': 200, '_Fighter__speed': 300}
    print(f1.get_value())                       #(1500, 200, 300)
    for i in f1.get_value():
        print(i)                                #1500
                                                #200
                                                #300

    在get_value中return的写法其实就是变形后再获取私有属性

    def get_value(self):
        return self._Fighter__hp,self._Fighter__atk,self._Fighter__speed

    私有静态属性

    class Fighter:
        __id = 1234445                          #私有静态属性
        def __init__(self,name,hp,atk,speed):
            self.name = name
            self.__hp = hp                      #私有属性
            self.__atk = atk                    #私有属性
            self.__speed = speed                #私有属性
        def get_value(self):                    #获取内部私有属性方法
            return self.__hp,self.__atk,self.__speed
        def get_id(self):
            return self.__id
    f1 = Fighter('AKK-18',1500,200,300)
    print(f1._Fighter__id)                      #1234445
    print(f1.get_id())                          #1234445

    私有方法

    class Fighter:
        __id = 1234445                          #私有静态属性
        def __init__(self,name,hp,atk,speed):
            self.name = name
            self.__hp = hp                      #私有属性
            self.__atk = atk                    #私有属性
            self.__speed = speed                #私有属性
        def get_value(self):                    #获取内部私有属性方法
            return self.__hp,self.__atk,self.__speed
        def get_id(self):                       #获取静态属性id的方法
            return self.__id
        def __shoot(self):                      #私有方法
            print('Shooting!')
        def get_shoot(self):                    #获取私有方法shoot
            self.__shoot()                      
            #self._Fighter__shoot()
    f1 = Fighter('AKK-18',1500,200,300)
    f1.get_shoot()                              #Shooting!

    修改私有属性

    class Room:
        def __init__(self,name,length,width):
            self.__name = name
            self.__length = length
            self.__width = width
        def Area(self):
            return self.__width*self.__length
        def get_name(self):         #获取这个私有名字的方法
            return self.__name
        def set_name(self,new_name):#重新设定这个房号
            if type(new_name) is str and new_name.isdigit() == True:
                self.__name = new_name
            else:
                print('错误的命名方式!')
    r1 = Room('1101',15,20)
    print(r1.Area())                #300
    print(r1.get_name())            #1101
    r1.set_name('asd')
    print(r1.__dict__)              #{'_Room__name': '1103', '_Room__length': 15, '_Room__width': 20}
    print(r1.get_name())            #1103

    几个装饰器

    1.@property

    我们在用面向对象的思想去写一个圆经常会把它的周长和面积当成一个方法,然而我们知道方法是一个获取的动作,而不是一个属性名词,所以要想处理这种将一个方法伪装成为一个属性就要用到@property,这样这个方法它就看起来像是一个属性了

    from math import pi as P
    class Circle:
        def __init__(self,r):
            self.r = r
        def Perimeter(self):
            return 2*P*self.r
        def Area(self):
            return P*self.r**2
    c = Circle(5)
    print(c.Area())                     #78.53981633974483
    print(c.Perimeter())                #31.41592653589793

    改进:

    from math import pi as P
    class Circle:
        def __init__(self,r):
            self.r = r
        @property
        def Perimeter(self):        #这里在self的后面不能传任何参数
            return 2*P*self.r
        @property
        def Area(self):             #这里在self的后面不能传任何参数
            return P*self.r**2
    c = Circle(5)
    print(c.Perimeter)              #31.41592653589793
    print(c.Area)                   #78.53981633974483

    BMI问题:BMI指数(BMI)=体重(kg)÷身高^2(m)

        成人的BMI数值:

        过轻:低于18.5

        正常:18.5-23.9

        过重:24-27

        非常肥胖:>32

    class BMI:
        def __init__(self,height,weight):
            self.__height = height
            self.__weight = weight
        @property
        def __bmi(self):                        #把计算bmi的方法伪装成一个属性
            return self.__weight/self.__height**2
    
        def get_bmi(self):                      #BMI判断
            if self.__bmi > 32:
                print('非常肥胖!')
            elif 24 <= self.__bmi <= 27:
                print('过重!')
            elif 18.5 <= self.__bmi <= 23.9:
                print('正常!')
            else:
                print('过轻!')
    
    b = BMI(1.75,72)
    b.get_bmi()                                 #正常!
    在@property的前提下用@setter来修改属性
    class Person:
        def __init__(self,name,):
            self.__name = name
        @property
        def name(self):
            return self.__name + ' hello!'
        @name.setter
        def name(self,new_name):
            self.__name = new_name
    p1 = Person('Jogn')
    print(p1.name)                               #Jogn hello!
    #p1._Person__name = 'Maria'                  #Maria hello!
    print(p1.name)                               #Maria hello!
    在@property的前提下用@deleter来删除属性
    class Person:
        def __init__(self,name,):
            self.__name = name
        @property
        def name(self):
            return self.__name + ' hello!'
        @name.deleter
        def name(self):                     
            del self.name                       
    p1 = Person('Jogn')
    print(p1.name)                               #Jogn hello!
    del p1.name                                  #del p1.name它在这里的作用是指向deleter下面这个方法,再去做这个方法的功能
    print(p1.name)                               #找不到这个名字了

    我们可以看一下在这里的del关键字它起到了什么的作用

    class Person:
        def __init__(self,name,):
            self.__name = name
        @property
        def name(self):
            return self.__name + ' hello!'
        @name.deleter
        def name(self):
            print('执行了这个方法!')
    p1 = Person('Jogn')
    print(p1.name)                               #Jogn hello!
    del p1.name                                  #del p1.name它在这里的作用是指向deleter下面这个方法,再去做这个方法的功能
    print(p1.name)                               #Jogn hello!

    因为第二个name里面没有关于修改名字的操作所以在最后p1.name还能打印出原来的名字

    2.@classmethod

    当这个方法只涉及到静态属性的时候,就应该使用classmethod来装饰这个方法

    class Goods:
        __discount = 0.8                                    #折扣
        def __init__(self,name,price):
            self.name = name
            self.__price = price
        @property
        def price(self):
            return self.__price * self.__discount
        @classmethod
        def change_discount(cls,new_discount):              #cls为类名
            cls.__discount = new_discount                   #修改折扣
    apple = Goods('苹果',4)
    print(apple.price)                                      #3.2
    Goods.change_discount(0.5)
    print(apple.price)                                      #2.0

    3.@staticmethod

    在完全面向对象的程序中,如果一个函数和对象没有关系那么就用staticmethod把这个函数变成一个静态方法

    class Login:
        def __init__(self,name,password):
            self.name = name
            self.password = password
        @staticmethod
        def get_n_psw():                            #没有默认参数就像函数一样
            username = input('请输入用户名:')
            psw = input('请输入密码:')
            Login(username,psw)                     #请输入用户名:asdd                                               
            return username,psw                     #请输入密码:4564648
    print(Login.get_n_psw())                        #('asdd', '4564648')
  • 相关阅读:
    关于求 p_i != i and p_i != i+1 的方案数的思考过程
    poj 3041 Asteroids 二分图最小覆盖点
    poj 1325 Machine Schedule 最小顶点覆盖
    poj 1011 Sticks 减枝搜索
    poj 1469 COURSES 最大匹配
    zoj 1516 Uncle Tom's Inherited Land 最大独立边集合(最大匹配)
    Path Cover (路径覆盖)
    hdu 3530 SubSequence TwoPoint单调队列维护最值
    zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)
    poj 1466 Girls and Boys 二分图最大独立子集
  • 原文地址:https://www.cnblogs.com/Fantac/p/11487685.html
Copyright © 2011-2022 走看看