面向对象三大特性之多态、封装与装饰器

一、多态

什么是多态:Animal类表现出Dog,Cat两种形态

# class Animal:pass
# class Dog(Animal):pass
# class Cat(Animal):pass

什么是多态:

  一个类表现出来的多种形态:通过继承来实现

  在Java中的表现:在一个函数中需要给参数指定数据类型,如果这个地方可以接收两个以上的参数,那么这些类型应该有一个父类,这个父类是所有子类对象的类型。

# def func(Cat mao):pass
# def func(Dog gou):pass
# def func(Animal gou|mao):pass

  在python中,:函数的参数不需要指定数据类型,所以我们也不需要通过继承的形式统一一组类的类型。换句话说,所有的对象其实都是object类型,所以在python当中其实处处都是多态。

# def func(a):
#     a既可以传猫也可以传狗类型,随便传任意类型

 

二、鸭子类型

鸭子类型
len() # str list tuple dict set 容器类型 range 所有的迭代器
index() # str list tuple
print() # 所有对象都是鸭子类型
不是明确的通过继承实现的多态
而是通过一个模糊的概念来判断这个函数能不能接收这个类型的参数

三、封装

1. 广义上的封装:

class 类名:

  def 方法(self):pass

  

是为了只有这个类的对象才能使用定义在类中的方法

2. 狭义上的封装

把一个名字藏在类中

# class Goods:
#     __discount = 0 # 私有的静态变量
#     print(__discount)

# print(Goods.__discount) # 在类的外部不能引用私有的静态变量

  

  类中的静态变量和方法名在程序加载过程中就已经执行完了,不需要等待调用。

  在这个类加载完成之前,Goods这个名字还没有出现在内存空间中

  私有的静态属性可以在类的内部使用,用来隐藏某个变量的值。

变形:

# class Goods:
#     __discount = 0 # 私有的静态变量
    # 变形: _类名__私有变量
# print(Goods.__dict__)
# print(Goods._Goods__dicount) # 编程规范的角度上出发,我们不能在类的外部使用私有的变量。

  

 1 # 私有方法能调用,但是不能修改
 2 # class Student:
 3 #     def __init__(self, name, age):
 4 #         self.__name = name
 5 #         self.age2 = age
 6 #
 7 #     def name(self):
 8 #         return self.__name
 9 #
10 # obj1 = Student('alex', 44)
11 # print(obj1.name())
12 # print(obj1.age2)
13 # print(obj1.name)
14 # obj1.age2 = 88
15 # print(obj1.age2)
16 # obj1.name = 'egon'
17 # # print(obj1.name()) # 出错
18 # print(obj1.name)
19 # obj1.__name = 'taibai'
20 # print(obj1.name)
私有方法

类中的私有成员有:

  • 私有的静态变量
  • 私有的对象属性
  • 私有的方法

对象属性:

# class Student:
#     def __init__(self, name):
#         pass

  

为什么要定义一个私有变量?

  • 不想让你看到这个值
  • 不想让你修改这个值
  • 想让你在修改这个值的时候有一些限制
  • 有些方法或者属性不能被子类继承

私有变量能不能在外部被定义?不能

# class A :
#     __country = 'China'  # 在类的内部会发生变形
#     print(__country)      # '_A__country'
# print(A.__dict__)
# A.__Language = 'Chinese'
# print(A.__dict__)

  

私有变量能不能被继承?不能

class A:
    __country = 'China'
    def __init__(self,name):
        self.__name = name  # '_A__name'

class B(A):
    # print(__country)
    # NameError: name '_B__country' is not defined
    def get_name(self):
        return self.__name  # '_B__name'
b = B('alex')
a = A('alex')
print(b.get_name())
# print(b.__dict__)

  

 四、装饰器

1.property

property是一个装饰器函数。

  所有的装饰器函数都怎么用?在函数、方法、类的上面一行直接@装饰器的名字

装饰器的分类:

  • 装饰函数
  • 装饰方法:property
  • 装饰类
# class Student:
#     def __init__(self,name,age):
#         self.__name = name
#         self.age = age
#     @property   # 将一个方法伪装成一个属性
#     def name(self):
#         return self.__name
# zhuge = Student('诸葛',20)
# print(zhuge.name)

  

 1 # from math import pi
 2 # class Circle:
 3 #     def __init__(self,r):
 4 #         self.r = r
 5 #     @property
 6 #     def area(self):
 7 #         return self.r ** 2 * pi
 8 #     @property
 9 #     def perimeter(self):
10 #         return 2 * self.r * pi
11 #
12 # c1 = Circle(10)
13 # print(c1.area)
14 # print(c1.perimeter)
15 # c1.r = 5
16 # print(c1.area)
17 # print(c1.perimeter)
18 
19 利用装饰器求圆的周长和面积
利用装饰器求圆的周长和面积

 2.setter

只有当被property装饰的方法
又实现了一个同名方法
且被setter装饰器装饰了
且 在 对被装饰的方法 赋值的时候 就出发被setter装饰器装饰的方法

# class Student:
#     def __init__(self, name):
#         self.__name = name
#
#     @property
#     def name(self):
#         return self.__name
#
#     @name.setter
#     def name(self, new):
#         if type(new) is str:
#             self.__name = new
#
#
# obj = Student('alex')
# print(obj.name)
# obj.name = 'egon'
# print(obj.name)

   

  一个方法被伪装成属性之后,应该可以执行一个属性的增删改查操作。

那么增加和修改 就对应这被setter装饰的方法 :这个方法又一个必传的参数new,表示赋值的时候等号后面的值,
删除一个属性 对应着 被deleter装饰的方法,这个方法并不能在执行的时候真的删除这个属性,
而是你在代码中执行什么就有什么效果

3.@classmethod

# class Goods:
#     __discount = 0.8           # 静态属性
#     def __init__(self,price):
#         self.__price = price   #  对象属性
#         self.name = 'apple'
#
#     @property
#     def price(self):
#         print(self)
#         return self.__price * Goods.__discount
#
#     @classmethod
#     def change_discount(cls,new):       # 类方法
#         cls.__discount = new
#
#
#
# Goods.change_discount(0.7)
# print(Goods.__dict__)
#
#
#
#
# apple = Goods(10)
# banana = Goods(20)
# apple.change_discount(0.7)
# print(apple.price)
# print(Goods)
# print(banana.price)

 

类:

  静态属性: 类  所有的对象都统一拥有的属性

  类方法: 类  如果这个方法涉及到操作静态属性、类方法、静态方法    cls表示类

  静态方法: 类  普通方法,不使用类中的命名空间也不使用对象的命名空间   一个普通的函数, 没有默认参数

  方法:  对象    self表示对象

  property方法  对象

4.isinstance

检测对象与类的关系

print(type(123) is int)
print(isinstance(123, int))  # 判断类型, 可以继承

class A:
    pass
class B(A):
    pass


a = A()
b = B()

print(type(a) is A)
print(type(b) is A)     # False
print(type(b) is B)

print(isinstance(a, A))
print(isinstance(b, A))  # 继承
print(isinstance(a, B))     # False

  

5.issubclass

检测类与类之间的关系

class A:
    pass
class B(A):
    pass

print(issubclass(A, B)) # 父类在前False
print(issubclass(B, A))  # True

  

 

原文地址:https://www.cnblogs.com/eaoo/p/9556741.html