面向对象的三大特性

  • 封装

  • 多态

  • 继承

封装 

   广义的封装 : 把方法和属性都封装在一个类里,定义一个规范来描述一类事物.
   狭义的封装 : 私有化 只能在类的内部访问
  __静态变量,私有方法 ,私有的对象属性,私有的类方法,私有的静态方法
  在内存中存储 _类名__名字
  为什么在类的内部可以使用双下划线访问 : 在类的内部使用,你就知道你在哪个类中
  在子类中可以访问访问父类的私有变量么?不行
  私有 : 不能在类的外部使用也不能被继承

私有变量和私有方法

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

私有变量

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

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是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

这种自动变形的特点:

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 Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area


#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()

property属性

装饰器函数,内置函数,帮助你将类中的方法伪装成属性,特性

调用方法的时候不需要主动加括号
让程序的逻辑性更合理
@方法名.setter 装饰器,修改被property装饰的属性的时候会调用被这个装饰器装饰的方法,除了self之外还有一个参数,被修改的值
@方法名.deleter 装饰器,当要删除被property装饰的属性的时候会调用被这个装饰器装饰的方法

# class Circle:
#     def __init__(self,r):
#         self.r = r
#         # self.area = 3.14*self.r**2
#
#     @property
#     def area(self):   #  这个方法计算结果本身就是是一个属性,但是这个属性会随着这个类/对象的一些基础变量的变化而变化
#         return 3.14*self.r**2

# c = Circle(5)
# print(c.area)
# c.r = 10
# print(c.area)

# 偏其他语言 property+私有的 合用 ,这个时候更多的也会用到setter和deleter
# class A:
#     def __init__(self,name):
#         self.__name = name
#
#     @property
#     def name(self):
#         return self.__name
#
#     @name.setter
#     def name(self,new_name):
#         if type(new_name) is str:
#             self.__name = new_name
#
#     @name.deleter
#     def name(self):
#         del self.__name
# a = A('alex')
# a.name = 123
# print(a.name)
# del a.name   # 语法
# print(a.name)

 classmethod

类方法的装饰器 内置函数
使用类名调用,默认传类名作为第一个参数
不用对象命名空间中的内容,而用到了类命名空间中的变量(静态属性),或者类方法或静态方法

# class Goods:
#     __discount = 0.8
#     def __init__(self,price):
#         self.__price = price
#     @property
#     def price(self):
#         return self.__price * Goods.__discount
#     @classmethod
#     def change_discount(cls,num):
#         cls.__discount = num
#
# # 商场的程序
# apple = Goods(10)
# banana = Goods(15)
# print(apple.price,banana.price)
# Goods.change_discount(1)
# print(apple.price,banana.price)

staticmethod

静态方法的装饰器 内置函数

如果一个类里面的方法 既不需要用到self中的资源,也不用cls中的资源.

相当于一个普通的函数
但是你由于某种原因,还要把这个方法放在类中,这个时候,就将这个方法变成一个静态方法
某种原因:
你完全想用面向对象编程 ,所有的函数都必须写到类里
某个功能确确实实是这个类的方法,但是确确实实没有用到和这个类有关系的资源

# 学生 管理员
# 课程 班级
# class Person:
#     @staticmethod
#     def login():  # 动词 动作 属于某一个对象
#         pass
# class Student(Person):pass
# class Manager(Person):pass
# class Course:pass
# class Classes:pass
幻想毫无价值,计划渺如尘埃,目标不可能达到。这一切的一切毫无意义——除非我们付诸行动。
原文地址:https://www.cnblogs.com/TodayWind/p/13916682.html