python's twenty-second day for me 封装,property方法

面对对象的三大特性:继承,多态,封装。

  函数和属性装到了一个非全局的命名空间----封装。

封装:

    在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字前加上‘__’(双下划线)

    在类内,只要你的代码遇到‘__’(双下划线).名字,就会被python解释器自动转换_类名__名字。

class A:
    __N = 'aaa'     # 静态变量
    def func(self):
        print(A.__N)    # 在类的内部使用正常 ‘aaa’
print(A.__dict__)   #  会以这种形式存储到字典中:{'_A__N': 'aaa'}
# print(A.__N)        # 直接在外部调用会报错
# print(A._A__N)      # 所以可以使用这种方式调用,但是不能这样调用。
a = A()
a.func()
# 一个私有的名字,在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到。
# python对其的名字进行了修改:_类名__名字。
# 只不过在类的外部调用: '_类名__名字'去使用。
# 在类的内部可以正常的使用名字调用。

  私有的名字不能被子类继承:

class D:
    def __func(self):       # _D_func
        print('in func')
class E(D):
    def __init__(self):
        self.__func()     # 它会找   _E__func 这样的名字。

e = E()  #  会报错,因为私有的名字不能被继承,
class D:
    def __init__(self):
        self.__func()       # 在哪个类中定义的名字就会以固定方式存储: _D__func
    def __func(self):       # _D__func
        print('in D')
class E(D):
    def __func(self):    # _E__func
        print('in E')
e = E()

# 私有的名字,在类内使用的时候,就是会变成:   _该类名__方法名
# 以上为例:没有双下划线会先找E中的func
# 但是有了双下划线,会在调用这个名字的类D中直接找_D__func
面试题

  变形只在类的内部发生:

class F:pass
F.__name = 'alex'   # 并不是创建私有属性。
print(F.__name)
print(F.__dict__)       # {'__name': 'alex'}  并不是私有属性

Java中的对比:

  public  共有的  在类的内部可以使用,子类可以使用,外部可以使用  python中所有正常的名字。

  prctect  保护的  在类的内部可以使用,子类可以使用,外部不可以使用,  python中没有

  private  私有的  只能在类的内部使用,子类和外部都不可以使用  python中的  __名字。(双下划线)

私有的用法:

    1,当一个方法不想被子类继承的时候。

  2,有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用。

@property  能够将一个方法伪装成一个属性。将代码变得更美观。

从原来的对象的对象名.方法名(),变成了对象名.方法名。

class Person:
    def __init__(self,name,weight,height):
        self.name = name
        self.__height = height
        self.__weight = weight
    @property
    def bmi(self):
        return self.__weight/self.__height**2
print(Person.__dict__)
p = Person('顾小白',70,1.75)
print(p.__dict__)    #{'name': '顾小白', '_Person__weight': 70, '_Person__height': 1.75}
# 被property装饰的bmi仍然是一个方法,存在Person.__dict__
# 对象的.__dict__中不会存储这个属性。

# 在一个类加载的过程中,会先加载这个的名字,包括被property装饰的。
# 在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性。
# 如果有就不能在自己的对象空间中创建这个属性了。

@property ---> func  将方法伪装成属性,只能看,不能对之操作。

@func.setter ---> func  对伪装的属性进行赋值的时候调用这个方法,一般情况用来修改属性。

@func.deleter ---> func  在执行del 对象.func的时候调用这个方法,一般情况用来删除属性,一般不用。

class Person:
    def __init__(self,name):
        self.__name = name   # 私有属性
    @property       # 将方法装饰成属性使用。  现在 p.name 相当于 p.name()
    def name(self):
        return self.__name
    @name.setter
    def name(self,new_name):
        if type(new_name) is str:       # 类型不对无法替换,防止乱改。
            self.__name = new_name  # 将new_name 赋值给 self.__name 这一步改变了值。
        else:
            print('类型不对,无法替换...')
    @name.deleter       
    def name(self):
        del self.__name     # 删除self.__name属性
p = Person('alex')
print(p.name)       # alex
p.name = 'alex_sb'
print(p.name)       # alex_sb
del p.name
print(p.name)  # 报错:AttributeError: 'Person' object has no attribute '_Person__name'

@classmethod : 类方法,可以直接被类调用,不需要默认传对象参数,只需要传一个类参数就行了。

# 全场改动折扣,不能单个改动。
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)        # 可以在实例化之前使用。
g = Goods('薯片',10)
print(g.price)

staticmethod:

  当一个方法要使用对象的属性时,就是使用普通的方法。

  当一个方法要使用类中的静态属性时,就是用类方法。

  当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用 staticmethod 静态方法。

class Student:
    def __init__(self,name):pass
    @staticmethod
    def login():    # login就是一个类中的静态方法,静态方法没有默认参数,就当成普通函数。
        pass

Student.login()

 

posted @ 2018-04-17 18:59  Qingqiu_Gu  阅读(165)  评论(0编辑  收藏  举报