12 类和对象

2017-04-20  本文已影响27人  阿健在长安

对象 = 属性(变量) + 方法(函数)

1. OO的特征

OO:Object Oriented(面向对象)

1. 封装:对外部隐藏对象的工作细节

一种信息隐蔽技术
例如:我们只会用list的相关方法,并不知道它们是如何实现的。

2. 继承:子类自动共享父类之间数据和方法的机制

3. 多态:可以对不同的对象调用相同的方法,产生不同的结果

即不同对象对同一方法响应不同的行动。

2.面向对象编程

1.self

每个实例对象的唯一标志,相当于C++的this指针。要求定义方法时把self写成第一个参数。

>>> class Ball:
    def setName(self,name):
        self.name = name
    def kick(self):
        print('I am %s' % self.name)
>>> a = Ball()
>>> a.setName('Tom')#调用时,会把a对应到self
>>> b = Ball()
>>> b.setName('John')
>>> a.kick()
I am Tom
>>> b.kick()
I am John

2.python的魔法方法

1. __init__(self):构造方法

实例化一个对象时,这个方法就在创建对象时被调用。

>>> class Ball:
    def __init__(self,name):#重写init,添加了一个name参数。
        self.name = name
    def kick(self):
        print('I am %s' % self.name)

        
>>> a = Ball('Tom')
>>> a.kick()
I am Tom

__init__特殊方法不应当返回除了None以外的任何对象,不能像下面这样写:

class C:
    def __init__(self):
        return 'hello world'

3.公有和私有

name mangling机制:在Python中定义私有变量只需要在变量名或函数名前加上“__”(两个下划线)即可。

>>> class Person:
    __name = 'Tom'#name变成了私有,不能通过p.__name直接访问
    def getName(self):#通过p.getName()间接访问
        return self.__name

    
>>> p = Person()
>>> p.getName()
'Tom'

也可以通过“_类名__变量名”访问,但不提倡。即:

p._Person__name

3. 类和对象的创建

1.类的创建

class Turtle:
    #属性
    color = 'green'
    weight = 10
    legs = 4
    shell = True
    mouth = '大嘴'
    #方法
    def climb(self):
        print('爬。。。。')
    def run(self):
        print('跑。。。。')     

2.对象的创建

>>> tt = Turtle()#把类赋给一个实例tt
>>> tt.climb()#调用成员方法
爬。。。。
>>> tt.color#调用成员属性
'green'
>>> Turtle()#创建一个实例,不被引用,会被回收机制清空
<__main__.Turtle object at 0x02B40FF0>

3.一个问题

Paste_Image.png

4.静态属性和静态方法

1.静态属性

在类中直接定义的变量(没有self),就是静态属性。引用类的静态属性使用“类名.属性名”的形式。
例如,计算一个类被实例化的次数:

>>> class C:
    count = 0
    def __init__(self):
        C.count += 1
    def getCount(self):
        return C.count
    
>>> a = C()
>>> b = C()
>>> C.count
2

2.静态方法

定义方法:在定义方法前加上@staticmethod。
优点:不会绑定到实例对象上,节省开销。

>>> class C:
    @staticmethod
    def static(a,b,c):
        print(a,b,c,a+b+c)
    def nostatic(self):
        print('I am nostatic.')
        
>>> c = C()
>>> c.static == C.static
True
>>> c.nostatic == C.nostatic
False

5.继承

1.继承的定义

class DerivedClassName(BaseClassName):
    .......

其中,BaseClassName为父类、基类或超类,DerivedClassName为子类。子类可继承父类的属性和方法。
例如:

>>> class Parent:
    def hello(self):
        print('正在调用父类的方法。')
        
>>> class Child(Parent):
    pass

>>> c = Child()
>>> c.hello()
正在调用父类的方法。

2.方法覆盖

如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。

>>> class Child(Parent):
    def hello(self):
        print('正在调用子类的方法。')
        
>>> c = Child()
>>> c.hello()
正在调用子类的方法。

看一个问题:

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
        return (self.x,self.y)

class Shark(Fish):
    def __init__(self):
        hungry = True
s = Shark()
s.move()#会报错,因为子类重写了父类的init方法

实现方法覆盖有两种方法:

class Shark(Fish):
    def __init__(self):
        Fish.__init__(self)#这里的self是子类的实例
        hungry = True
class Shark(Fish):
    def __init__(self):
        super().__init__()
        hungry = True

3.多重继承

1.定义方法:

class DerivedClassName(Base1,Base2,...):
    .......

尽量不用多重继承,防止不可预料的错误。

2.菱形继承

Paste_Image.png
class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        A.__init__(self)
        print("离开B…")
        
class C(A):
    def __init__(self):
        print("进入C…")
        A.__init__(self)
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        B.__init__(self)
        C.__init__(self)
        print("离开D…")

>>> d = D()
进入D…
进入B…
进入A…
离开A…
离开B…
进入C…
进入A…
离开A…
离开C…
离开D…

解决方案(super函数大显神威):

class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        super().__init__()
        print("离开B…")
        
class C(A):
    def __init__(self):
        print("进入C…")
        super().__init__()
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        super().__init__()
        print("离开D…")

>>> d = D()
进入D…
进入B…
进入C…
进入A…
离开A…
离开C…
离开B…
离开D…

5.组合

组合常用于没有什么关系的几个类,是一种横向关系,而继承是一种纵向关系。
比如定义了一个乌龟类和小鱼类,又想定义一个水池类,包含上面两类,就用到了组合。
操作方法:直接在类定义中把需要的类放进去实例化就可以了。

class Turtle:
    def __init__(self,x):
        self.num = x

class Fish:
    def __init__(self,x):
        self.num = x

class Pool:
    def __init__(self,x,y):
        self.turtle = Turtle(x)#创建乌龟和小鱼类的实例
        self.fish = Fish(y)

    def print_num(self):
        print('水池中共有乌龟%d只,小鱼%d只。' % (self.turtle.num,self.fish.num))
Paste_Image.png

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

1.Python无处不对象,类本身也是对象。

>>> class C:
    count = 0
    
>>> c = C()
>>> C.count += 1
>>> c.count
1
Paste_Image.png

2.如果实例的属性名字与方法名相同,则属性会覆盖方法。例:

>>> class C:
    def c():
        print('hello')

        
>>> x = C()
>>> x.c = 1
>>> x.c()
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    x.c()
TypeError: 'int' object is not callable

再如:

>>> class Test:
    def __init__(self,x):
        self.t = x
    def t(self):
        print('hello')

>>> tt = Test(10)
>>> tt.t#属性可以调用
10
>>> tt.t()#方法不能调用,被属性覆盖了
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    tt.t()
TypeError: 'int' object is not callable

3.区分类属性和实例属性

Paste_Image.png

4.思考题

在一个类中定义一个变量,用于跟踪该类有多少个实例被创建。

class Lei:
    count = 0

    def __init__(self):
        Lei.count += 1

    def __del__(self):
        Lei.count -= 1

a = Lei()
b = Lei()
print(Lei.count)

del a
print(Lei.count)

7.绑定

Python严格要求方法需要有实例才能被调用,这种限制就是Python所谓的绑定概念。

Paste_Image.png

8.相关BIF

1.issubclass()

判断一个类是否是另一个类的子类:

issubclass(class,classinfo)

注意:

>>> class A:
    pass

>>> class B(A):
    pass

>>> issubclass(B,A)
True
>>> issubclass(B,B)
True
>>> issubclass(B,object)#object是所有类的父类
True

2.isinstance()

判断一个实例对象是否属于一个类。

isinstance(object,classinfo)
>>> b = B()
>>> isinstance(b,B)
True
>>> isinstance(b,A)
True
>>> isinstance(b,(A,B))

3.hasattr()

判断一个对象是否有指定的属性。

hasattr(object,name)

例如:

>>> class C:
    def __init__(self,x = 0):
        self.x = x

>>> c = C()
>>> hasattr(c,'x')#注意,属性名要写成字符串形式

4.getattr()

得到一个对象的属性值。

getattr(object,name,[default])

如果属性不存在,则打印出default的内容。
例如:

>>> getattr(c,'x')
0
>>> getattr(c,'y','这个属性不存在。')
'这个属性不存在。'

5.setattr()

设置对象的属性值。如果属性不存在,则创建一个属性并赋值。

setattr(object,name,value)
>>> setattr(c,'y',3)
>>> getattr(c,'y')
3

6.delattr()

删除对象中指定属性。

delattr(object,name)

7.property()

用属性去设置属性。

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

例如:

>>> class C:
    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)
    
>>> c = C()
>>> c.x
10
>>> c.x = 11
>>> c.x
11
>>> del c.x

作用:
如果你改了get、set、del方法的名字,那提供给用户的接口也要改,麻烦。如果用了这个,改了也没关系,提供给用户的还是x。

上一篇 下一篇

猜你喜欢

热点阅读