黑马python入门(5):Python基础(面向对象相关)

非常优秀的面向对象教程(非常推荐) https://www.cnblogs.com/Eva-J/articles/7293890.html


面向对面

一切皆为对象


面向过程 面向对象的个人理解

搬家具到屋子为例

面向过程分析这个事  把事情分成几步 从上到下按照流程走下去自然就完成了  这个也是我们常见的逻辑思维思路

1。人去搬动家具 2 移动到屋子 3 重复 1 2步若干次 4 所有家具都搬进去了或者屋子满了为止 5流程结束

面向对象分析这事 首先分析 办这个事的主体都有谁 然后这个事 需要这几个对象都有什么特点 然后就是这些对象的特点怎么样交互才能完成这事

对象

1 人对象 2 家具对象 3 屋子对象

要办这事这些对象之间需要什么特点:

1 人对象需要有搬动这个功能 2 家居对象 需要有个占地面积的功能还有家具编号 3 屋子对面需要有总面积 剩余面积的特点

交互来完成目标(利用这几个对象和对象自身的特点来进行交互以达到目标):

人这个对象的搬动操作  搬动目标是家具对象n  搬动到的地方是屋子对象 判断完成条件是 所有家具都搬动过了 或者 屋子对面的剩余面具属性小于等于0 其实交互也可以部分看作是按照流程 面向过程


类与对象

类就是汽车图纸  这个类的对象 就是按照这图纸制造的一辆一辆的汽车


定义类

class TestClassObject(object):
    """
    展示下新类的常见结构
    """
    name = "TestClassObject.name"  # 类属性 name 可以在该类的所有实例下调用 但是只能通过类名.类属性进行修改 不能类实例.类属性进行修改
    fun = "测试用类"  # 类属性 fun

    def __init__(self, a, b, c):  # 固定的类初始化函数 在类实例化的时候自动隐式调用 该类方法内也是统一声明类实例属性的地方
        self.a = a  # 类实例属性 a
        self.b = b  # 类实例属性 b
        self.c = c  # 类实例属性 c

    def test1(self):  # 类实例方法 第一个参数是self 但是调用类实例方法第一个参数不用写
        print(self.a + self.b)

    @classmethod
    def test2(cls):  # 这是类方法 第一个参数代指类本身 可以在这个类方法里面调用类属性 其他类方法来运算
        print(cls.name)


    @staticmethod
    def test4():  # 这是静态方法 注意这个静态方法不能有 类的属性方法 或者 类实例的属性和方法在 看做是一个普通的函数即可
        print("这里是静态方法")



Python __init__()类构造方法

1.每次创建对应实例就会自动隐式调用__init__()

2 第一个参数必然是self  类方法的参数self代表的是类实例本身  注意不是类本身 类本身用cls来代表

3 普通的类实例属性一般都在init里面声明  也是规范的类实例化赋初值的地方

4 类属性和类实例属性

(1)类属性和类实例属性的区分:  定义在类方法外 但是依然在类内声明的就是类属性 类实例属性是定义在类方法里面并且以self.变量名声明和使用的的都是类实例属性 还有一种是在类方法中声明 但是只是以 变量名 = 值 的形式的只是一个单纯的局部变量 一般而言统一规范 类实例属性都在init方法里面声明初值

(2)修改类属性:类属性是在该类下的所有实例都共享该类属性  都可以通过类实例.类属性名 获取到类属性的内容 但是 无法通过类实例.类属性名 = 新值 来修改类属性的内容  修改类属性 还是要以 类名.类属性 =  新值 来修改

(3)修改类实例属性: 自然是 类实例.类实例属性 = 新值 



类实例 或者类对象的创建

类的实例化

实例名1 = 类名(初始化的参数1,初始化的参数2,初始化的参数3,…)


类实例的使用

实例名1.类实例属性

实例名1.类实例方法(参数)


类实例属性的添加和删除

添加:直接在代码中写 实例名1.新属性名 = 值 就好  不过这种写法太随意了 不太规范 还是在类内提前声明好就是 也方便管理代码

删除:del(实例名1.新属性名)


类方法 类实例方法 静态方法


类方法

1.第一个参数必须是cls 类方法可以使用类属性和其他类方法 但是不能使用 类实例属性和方法 因为cls代指类本身  而不是类实例

2. 调用 类名.类方法()   

3  类方法定义的时候开头加上@classmethod

类实例方法

1.第一个参数必须是self 类实例方法可以使用 类实例属性和类实例方法 但是切不可以使用 类属性类方法

2 调用  类实例名.类实例方法() 还有一种未绑定方法  类名.类实例方法(实例名,参数1,参数2….)

静态方法

1.参数不能包含cls self 方法内不能调用 类属性类方法 类实例属性 类实例方法 可以理解为一个在类内的普通函数

2 调用  类名.静态方法()     类实例名.静态方法()

3 类方法定义的时候开头加上@staticmethod

class TestClassObject(object):
    """
    展示下新类的常见结构
    """
    name = "TestClassObject.name"  # 类属性 name 可以在该类的所有实例下调用 但是只能通过类名.类属性进行修改 不能类实例.类属性进行修改
    fun = "测试用类"  # 类属性 fun

    def __init__(self, a, b, c):  # 固定的类初始化函数 在类实例化的时候自动隐式调用 该类方法内也是统一声明类实例属性的地方
        self.a = a  # 类实例属性 a
        self.b = b  # 类实例属性 b
        self.c = c  # 类实例属性 c

    def test1(self):  # 类实例方法 第一个参数是self 但是调用类实例方法第一个参数不用写
        print(self.a + self.b)

    @classmethod
    def test2(cls):  # 这是类方法 第一个参数代指类本身 可以在这个类方法里面调用类属性 其他类方法来运算
        print(cls.name)


    @staticmethod
    def test3():  # 这是静态方法 注意这个静态方法不能有 类的属性方法 或者 类实例的属性和方法在 看做是一个普通的函数即可
        print("这里是静态方法")


# 调用类属性 类方法:  类名.类属性 类名.类方法()  不推荐 类实例名.类属性 类实例名.类方法()
print("类属性为:{}".format(TestClassObject.name))
# 类方法
TestClassObject.test2()
# 实例属性
print("类实例属性为:{}".format(test_class_object.a))
# 类实例方法
 test_class_object.test1()
 # 类静态方法 类名.静态方法()  类实例名.静态方法() 都可以
TestClassObject.test3()
test_class_object.test3()


封装

Python下 没有public 和 protected private 

1.public :默认情况下  类属性 类方法  类实例属性 类实例方法 静态方法 都是public  public下 类内可用 类外 和子类中都可以直接使用

2 protected:属性方法前加 _ 就是protected 能在本类和子类中使用 但是类外直接访问

3.private :属性方法 名字前加上 __则表示为private  只能在本类中使用 在类外或者子类中都无法使

4.__doc__  __init__  __new__之类的固定的类方法 不是私有 只是固定的写法

5.封装函数property() 用于给私有属性提供进一步的封装控制 

私有属性=property(读取该私有属性触发的类方法,[修改该私有属性触发的类方法],[del该私有属性触发的类方法],【读取该私有属性__doc__触发的类方法],)

这4个参数不是都必须写的 可以写一个 可以写2个 3个 4个 分别用来控制 外界或者子类访问私有属性触发的函数  比如我们只要让他有只读权限 就只设置第一个参数 其他不管即可

6.如果知道了 类名 和私有属性或者私有方法真正的名 我们可以用 实例名._类名私有属性名 的方式直接访问修改 私有属性 比如下面的testaa._TestProperty__aa的用法

class TestProperty(object):
    """
    测试私有属性的Property的用法
    """
    def __init__(self, aa):
        self.__aa = aa  # 给私有属性赋初值

    # 外界想要用 类实例名.变量名的方式来获取这个私有变量的时候触发 注意 类实例名.变量名的变量名 以下面的 变量名=property 为准
    def getaa(self):
        print("=[获取]私有属性aa的值=")
        return self.__aa

    # 外界想要用 类实例名.变量名的方式来修改这个私有变量的时候触发
    def setaa(self, v):
        print("=[修改]私有属性aa的值=")
        self.__aa = v

    # 外界想要用 del(类实例名.变量名)的方式来修改这个私有变量的时候触发 注意的是del函数无法真正的销毁这个私有属性 要想彻底销毁这个私有属性 需要在类内执行del才可以
    def delaa(self):
        print("=[删除]私有属性aa的值=")
        # del(self.__aa)  # 要想彻底销毁这个私有属性 需要在类内执行del才可以
        self.__aa = 0  # 假装销毁一下归零吧

    # 这个变量才是外面要直接调用的变量名 而不是私有属性名 这个变量可以随意改
    aaa = property(getaa, setaa, delaa, "doc1111")
    # aaa = property(getaa)  #设置为外界只读

testaa = TestProperty(14)

print("私有类属性aa为:{}".format(testaa.aaa))
testaa.aaa = 24
print("私有类属性aa为:{}".format(testaa.aaa))

del(testaa.aaa)
print("私有类属性aa为:{}".format(testaa.aaa))

print(testaa._TestProperty__aa)
testaa._TestProperty__aa = 34  # 知道了类名和私有属性名 用这种方式可以直接修改访问私有属性
print("私有类属性aa为:{}".format(testaa.aaa))


public protected private三种封装类型 在 当前类  当前类的子类 和外部访问的权限情况


范围\封装类型 public protected private
类内 okok ok
外部访问 ok 无法直接访问修改 无法直接访问修改
子类是否继承到这些封装属性方法 ok ok 虽然dir(子类)显示有该私有属性方法但是无法在子类中调用该继承属性方法
子类中能否直接调用父类.封装属性方法 ok ok 调用失败 没找到对应的属性方法


论:public是哪个地方都能用 protected是类内 子类能继承 子类也能直接调用 但是就是外部无法直接访问 private是只能类内调用 子类继承这种私有属性方法但无法使用 子类更无法直接使用这种父类的私有属性方法


继承

单继承

class TestObject(object):  # 括号内是父类名字

        pass

多继承

class TestObject(TestA, TestB):  # 括号内是父类们的名字

        pass

多继承的问题

一个子类继承多个父类,如果这些父类的方法属性重名相互冲突  一般都是前面的父类的同名方法属性覆盖后面的 并且并不推荐使用多继承


子类的属性方法的来源

由于存在继承 类实例使用的属性方法 可能是源于类本身 也可能是源于类的父类中  或者源于 父类的父类 祖父类 等等一级一级的向上找 都是有可能的 至于先找谁后找谁就涉及到了 mro问题


父类的方法的重写

没什么说的

class TestFather(object):

         def hobby(self):  # 父类的爱好方法是喜欢喝酒

               print(“爱好是喝酒”)

class Tom(TestFather):  # 但是tom这个不喜欢喝酒 但是会自动继承父类 TestFather的爱好方法 所以这里重写下 这个爱好方法改变他的内容

          def hobby(self):

               print(“爱好是睡觉”) 


非绑定方法

 解决通过类名调用该类对应的实例方法 通过类名调用实例方法 叫非绑定方法 具体形式 类名.实例方法名(实例名,参数1,参数2….) 这样可以使用类名来调用实例方法 注意严格按照实例方法的参数来写入参数 一个都不能少 不会自动省略self了 如果该实例方法内部还掺杂 其他实例属性或者其他实例方法无法在参数里面完全给予 则只能另想其他思路


super()函数

解决 子类调用父类中的方法的问题 一般是用来载入父类的__init__方法 而且注意父类的__init__()的参数个数  也要原样的写上 如果是多继承,那么除了第一个父类可以用super().父类方法(参数1.参数2,…)  其他的依然要使用 父类名.父类方法(参数1.参数2,…)  来调用

注意 super在多继承情况下 super是代表当前类第一个父类  根据该父类的方法 super自动加载self 这个不用写 其他的参数都要写

个人推荐 子类调用父类中的方法上 如果单继承 推荐super 如果多继承 第一个父类的方法都用super执行 其他的父类则推荐 父类名.父类方法名(参数1,…)  注意这种写法严格按照实例方法的参数来写入参数 一个都不能少 不会自动省略self了

class People:
    def __init__(self,name):
        self.name = name
    def say(self):
        print("我是人,名字为:",self.name)
class Animal:
    def __init__(self,food):
        self.food = food
    def display(self):
        print("我是动物,我吃",self.food)
class Person(People, Animal):
    #自定义构造方法
    def __init__(self,name,food):
        #调用 People 类的构造方法
        super().__init__(name)
        #super(Person,self).__init__(name) #执行效果和上一行相同
        #People.__init__(self,name)#使用未绑定方法调用 People 类构造方法
        #调用其它父类的构造方法,需手动给 self 传值
        Animal.__init__(self,food)    
per = Person("zhangsan","熟食")
per.say()
per.display()
结果

我是人,名字为: zhangsan
我是动物,我吃 熟食


了解:动态的添加或者修改类 或者 类实例的属性和方法

类名.新方法名 = 函数名

类实例名.新方法名 = 函数名

但是这种动态的添加修改 类属性 类方法 实例属性 实例方法的有点危险  可以在类内规定 运行动态添加修改的属性名或者方法名 但是类的动态添加修改不在限制范围内

  1. class CLanguage:
  2. __slots__ = ('name','add','info')  # 值允许添加修改这3个命名的属性或者方法  而且只能限制类实例  类本身的动态添加属性方法不受限制 并且对于本类的子类 也没有继承到这个限制


了解:type ()函数的进一步的用法  创建自定义类(创建一个新的类型)  type(name, bases, dict)

#定义一个实例方法
def say(self):
    print("我要学 Python!")
#使用 type() 函数创建类
CLanguage = type("CLanguage",(object,),dict(say = say, name = "C语言中文网"))
#创建一个 CLanguage 实例对象
clangs = CLanguage()
#调用 say() 方法和 name 属性
clangs.say()
print(clangs.name)

从底层原理看 我们最常见的用class定义类 到了底层本质上就是用type来声明一个类的


多态

1.多态发生在有继承关系的子类父类之间

2.子类重写了父类的某方法 使该方法的结果和父类不同呈现多种形态

class CLanguage:
    def say(self):
        print("调用的是 Clanguage 类的say方法")
class CPython(CLanguage):
    def say(self):
        print("调用的是 CPython 类的say方法")
class CLinux(CLanguage):
    def say(self):
        print("调用的是 CLinux 类的say方法")
a = CLanguage()
a.say()

a = CPython()
a.say()

a = CLinux()
a.say()

调用的是 Clanguage 类的say方法
调用的是 CPython 类的say方法
调用的是 CLinux 类的say方法


类常见的几个固定函数

object类的理解

Python3下所有没指定父类的类默认都继承object 就是所说的新类 Python3之前的都是经典类

没继承和继承了object的区别如下

  1. Person ['__doc__', '__module__', 'name']   #没有继承object的普通景点类 就2个类方法 name是自己定义的类实例属性

  2. Animal ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',

  3. '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',

  4. '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']  #这个就是继承了object

object类的类属性方法的简单介绍

https://www.jb51.net/article/182040.htm

class object:
 """ The most base type """

 # del obj.xxx或delattr(obj,'xxx')时被调用,删除对象中的一个属性
 def __delattr__(self, *args, **kwargs): # real signature unknown
 """ Implement delattr(self, name). """
 pass

 # 对应dir(obj),返回一个列表,其中包含所有属性和方法名(包含特殊方法)
 def __dir__(self, *args, **kwargs): # real signature unknown
 """ Default dir() implementation. """
 pass

 # 判断是否相等 equal ,在obj==other时调用。如果重写了__eq__方法,则会将__hash__方法置为None
 def __eq__(self, *args, **kwargs): # real signature unknown
 """ Return self==value. """
 pass

 # format(obj)是调用,实现如何格式化obj对象为字符串
 def __format__(self, *args, **kwargs): # real signature unknown
 """ Default object formatter. """
 pass

 # getattr(obj,'xxx')、obj.xxx时都会被调用,当属性存在时,返回值,不存在时报错(除非重写__getattr__方法来处理)。
 # 另外,hasattr(obj,'xxx')时也会被调用(估计内部执行了getattr方法)
 def __getattribute__(self, *args, **kwargs): # real signature unknown
 """ Return getattr(self, name). """
 pass

 # 判断是否大于等于 greater than or equal,在obj>=other时调用
 def __ge__(self, *args, **kwargs): # real signature unknown
 """ Return self>=value. """
 pass

 # 判断是否大于 greater than,在obj>other时调用
 def __gt__(self, *args, **kwargs): # real signature unknown
 """ Return self>value. """
 pass

 # 调用hash(obj)获取对象的hash值时调用
 def __hash__(self, *args, **kwargs): # real signature unknown
 """ Return hash(self). """
 pass

 def __init_subclass__(self, *args, **kwargs): # real signature unknown
 """
 This method is called when a class is subclassed.

 The default implementation does nothing. It may be
 overridden to extend subclasses.
 """
 pass

 # object构造函数,当子类没有构造函数时,会调用object的__init__构造函数
 def __init__(self): # known special case of object.__init__
 """ Initialize self. See help(type(self)) for accurate signature. """
 pass

 # 判断是否小于等于 less than or equal,在obj<=other时调用
 def __le__(self, *args, **kwargs): # real signature unknown
 """ Return self<=value. """
 pass

 # 判断是否小于 less than,在obj<other时调用
 def __lt__(self, *args, **kwargs): # real signature unknown
 """ Return self<value. """
 pass

 # 创建一个cls类的对象,并返回
 @staticmethod # known case of __new__
 def __new__(cls, *more): # known special case of object.__new__
 """ Create and return a new object. See help(type) for accurate signature. """
 pass

 # 判断是否不等于 not equal,在obj!=other时调用
 def __ne__(self, *args, **kwargs): # real signature unknown
 """ Return self!=value. """
 pass

 def __reduce_ex__(self, *args, **kwargs): # real signature unknown
 """ Helper for pickle. """
 pass

 def __reduce__(self, *args, **kwargs): # real signature unknown
 """ Helper for pickle. """
 pass

 # 如果不重写__str__,则__repr__负责print(obj)和交互式命令行中输出obj的信息
 # 如果重写了__str__,则__repr__只负责交互式命令行中输出obj的信息
 def __repr__(self, *args, **kwargs): # real signature unknown
 """ Return repr(self). """
 pass

 # 使用setattr(obj,'xxx',value)、obj.xxx=value是被调用(注意,构造函数初始化属性也要调用)
 def __setattr__(self, *args, **kwargs): # real signature unknown
 """ Implement setattr(self, name, value). """
 pass

 # 获取对象内存大小
 def __sizeof__(self, *args, **kwargs): # real signature unknown
 """ Size of object in memory, in bytes. """
 pass

 # 设置print(obj)打印的信息,默认是对象的内存地址等信息
 def __str__(self, *args, **kwargs): # real signature unknown
 """ Return str(self). """
 pass

 @classmethod # known case
 def __subclasshook__(cls, subclass): # known special case of object.__subclasshook__
 """
 Abstract classes can override this to customize issubclass().

 This is invoked early on by abc.ABCMeta.__subclasscheck__().
 It should return True, False or NotImplemented. If it returns
 NotImplemented, the normal algorithm is used. Otherwise, it
 overrides the normal algorithm (and the outcome is cached).
 """
 pass
 # 某个对象是由什么类创建的,如果是object,则是type类<class 'type'>
 __class__ = None
 # 将对象中所有的属性放入一个字典,例如{'name':'Leo','age':32}
 __dict__ = {}
 # 类的doc信息
 __doc__ = ''
 # 类属于的模块,如果是在当前运行模块,则是__main__,如果是被导入,则是模块名(即py文件名去掉.py)
 __module__ = ''



__new__   __init__  __str__   __del__的介绍


类初始化的机制的粗浅理解

首先开始初始化->__new__被触发->类本身作为参数被传入到__new__里面->使用继承自object类或者父类的__new__方法 在内存中开辟了一个空间来准备存储这个类的实例对象,并且把开辟的空间地址(也有一说是返回的一个实例对象)  自动传给__init__作为它的第一个参数并自动调用了__init__->__init__方法在__new__开辟的空间进行了进一步的初始化工作 完成整个初始化   整个初始化是__new__和__init__一起配合才完成的


__new__

初始化对象的时候触发 __new__是个类方法 参数是类本身(参数cls) 作用是创建一个类实例的空间 返回一个类实例对象自动给__init__作为第一个参数触发__init__继续完成初始化


__init__

承接__new__继续完成初始化工作  没有返回值  是个类实例方法

一般情况下都是在__init__里面显式对类实例属性统一的声明赋初值和进行前期处理和验证


__str__ 

print函数的时候触发 简单说 print(类实例名) 其实就是自动调用了 类实例.__str__  默认情况下会输出 实例名和对应的内存地址  如果我们改写__str__那么print(类实例名) 显示的内容自然是按照我们的定义来显示的

class Student(object):
    def __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
 
    def __str__(self):
        return "学号:{}--姓名:{}--年龄{}".format(self.id,self.name,self.age)
    
s=Student(111,"Bob",18)
print(s)

学号:111–姓名:Bob–年龄18  # 而不是 <main.Student object at 0x0362EBF0>


__del__

对象从内存删除的时候触发  比如该实例被del()了 自然会自动触发类实例.__del__() 没什么可说的


项目的简易分析设计

总结需求 –> 分析  -> 获取其中的各个对象 和对象具备的属性方法 –> 研究对象之间的交互 构建整个流程

项目简易分析 很简单 把需求写出来  然后提取出名词 动词 形容词 数据等等 一般情况下 名词就是该项目的一个对象  形容词很可能是某个对象的属性 动词很有可能是某个对象的方法   然后建立对象和对应的属性方法 然后尝试用对象和具备的属性方法来交互完成整个项目要求 如果存在问题再修正 不断完善

实例1:屋子放家具

1.2个名词 屋子 家具 不过按理说还有一个移动家具的 人存在  暂时是3个对象  屋子  家具 人

2 屋子没法自己把家具拉进去 家具自己也没张腿 所以 人 必须具备方法 搬动 这个搬动方法应该至少2个参数 一个是搬动什么  第二个参数是搬动到哪里去 家具存在多个 自然要增加一个 家具对象的属性 家具id和家具名字  屋子应该只有一个 不需要屋子序号 只要一个屋子名字属性即可

屋子  属性:屋子id 屋子名

人 方法:搬动

家具 属性:家具id 家具名字

3 要完成屋子放家具的动作   对象人.搬动(被搬动的家具id,搬动到哪的屋子id)


实例2:小明体重75公斤 每次跑步减少0.5 每次吃饭增加1

1。名词就一个小明  对象就小明一个对象  体重是附属于小明的自然是小明这个对象的属性 动词 跑步 吃饭 都是属于小明对象的方法

2 对象小明

属性:体重

方法: 跑步 吃饭

3 简单的概念结构

class xiaoming(object):

      def __init__(self,weight):

          self.weight = weight

    

     def showweight():

          print(self.weight)

   

    def run():

         self.weight –= 0.5

 

    def eat():

         self.weight += 1



设计模式 单例模式

设计模式很多 先来说下单例模式

简单说 无论创建多少类的实例 单例模式会让从始至终只有一开始创建的那个类实例存在

单例模式的实现主要是对 类的__new__的重写来实现的 每次要创建新的类实例 触发__new__的时候 在__new__里面都会检查下 之前记录的类实例的是否还存在 存在则返回这个已存在的实例对象的内存地址给__init__就是 如果不存在则创建下新的类实例 然后记录下这个类实例到类属性中 然后把新的类属性返回给__init__继续完成初始化的工作

一个简易的单例模式:没考虑多线程的问题 后面再说

class TestOnlyMode(object):
    """
    简单的一个单例模式结构
    """
    # 类属性 用来记录唯一的类实例对象和是否要初始化实例的各个参数
    _only_record = None
    _is_init = False

    def __new__(cls, *args, **kwargs):
        if cls._only_record:
            # _only_record里面已经存储了一个类实例了 就不用创建了
            print("_only_record 为真 不用创建实例了[{}]".format(cls._only_record))
            pass
        else:
            # 还没创建实例呢 就现在创建1个
            print("_only_record 为假 创建实例中")
            cls._only_record = object.__new__(cls)
            print("_only_record 为真 创建实例完毕[{}]".format(cls._only_record))
        return cls._only_record  # 返回个实例对象给init处理

    def __init__(self, a, b, c):
        print(self._is_init)
        if self._is_init:
            # 为真表示已经实例化完毕了 不用再次连续设置初值
            print("无需初始化参数")
            pass
        else:
            # 没实例化自然要设置初值
            print("初始化参数了")
            self.a = a
            self.b = b
            self.c = c
            self._is_init = True
    def showit(self):
        print("a:{} ,b:{} ,c:{}".format(self.a, self.b, self.c))

aa = TestOnlyMode(1, 2, 3)
print(aa.showit())
bb = TestOnlyMode(1, 2, 4)
print(bb.showit())
cc = TestOnlyMode(2, 2, 3)
print(cc.showit())
print(id(aa))
print(id(bb))
print(id(cc))
posted @ 2020-09-12 19:09  点-滴  阅读(218)  评论(0编辑  收藏  举报