Python学习笔记——类和对象

时间:2021-07-25 06:52:34

类和对象

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'