美文网首页
12 类和对象

12 类和对象

作者: 阿健在长安 | 来源:发表于2017-04-20 12: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
    
    • 使用super()函数(推荐)
      可以自动找到父类的方法,并自动传入self参数。
      super的超级之处在于你不需要明确给出任何父类的名字,它会自动帮您找出所有父类以及对应的方法。由于不必给出基类名字,所以如果改变了类继承关系,只需改变class语句里的父类即可。
    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)
    

    注意:

    • 一个类它本身也被认为是它自己的子类。
    • classinfo可以是类对象组成的元组,只要class是其中任何一个候选类的子类,则为真。
      例如:
    >>> 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)
    
    • 如果第一个参数不是对象,刚永远返回False。
    • 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。例如:
    >>> 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。

    相关文章

      网友评论

          本文标题:12 类和对象

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