封装、多态、类的约束、类的私有成员

# 面向对象的三大特性
# 封装:将一些重要的数据和信息放到一个空间,比如函数
# 面向对象:

class A:
    country = "China"  # 静态属性也是一种封装
    area = "深圳"

    def __init__(self, name, age):  # 这也是封装
        self.name = name
        self.age = age

a1 = A("小明", 22)
a2 = A("小花", 18)
print(a1.__dict__)  # 对象属性的封装
print(a1.name)  # 通过万能的 . 来调用
# 多态
# 一种事物有多种形态,比如水
# Python默认支持多态
# 鸭子类型
# 看着像鸭子,就是鸭子
# Python中约定俗成制定一些保持一致性的行为规范

class A:
    def func1(self):
        print("in A func1")

    def func2(self):
        print("in A func2")

class B:
    def func1(self):
        print("in B func1")

    def func2(self):
        print("in B func2")

# 将A类B类里面相似的一些功能命名成相同的名字,隐约制定一些标准
obj1 = A()
obj1.func1()
obj2 = B()
obj2.func1()

# 源码:
# str index
class Str_:
    def index(self):
        print("根据元素找索引")

class List_:
    def index(self):
        print("根据元素找索引")

class Tuple_:
    def index(self):
        print("根据元素找索引")

# 这三个类中都有 index,都是指索引,这样更加规范化
# 这三个类即互为鸭子
# 类的约束
# 目的是对类进行一些正确引导,约束,统一规范,满足正确的开发方式

class Alipay:

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay:

    def pay(self, money):
        print("此次消费%s元" % money)

a = Alipay()
a.pay(100)  # 此次消费100元

q = QQpay()
q.pay(200)  # 此次消费200元
# 统一支付功能

class Alipay:

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay:

    def pay(self, money):
        print("此次消费%s元" % money)

def pay(obj, money):  # 设计一个接口
    obj.pay(money)

a = Alipay()
a1 = Alipay()
q = QQpay()
pay(a, 100)
pay(q, 100)
pay(a1, 300)
# 假设要添加一个微信支付

class Alipay:

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay:

    def pay(self, money):
        print("此次消费%s元" % money)

class Wechat:
    def fuqian(self, money):  # 不规范
        print("此次消费%s元" % money)

def pay(obj, money):  # 这是一个隐藏的标准
    obj.pay(money)

c = Wechat()
c.fuqian(300)
# 制定一个约束或标准
# 如果有父类,父类的方法只有一个pass
# 其实就是制定了一个规范,表明子类一定要有pay()方法

class A:

    def pay(self, money):
        pass

class Alipay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class Wechatpay(A):

    def pay(self, money):  # 不规范
        print("此次消费%s元" % money)

def pay(obj, money):  # 这是一个隐藏的标准
    obj.pay(money)

c = Wechatpay()
c.pay(300)
# 在之前基础上
class A:

    def pay(self, money):
        pass

class Alipay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class Wechatpay(A):

    def pay(self, money):  # 不规范
        print("此次消费%s元" % money)

class Unitypay(A):

    def zhifu(self, money):
        print("此次消费%s" % money)

def pay(obj, money):  # 这是一个隐藏的标准
    obj.pay(money)

u1 = Unitypay()
pay(u1, 100)

# 虽然没有这个方法,但是也没有报错,因为父类中有 pay()
# 侧面说明 A类不是强制性约束,为了起到决定性的作用,可以强制加一个约束
# 只要不按规则走就直接报错
# 两种解决方法:
# 1. 在父类写一个相同的方法,此方法主动抛出一个错误, 提示应该在子类写这个方法

class A:

    def pay(self, money):  # 如果子类没有定义这个方法,使用了父类的就报错
        raise Exception("未定义pay方法")

class Alipay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class Wechatpay(A):

    def pay(self, money):  # 不规范
        print("此次消费%s元" % money)

class Unitypay(A):

    def zhifu(self, money):
        print("此次消费%s" % money)

def pay(obj, money):  # 这是一个隐藏的标准
    obj.pay(money)


u1 = Unitypay()
pay(u1, 100)
#  File "G:/.../123asda.py", line 203, in pay
#     raise Exception("未定义pay方法")
# Exception: 未定义pay方法
# 解决方法二:
# 在父类引用元类的抽象方法

from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):
    """
    抽象类,接口类,制定一个规范,强制执行
    """

    @abstractmethod
    def pay(self, money):
        pass

class Alipay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class QQpay(A):

    def pay(self, money):
        print("此次消费%s元" % money)

class Wechatpay(A):

    def pay(self, money):  # 不规范
        print("此次消费%s元" % money)

class Unitypay(A):

    def zhifu(self, money):
        print("此次消费%s" % money)

def pay(obj, money):  # 这是一个隐藏的标准
    obj.pay(money)

u1 = Unitypay()
pay(u1, 100)
# Traceback (most recent call last):
#   File "G:/.../123asda.py", line 274, in <module>
#     u1 = Unitypay()
# TypeError: Can't instantiate abstract class Unitypay with abstract methods pay
总结
约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:

1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c,所以使⽤频率还是很少的

2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError
这样比较专业, ⽽且错误比较明确.(推荐)
# 类的私有成员

# Python的结构分析
# 类的结构
# 分为属性和方法

# 按照公有,私有对类进行划分
# 私有分为三部分;

class Boss:
    name = "alex"  # 公有静态属性 公有静态字段
    __secretary = ["女1", "男2", "眼膜"]  # 私有普通字段

    def __init__(self, username, password):
        self.username = username  # 公有对象属性 公有普通字段
        self.__password = password  # 私有对象属性

    def func(self):
        # print(self.__secretary)
        self.__func()

    def __func(self):  # 私有方法
        print("经常做一些不可描述的事")

class Boss_son(Boss):

    def func(self):
        print(self.__secretary)

# 私有成员:私有静态属性,私有对象属性,私有方法

# 私有静态属性
# 访问它有三个方法:
#   1.类外部 Boss.name b1.name
print(Boss.name)  # alex
print(Boss.__secretary)  # 不能访问,报错

#   2.类内部 func()访问
b1 = Boss("alex", 123)  #
b1.func()  # ['女1', '男2', '眼膜']

#   3.子类
b2 = Boss_son("other", 123)
b2.func()
# 报错

b3 = Boss("abc", 123)
b3.__func() # 报错
b3.func() # 经常做一些不可描述的事
print(b3.__password) # 报错
b4 = Boss_son("asd", 123)
print(b4.__password) # 报错
# 因此私有方法只能在类内部访问,外部和派生类都不能
# 然而
class Boss:
    name = "alex"
    __secretary = ["女1", "男2", "眼膜"]

    def __init__(self, username, password):
        self.username = username
        self.__password = password

    def func(self):
        self.__func()

    def __func(self):
        print("经常做一些不可描述的事")

b1 = Boss("asd", 1234)

print(Boss.__dict__)
# {'__module__': '__main__', 'name': 'alex',
# '_Boss__secretary': ['女1', '男2', '眼膜'],
# '__init__': <function Boss.__init__ at 0x000001BA3EA7AC80>,
# 'func': <function Boss.func at 0x000001BA3EA7AD90>,
# '_Boss__func': <function Boss.__func at 0x000001BA3EA7AD08>,
# '__dict__': <attribute '__dict__' of 'Boss' objects>,
# '__weakref__': <attribute '__weakref__' of 'Boss' objects>, '__doc__': None}

# print(Boss._Boss__secretary)
# 私有成员虽然可以在类外部或者派生类可以访问,但是不要这样做
# 类的方法
class A:
    name = "barry"

    def __init__(self, a, b):  # 双下方法
        self.a = a
        self.b = b

    def func(self):  # 实例方法——可通过实例化对象调用的方法,普通方法
        pass

    @staticmethod  # 静态方法,跟类和实例化对象没关系
    def func1():
        print(666)

    @classmethod  # 类方法
    def func2(cls):
        print(777)

    @property     # 将一个方法伪装成属性
    def bim(self):
        print(888)
# 类方法
# 类方法是通过类名直接调用的方法,类方法至少要有一个参数,第一个默认是cls

class A:
    name = "barry"

    def func(self):  # 实例方法——可通过实例化对象调用的方法,普通方法
        pass

    @classmethod  # 类方法
    def func2(cls):
        print(cls)
        print(777)

a = A()  # <class '__main__.A'>
# print(a)
# a.func()
print(A)  # <class '__main__.A'>
A.func2()  # 777

# 对象可以调用类方法,但是 cls 接收的不是对象的空间,而是类的空间
a.func2()
# <class '__main__.A'>
# 777
# 类方法在哪使用?
# 对类中的属性方法直接操作,与对象无关,这时需要使用类方法
# 原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法
# 且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。
# 另外,如果需要继承,也可以定义为类方法。
# 如下场景:
# 假设我有一个学生类和一个班级类,想要实现的功能为:
#     执行班级人数增加的操作、获得班级的总人数;
#     学生类继承自班级类,每实例化一个学生,班级人数都能增加;
#     最后,我想定义一些学生,获得班级中的总人数。
#
# 思考:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,
# 但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。
# 同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。

class ClassTest(object):
    __num = 0

    @classmethod
    def addNum(cls):
        cls.__num += 1

    @classmethod
    def getNum(cls):
        return cls.__num

    # 这里我用到魔术函数__new__,主要是为了在创建实例的时候调用人数累加的函数。
    def __new__(self):
        ClassTest.addNum()
        return super(ClassTest, self).__new__(self)

class Student(ClassTest):
    def __init__(self):
        self.name = ''

a = Student()
b = Student()
print(ClassTest.getNum())
# 静态方法
# 相似功能,保持一致性,而类本来就是一种功能的划分
# 静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,
# 逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,
# 不会涉及到类中的属性和方法的操作。可以理解为,
# 静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。

class A:

    name = "barry"

    @staticmethod
    def func():
        print(666)

a1 = A
A.func()  # 666
a1.func()  # 666
import time

class TimeTest(object):
    def __init__(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    @staticmethod
    def showTime():
        return time.strftime("%H:%M:%S", time.localtime())


print(TimeTest.showTime())  # 12:23:37
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime)  # 12:23:37

猜你喜欢

转载自www.cnblogs.com/shawnhuang/p/10282265.html