Python学习笔记——类和对象

作者: 没有故事的土鳖 | 来源:发表于2019-04-21 09:51 被阅读0次

    类和对象

    1. 一个例子

    # 对象 = 属性 + 方法
    # Python 中的类名称约定首字母大写,而 Python 函数名首字母小写
    class Turtle:  
        #属性
        color = 'green'
        weight = 10
        legs = 4
        shell = True
        mouth = '大嘴'
        
        # 方法
        # 这里的 self 表示 this 指针 
        def climb(self):
            print("我正在很努力地向前爬")
        def run(self):
            print("我正在飞快地向前跑")
        def bite(self):
            print("我咬死你咬死你")
        def eat(self):
            print("有得吃,真满足!")
        def sleep(self):
            print("困了,睡觉,晚安")
    
    tt = Turtle()
    tt.climb()
    tt.bite()
    tt.sleep()
    
    我正在很努力地向前爬
    我咬死你咬死你
    困了,睡觉,晚安
    

    2. 面向对象的特征

    ① 封装

    # 我们只知道这些方法如何调用,并不知道方法内部怎么实现的
    list1 = [2,1,7,5,3]
    list1.sort()
    list1.append(9)
    print(list1)
    
    [1, 2, 3, 5, 7, 9]
    

    ② 继承

    class MyList(list): # 这里表示 Mylist 类继承于 list 类
        # pass 为占位符,表明不做任何操作
        pass
    list2 = MyList()
    # list 类中的方法都被继承了
    list2.append(1)
    list2.append(7)
    list2.append(5)
    list2.append(4)
    list2.append(9)
    list2.sort()
    print(list2)
    
    [1, 4, 5, 7, 9]
    

    ③ 多态

    # 不同对象对同一方法响应不同的行动
    class A:
        def fun(self):
            print("我是小A")
            
    class B:
        def fun(self):
            print("我是小B")
    
    a = A()
    b = B()
    a.fun()
    b.fun()
    
    我是小A
    我是小B
    

    3. self

    # 当一个对象的方法被调用时,会将自身作为参数传入
    # 类的方法定义时,必须把 self 写入第一个参数
    class Ball:
        def setName(self,name):
            self.name = name
        def kick(self):
            print("我叫%s,该死的,谁踢我。。。" % self.name)
    
    a = Ball()
    a.setName('球A')
    b = Ball()
    b.setName('球B')
    c = Ball()
    c.setName('球C')
    a.kick()
    b.kick()
    c.kick()
    
    我叫球A,该死的,谁踢我。。。
    我叫球B,该死的,谁踢我。。。
    我叫球C,该死的,谁踢我。。。
    

    4. _ _ init _ _ (self)(这里是两个双下划线)

    class Ball:
        # 这个即为构造函数
        def __init__(self,name):
            self.name = name
        def kick(self):
            print("我叫%s,该死的,谁踢我。。。" % self.name)
            
    b = Ball('土豆')
    b.kick()
    
    我叫土豆,该死的,谁踢我。。。
    

    5. 公有和私有

    class Person:
        name = '小甲鱼'
    p = Person()
    print(p.name)
    
    小甲鱼
    
    class Person:
        # 变量前加上双下划线就会变成私有变量,无法直接调用
        __name = '小甲鱼'
        # 可以通过方法来调用
        def getName(self):
            return self.__name
    p = Person()
    print(p.name)
    
    -------------------------------------------------------------------------
    
    AttributeError                          Traceback (most recent call last)
    
    <ipython-input-23-e128ce7b44b9> in <module>()
          5         return self.__name
          6 p = Person()
    ----> 7 print(p.name)
    
    AttributeError: 'Person' object has no attribute 'name'
    
    print(p.getName())
    
    小甲鱼
    
    # 其实 Python 的私有为伪私有,只是将变量的名字改了(名字改编)
    # 可以通过 对象名._类名__变量名 来调用
    print(p._Person__name)
    
    小甲鱼
    

    6. 继承

    class Parent:
        def hello(self):
            print("正在调用父类的方法。。。")
            
    class Child(Parent):
        pass
    p = Parent()
    p.hello()
    c = Child()
    c.hello()
    
    正在调用父类的方法。。。
    正在调用父类的方法。。。
    
    class Child1(Parent):
        # 如果在子类中定义与父类同名的方法或属性,则会覆盖父类相应的方法或属性
        def hello(self):
            print("正在调用子类的方法。。。")
    d = Child1()
    d.hello()
    p.hello()
    
    正在调用子类的方法。。。
    正在调用父类的方法。。。
    

    7. 继承例子

    import random as r
    class Fish:
        def __init__(self):
            self.x = r.randint(0,10)
            self.y = r.randint(0,10)
        def move(self):
            self.x -= 1
            print("我现在的位置是:", self.x, self.y)
            
    class Goldfish(Fish):
        pass
    class Carp(Fish):
        pass
    class Salmon(Fish):
        pass
    class Shark(Fish):
        def __init__(self):
            self.hungry = True
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
    
    fish = Fish()
    fish.move()
    
    我现在的位置是: 3 6
    
    fish.move()
    
    我现在的位置是: 2 6
    
    goldfish = Goldfish()
    fish.move()
    
    我现在的位置是: 1 6
    
    shark = Shark()
    shark.eat()
    
    吃货的梦想就是天天有得吃
    
    # 由于 Shark 子类重写了 __init__ 方法,属性 x 和 y,都不存在了,所以会报错
    shark.move()
    
    -------------------------------------------------------------------------
    
    AttributeError                          Traceback (most recent call last)
    
    <ipython-input-44-e54bb3f218a2> in <module>()
    ----> 1 shark.move()
    
    <ipython-input-35-3f1e9b36930e> in move(self)
          5         self.y = r.randint(0,10)
          6     def move(self):
    ----> 7         self.x -= 1
          8         print("我现在的位置是:", self.x, self.y)
          9 
    
    AttributeError: 'Shark' object has no attribute 'x'
    
    class Shark1(Fish):
        def __init__(self):
            # 这里调用未绑定的父类方法
            # 这里的 self 是子类的对象,即将子类对象作为参数传入父类的构造方法
            # 从而定义了属性 x 和 y 
            Fish.__init__(self)
            self.hungry = True
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
    
    shark1 = Shark1()
    shark1.eat()
    shark1.move()
    
    吃货的梦想就是天天有得吃
    我现在的位置是: 8 9
    
    class Shark2(Fish):
        def __init__(self):
            # 也可以使用super
            super().__init__()
            self.hungry = True
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
    
    shark2 = Shark2()
    shark2.eat()
    shark2.move()
    
    吃货的梦想就是天天有得吃
    我现在的位置是: 5 9
    

    8. 多重继承

    # 尽量避免使用多重继承
    class Base1:
        def foo1(self):
            print("我是foo1,我为Base1代言。。。")
            
    class Base2:
        def foo2(self):
            print("我是foo2,我为Base2代言。。。")
            
    class C(Base1, Base2):
        pass
    
    c = C()
    c.foo1()
    c.foo2()
    
    我是foo1,我为Base1代言。。。
    我是foo2,我为Base2代言。。。
    

    9. 组合

    class Turtles:
        def __init__(self, x):
            self.num = x
    
    class Fishs:
        def __init__(self, x):
            self.num = x
    
    class Pool:
        def __init__(self, x, y):
            # 把类的实例化放到一个新类中,这样就可以避免使用多重继承
            self.turtles = Turtles(x)
            self.fishs = Fishs(y) 
            
        def print_num(self):
            print("水池里总共有乌龟 %d 只,小鱼 %d 条!" % (self.turtles.num, self.fishs.num))
    
    pool = Pool(1,10)
    pool.print_num()
    
    水池里总共有乌龟 1 只,小鱼 10 条!
    

    10. Mix-in 编程机制

    https://fishc.com.cn/forum.php?mod=viewthread&tid=48888&highlight=Mix

    11. 类、类对象和实例对象

    # 在定义的时候他是一个类,等他定义完就是一个类对象
    class C:
        count = 0
    
    a = C()
    b = C()
    c = C()
    print(a.count)
    print(b.count)
    print(c.count)
    
    0
    0
    0
    
    # 这里相当于生成了一个对象来覆盖了原来的count
    # 类中定义的属性都是静态属性
    # 类属性和类对象是相互绑定的,并不依赖于实例对象
    # 当执行 c.count += 10 的时候,c实例对象里面多出了一个count属性
    # 这个实例属性将类属性给覆盖了
    c.count += 10
    print(c.count)
    print(a.count)
    print(b.count)
    
    10
    0
    0
    
    C.count += 100
    print(a.count)
    print(b.count)
    print(c.count)
    
    100
    100
    10
    

    12. 属性和方法同名

    class D:
        def x(self):
            print("X-man!")
    d = D()
    d.x()
    
    X-man!
    
    # 这里是在实例对象里创建一个新的变量x,与方法同名,会覆盖方法
    d.x = 1
    print(d.x)
    
    1
    
    d.x()
    
    -------------------------------------------------------------------------
    
    TypeError                               Traceback (most recent call last)
    
    <ipython-input-84-a03010f95e9e> in <module>()
    ----> 1 d.x()
    
    TypeError: 'int' object is not callable
    
    • 不要试图在一个类里边定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展。
    • 用不同的词性命名,如属性名用名词,方法名用动词。

    13. 绑定

    Python要求方法需要有实例才能被调用,即为绑定

    class BB:
        # 这里没写参数 self
        def printBB():
            print("no zuo no die")       
    
    # 直接用类名可以调用
    BB.printBB()
    
    no zuo no die
    
    # 由于没有 self 参数,所以实例化对象没办法调用该方法
    bb = BB()
    bb.printBB()
    
    -------------------------------------------------------------------------
    
    TypeError                               Traceback (most recent call last)
    
    <ipython-input-87-65bc6f83f641> in <module>()
          1 bb = BB()
    ----> 2 bb.printBB()
    
    TypeError: printBB() takes 0 positional arguments but 1 was given
    
    class CC:
        # 方法是静态的,绑定在类对象中
        def setXY(self, x, y):
            self.x = x
            self.y = y
        def printXY(self):
            print(self.x, self.y)
    
    dd = CC()
    # 以字典方式输出 dd 对象所有的属性
    print(dd.__dict__)
    # 只有实例对象的属性,不显示类属性和特殊属性(魔法方法)
    # 键用引号引起来,表示属性名
    # 值表明属性对应的值
    print(CC.__dict__)
    
    {}
    {'__module__': '__main__', 'setXY': <function CC.setXY at 0x00000159506896A8>, 'printXY': <function CC.printXY at 0x00000159506891E0>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    # 这里调用实际上调用的是dd.setXY(dd,4,5)
    # x,y 变量储存在 dd 实例对象的空间中
    dd.setXY(4,5)
    # 这里的 x, y 仅属于dd
    print(dd.__dict__)
    print(CC.__dict__)
    
    {'x': 4, 'y': 5}
    {'__module__': '__main__', 'setXY': <function CC.setXY at 0x00000159506896A8>, 'printXY': <function CC.printXY at 0x00000159506891E0>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    del CC
    ee = CC()
    
    -------------------------------------------------------------------------
    
    NameError                               Traceback (most recent call last)
    
    <ipython-input-99-55ea04a3e7cb> in <module>()
          1 del CC
    ----> 2 ee = CC()
    
    NameError: name 'CC' is not defined
    
    
    # 虽然类对象已经被删除,但是实例对象已经储存在内存中,仍然可以使用
    # 只有在程序退出时才会被释放
    # 所以大多数情况下应该使用实例属性,而不要去使用类属性
    dd.printXY()
    
    4 5
    

    14.一些BIF

    ① issubclass(class,classinfo)

    如果 clss 是 classinfo 的子类,就会返回TRUE

    • 一个类会被认为是其自身的子类
    • classinfo可以是类对象组成的元组,只要class是其中任何一个候选类的子类,则会返回True
    class A:
        pass
    class B(A):
        pass
    class C:
        pass
    print(issubclass(B,A))
    print(issubclass(B,B))
    # 所有类都是object类的子类
    print(issubclass(B,object))
    print(issubclass(B,C))
    
    True
    True
    True
    False
    

    ② isinstance(object,classinfo)

    如果 object 是 classinfo 的实例对象,就会返回TRUE

    • 如果第一个参数不是对象,则永远返回False
    • classinfo可以是类对象组成的元组,只要object是其中任何一个候选类的实例对象,则会返回True
    • 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError
    b1 = B()
    print(isinstance(b1,B))
    # B类继承于A类
    print(isinstance(b1,A))
    print(isinstance(b1,C))
    print(isinstance(b1,(A,B,C)))
    
    True
    True
    False
    True
    

    ③ hasattr(object,name)

    测试object对象里面是否有属性name

    class D:
        def __init__(self,x=0):
            self.x = x
    d1 = D()
    # 这里的属性名参数,必须加上引号,否则会报错
    print(hasattr(d1,'x'))
    
    True
    

    ④ getattr(object,name[,default])

    返回对象指定的属性值,如果属性不存在,如果你还设置了default,则会打印出default;如果没设置,则会抛出AttributeError的异常

    print(getattr(d1,'x'))
    
    0
    
    print(getattr(d1,'y'))
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-12-bae8070f3f96> in <module>()
    ----> 1 print(getattr(d1,'y'))
    
    AttributeError: 'D' object has no attribute 'y'
    
    print(getattr(d1,'y','您所访问的属性不存在'))
    
    您所访问的属性不存在
    

    ⑤ setattr(object,name,value)

    设置对象中指定属性的值,如果没有,则会新建并赋值

    setattr(d1,'y','Nigream')
    print(getattr(d1,'y'))
    
    Nigream
    

    ⑥ delattr(object,name)

    删除对象中指定的属性,如果不存在则抛出AttributeError的异常

    delattr(d1,'y')
    
    delattr(d1,'y')
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-16-88d9b933b227> in <module>()
    ----> 1 delattr(d1,'y')
    
    AttributeError: y
    

    ⑦ property(fget=None, fset=None, fdel=None, doc=None)

    通过属性来设置属性

    • fget为获取属性的方法,当执行e1.x语句时调用
    • fset为设置属性的方法,当执行e1.x=18语句时调用
    • doc为删除属性的方法,当执行del e1.x语句时调用
    class E:
        def __init__(self,size=10):
            self.size = size
        def getSize(self):
            return self.size
        def setSize(self,value):
            self.size = value
        def delSize(self):
            del self.size
        x = property(getSize,setSize,delSize)
    
    e1 = E()
    print(e1.getSize())
    
    10
    
    print(e1.x)
    
    10
    
    e1.x = 18
    print(e1.x)
    
    18
    
    print(e1.getSize())
    
    18
    
    del e1.x
    
    e1.size
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-53-2b22d88d2a9b> in <module>()
    ----> 1 e1.size
    
    AttributeError: 'E' object has no attribute 'size'
    

    相关文章

      网友评论

        本文标题:Python学习笔记——类和对象

        本文链接:https://www.haomeiwen.com/subject/xdxrgqtx.html