面向对象 封装 property setter classmethod staticmethod

【封装】

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

【好处】 

1. 将变化隔离; 

2. 便于使用;

3. 提高复用性; 

4. 提高安全性;

【封装原则】

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

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

私有变量和私有方法

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

私有变量

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
View Code

这种自动变形的特点:

1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果

2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

 

这种变形需要注意的问题是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形

私有方法

3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B
 

#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__

# 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()
#     def __func(self):
#         print('in D')
#
# class E(D):
#     def __func(self):
#         print('in E')
# e = E()
View Code

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

# class F:
#     pass
# F.__name = 'alex'  # 不是在创建私有属性
# print(F.__name)
# print(F.__dict__)
# 变形只在类的内部发生

# class F:
#     def ADCa(self):
#         self.__name = 'alex'   # _F__name
#
# f = F()
# f.ADCa()
# print(f._F__name)

# java中的对比
# public 公有的    在类的内部可以使用,子类可以使用,外部可以使用    python中所有正常的名字
# protect 保护的   在类的内部可以使用,子类可以使用,外部不可以使用  python中没有
# private 私有的   只能在类的内部使用,子类和外部都不可以使用        python中的__名字

# 私有的用法
# 当一个方法不想被子类继承的时候
# 有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用

 

人体BMI指数
体质指数(BMI)=体重(kg)÷身高^2(m)
 写一个类 描述人体BMI指数

property setter

lass Person:
    def __init__(self,name,weight,height):
        self.name = name
        self.__height = height
        self.__weight = weight
        # self.bmi = self.__weight / self.__height ** 2
        # self.bmi = self.cal_BMI()

    def cal_BMI(self):
        return self.__weight / self.__height ** 2

    @property
    def bmi(self):
        return self.__weight / self.__height ** 2
p = Person('大表哥',92,1.85)
# print(p.cal_BMI())
# p.cal_BMI()   # bmi是一个名词
# print(p.bmi)   # bmi是一个名词
# p._Person__weight = 90
# print(p.bmi)
# 将一个方法伪装成一个属性
    # 并不会让你的代码有什么逻辑上的提高
    # 只是从调用者的角度上换了一种方式,使之看起来更合理

# 单纯的在init中计算
# class Person:
#     def __init__(self,name,weight,height):
#         self.name = name
#         self.__height = height
#         self.__weight = weight
#         self.bmi = self.__weight / self.__height ** 2
#
# p = Person('大表哥',92,1.85)   #
# print(p.bmi)   # bmi是一个名词
# p._Person__weight = 90   # 3天
# print(p.bmi)

# 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
#
# p = Person('大表哥',92,1.85)
# print(p.bmi)
# p._Person__weight = 90
# print(p.bmi)

# @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('大表哥',92,1.85)
# print(p.__dict__)
# print(p.bmi)   # 对这个属性 只能看了

# 被property装饰的bmi仍然是一个方法 存在Person.__dict__
# 对象的.__dict__中不会存储这个属性

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

# 圆形类
# 半径 面积 周长
# from math import pi
# class Circle:
#     def __init__(self,r):
#         self.r = r
#     def cal_area(self):
#         return self.r**2*pi
#     def cal_perimeter(self):
#         return 2*pi*self.r
# c = Circle(10)
# print(c.cal_area())
# print(c.cal_perimeter())

# 将方法伪装成属性,方法中一般涉及的都是一些计算过程
# from math import pi
# class Circle:
#     def __init__(self,r):
#         self.r = r
#     @property
#     def area(self):
#         return self.r**2*pi
#
#     @property
#     def perimeter(self):
#         return 2*pi*self.r
# c = Circle(10)
# print(c.area)
# print(c.perimeter)
# c.r = 15
# print(c.area)
# print(c.perimeter)

# __name setter deleter
# class Person0:
#     def __init__(self,name):
#         self.name = name
#
# p = Person0('alex')
# print(p.name)
# p.name = 'sb'
# p.name = 123

# class Person:
#     def __init__(self,name):
#         self.__name = name  # 私有的属性了
#     @property
#     def name(self):
#         return self.__name
#
#     def set_name(self,new_name):
#         if type(new_name) is str:
#             self.__name = new_name
#         else:
#             print('您提供的姓名数据类型不合法')
#
# p = Person('alex')
# print(p.name)
# # 和直接定义name属性有什么区别???
# p.set_name('alex_sb')
# print(p.name)
# p.set_name(123)
# print(p.name)


# 方法伪装成的属性的修改
# class Person:
#     def __init__(self,n):
#         self.__name = n  # 私有的属性了
#     @property
#     def name(self):
#         return self.__name
#
#     @name.setter        # 重要程度 ***
#     def name(self,new_name):
#         if type(new_name) is str:
#             self.__name = new_name
#         else:
#             print('您提供的姓名数据类型不合法')
#
# p = Person('alex')
# print(p.name)       #def name(self):
# p.name = 'alex_sb' #def name(self,new_name):
# print(p.name)       #def name(self):
# p.name = 123 #def name(self,new_name):
# print(p.name)       #def name(self):

# 方法伪装成的属性的删除
class Person:
    def __init__(self,n):
        self.__name = n  # 私有的属性了
    @property            # 重要程度 ****
    def name(self):
        return self.__name
    # @name.deleter
    # def name(self):
    #     print('name 被删除了')
    # @name.deleter         # 重要程度*
    # def name(self):
    #     del self.__name

# p = Person('alex')
# 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,origin_price,discount):
#         self.name = name
#         self.__price = origin_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
# apple = Goods('apple',5,0.8)
# print(apple.price)
# # 修改苹果的原价
# apple.price = 8
# print(apple.price)


# 将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
# 将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性

 

 

 classmethod  staticmethod

店庆 全场八折

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)  # 不依赖对象的方法 就应该定义成类方法 类方法可以任意的操作类中的静态变量
apple = Goods('apple',5)
banana = Goods('banana',8)
print(apple.price)
print(banana.price)

# 折扣变了 店庆结束 恢复折扣
# apple.change_discount(1)   # 如果要改变折扣 是全场的事情 不牵扯到一个具体的物品 所以不应该使用对象来调用这个方法
# print(apple.price)
# print(banana.price)


# staticmethod
# 当一个方法要使用对象的属性时 就是用普通的方法
# 当一个方法要使用类中的静态属性时 就是用类方法
# 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用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)

 完全面向对象编程
 先登录 后 实例化
还没有一个具体的对象的时候 就要执行login方法

 使用什么样的方法要看具体用到了哪些名称空间中的变量
当一个方法要使用对象的属性时 就是用普通的方法
 当一个方法要使用类中的静态属性时 就是用类方法
 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法

posted @ 2018-04-17 16:06  笨?狐狸  阅读(141)  评论(0编辑  收藏  举报