Day 22 封装 property

【封装】

         隐藏对象的属性和实现细节,仅对外提供公共访问方式。

【好处】 

  1. 将变化隔离; 

  2. 便于使用;

  3. 提高复用性; 

  4. 提高安全性;

【封装原则】

      1. 将不需要对外提供的内容都隐藏起来;

      2. 把属性都隐藏,提供公共方法对其访问。

私有变量和私有方法

在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

# 私有的用途
# 当一个方法不想被子类继承的时候
# 有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用
# java中的对比
# public 公有的    在类的内部可以使用,子类可以使用,外部可以使用    python中所有正常的名字
# protect 保护的   在类的内部可以使用,子类可以使用,外部不可以使用  python中没有
# private 私有的   只能在类的内部使用,子类和外部都不可以使用        python中的__名字

# 描述一个房子
    #单价
    #面积
class Room:
    def __init__(self,name,price,length,width,height):
        self.name = name
        self.price = price
        self.__length = length
        self.__width = width
        self.height = height
    @property
    def area(self):
        return self.__length * self.__width
r = Room('peng',100,2,1,5)
print(r.name)
print(r.area)
# 一个私有的名字,在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到
# python对其的名字进行了修改:__类名__名字
# 只不过在类的外部调用:需要'_类名__名字'去使用
# 在类的内部可以正常的使用名字
class Person:
#     def __init__(self,name,pwd):
#         self.name = name
#         self.__pwd(pwd)
#     def __pwd(self,pwd):
#         # '12345' ---> ascii ---> 2175981070935
#         self.my_secret_pwd = 2175981070935

 

# _A__N
# 在类内 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字

# 私有的属性
class B:
    def __init__(self,name):
        self.__name = name
    def func(self):
        print('in func: %s'%self.__name)
b = B('alex')
print(b._B__name)
b.func()
# 私有的方法
class C:
    def __wahaha(self):
        print('wahaha')
    def ADca(self):
        self.__wahaha()

c= C()
c._C__wahaha()
c.ADca()

# 在类中,静态属性,方法,对象属性都可以变成私有的,只要在这些名字之前加上__
class D:
    def __func(self): #存储'_D__func'
        print('in func')

class E(D):
    def __init__(self):
        # self.__func()   报错
        self._D__func()  #'_E__func'

e = E()
》》》in func
#私有的名字不能被子类继承

class D:
    def __init__(self):
        self.__func() #_D__func
    def __func(self):
        print('in D')
class E(D):
    def __func(self):
        print('in E')

e = E()

》》》in D
class D:
    def __init__(self):
        self.__func() #_D__func
    def __func(self):
        print('in D')
class E(D):
    def _D__func(self):
        print('in E')

e = E()
>>>in E
# 私有的名字,在类内使用的时候,就是会变形成 _该类名__方法名
# 以此为例,没有双下划线会找到E中的func
# 但是有了双下划线,会在调用这个名字的类D 中直接找_D__func
class F:pass
F.__name = 'alex' #不是在创建私有属性,只有在类的内部才关心下划线操作,变形只在类的内部发生,不会在外部发生
print(F.__name)
print(F.__dict__)

alex
{'__dict__': <attribute '__dict__' of 'F' objects>, '__module__': '__main__', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'F' objects>, '__name': 'alex'}

class F:
    def ADCa(self):
        self.__name = 'alex'

f = F()
f.ADCa()
# print(f.__name) #报错
print(f._F__name) 真正工作的时候不可以这么写,只是为了应付面试

Property

 

例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86

class Person:
    def __init__(self,name,weight,height):
        self.name = name
        self.__weight =weight
        self.__height = height
    @property
    def BMI(self):
        return self.__weight /self.__height ** 2

kate = Person('kate',58,1.59)
print(round(kate.BMI))
print(round(kate.BMI))
print(Person.__dict__)
BMI': <property object at 0x102138958>,

 

BMI 是个名词
将一个方法伪装成一个属性
并不会让你的代码有什么逻辑上的提高
只是从调用者的角度上换了一种方式,使它看起来更合理
有了property装饰,bmi不能重名,也不能重新赋值,否则会报错,说白了就是只能看了,不能修改

@property能够将一个方法伪装成一个属性
从原来的对象名.方法名()变成了对象名.方法名
只是让代码变得更美观,并不会起到改变逻辑的作用
被property装饰的bmi仍然是一个方法 存在Person.__dict__
对象的__dict__ 中不会存储这个属性
在一个类加载的过程中,会先加载这个中的名字,包括被property装饰
在实例化对象的时候,python解释器会先到类的空间里看看有咩有这个被装饰的属性
如果有就不能再在自己的空间中创建这个属性了

# 将方法伪装成属性,方法中一般设计的就是一些计算过程
from math import pi
class Circle:
    def __init__(self,r):
        self.r = r

    @property
    def area(self):
        return pi * self.r**2

    @property
    def perimeter(self):
        return pi * 2* self.r

p = Circle(10)
print(round(p.area))
print(round(p.perimeter))
# 这样不能随意改姓名name,并且通过setname约束
class Person:
    def __init__(self,name):
        self.__name = name #私有的属性
    @property
    def name(self):
        return self.__name
    def set_name(self,newname):
        if type(newname) is str:
            self.__name = newname
        else:
            print('您输入的姓名数据类型不合法')

p = Person('alex')
p.set_name('alex_sb')
# p.set_name(123) 报错
print(p.name)
# 方法伪装成的属性的修改
class Person:
    def __init__(self,name):
        self.__name = name #私有的属性

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,newname):
        if type(newname) is str:
            print(newname)
        else:
            print('数据类型错误')

p = Person('alex')
print(p.name) #def name(self)
p.name = 'SBBBBBB' #def name(self,newname):
print(p.name) #def name(self)
p.name  = 123
print(p.name)
#三个name必须一致

alex
SBBBBBB
alex

数据类型错误


#方法伪装成属性的删除
class Person:
    def __init__(self,name):
        self.__name = name

    @property
    def name(self):
        return self.__name
    @name.deleter
    def name(self):
        print('name 被删除')

    # @name.deleter
    # def name(self):
    #     del self.__name #这个可以真正删除

p = Person('egon')
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,price,discount):
        self.name = name
        self.__price = 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
        else:
            print('您输入的数据类型错误')

apple = Goods('apple',5,0.8)
print(apple.price)
#  修改苹果价格
apple.price = 8
print(apple.price)
店庆全场八折# 折扣结束 折扣变了 恢复折扣
class Product:
    __discount = 0.8
    def __init__(self,name,price):
        self.name = name
        self.__price = price

    @property
    def price(self):
        return self.__price * Product.__discount

    @classmethod #不依赖对象的方法,就应该定义为类方法,类方法可以任意的操作类中的静态变量
    def change_discount(cls,new_discount): # 类方法,可以直接被类调用,不需要默认传对象参数,只需要传一个类参数就可以了
        cls.__discount = new_discount

Product.change_discount(1)
apple = Product('apple',5)
banana = Product('banana',8)
print(apple.price)
print(banana.price)
#使用什么样的方法要看具体用到了哪些名称空间中的值
# 当一个方法要使用对象的属性时,就使用普通的方法
# 当一个方法要使用类中的静态属性时,就使用类方法
# 当一个方法既不使用对象的属性也不使用类中的静态属性时,就可以使用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)

 

class A:
    __role = 'CHINA'
    @classmethod
    def show_role(cls):
        print(cls.__role)

    @staticmethod
    def get_role():
        return A.__role

    @property
    def role(self):
        return self.__role

a = A()
print(a.role)
print(a.get_role())
a.show_role()

CHINA
CHINA
CHINA

 





 

posted on 2018-04-17 16:43  欣蔚  阅读(167)  评论(0编辑  收藏  举报