zoukankan      html  css  js  c++  java
  • python 对象和类

    python中所有数据都是以对象形式存在。对象既包含数据(变量),也包含代码(函数),是某一类具体事物的特殊实例。

    面向对象的三大特性为封装、继承和多态。

    1、定义类

    #定义空类
    class Person():
        pass
    #添加对象初始化方法
    def Person():
        def __init__(self):
            pass

    self参数指向正在被创建的对象本身。

    self 代表的是类的实例,代表当前对象的地址,而 self.__class__ 则指向类。

    #初始化方法中添加参数
    def Person():
        def __init__(self,name):
            self.name=name

    2、创建实例

    >>>hunter=Person('Elmer Fudd')

    上一行做了以下工作:

    • 查看Person类的定义
    • 在内存中实例化(创建)一个新的对象调用对象的__init__方法,将这个新创建的对象作为self传入,并将另一个参数‘Elmer Fudd’作为name传入
    • 将name的值存入对象
    • 返回这个新的对象
    • 将名字hunter和这个对象关联

    3、访问属性

    使用点号 . 来访问对象的属性

    print(hunter.name)

    一些内置类属性:

    • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
    • __doc__ :类的文档字符串
    • __name__: 类名
    • __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
    • __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)

    4、继承

    继承即从已有类中衍生出新的类,可以添加或修改部分功能。便于代码复用。

    class Car():
        pass
    class Yugo(Car):
        pass

    5、类方法覆盖

    新创建的子类会自动继承父类的所有信息。

    class Car():
        def exclaim(self):
            print("I'm a Car!")
    class Yugo(Car):
        pass
    t1=Car()
    t2=Yugo()
    >>>t1.exclaim()
    I'm a Car!
    >>>t2.exclaim()
    I'm a Car!

    对继承的方法进行修改后会覆盖原有的方法。

    class Car():
        def exclaim(self):
            print("I'm a Car!")
    class Yugo(Car):
        def exclaim(self):
            print("I'm a Yugo!")
    t1=Car()
    t2=Yugo()
    >>>t1.exclaim()
    I'm a Car!
    >>>t2.exclaim()
    I'm a Yugo!

    在子类中,可以覆盖父类的方法,包括__init__()方法

    class MDPerson(Person):
        def __init__(self,name):
            self.name="Doctor" + name
    a=Person('Tom')
    b=MDPerson('Tom')
    >>>a.name
    Tom
    >>>b.name
    Doctor Tom

    6、子类添加新方法

    class Car():
        def exclaim(self):
            print("I'm a Car!")
    class Yugo(Car):
        def exclaim(self):
            print("I'm a Yugo!")
        def push(self):
            print('need a push')
    a=Car()
    b=Yugo()
    >>>b.push()
    need a push

    7、使用super()调用父类方法

    class EPerson(Person):
        def __init__(self,name,email):
            super().__init__(name)
            self.email=email

    我们应当使用super()来让父类完成其应当做的事情。并且,如果父类的定义以后发生改变,使用super()可以保证这些改变会自动反映到子类上,而不需要手动修改。

    8、self参数作用

    以下句代码举例:

    >>>t1.exclaim()
    • 查找t1对象所属的类Car
    • 把t1对象作为self参数传给Car类所包含的exclaim()方法

    相当于:

    >>>Car.exclaim(t1)

    9、使用property属性访问

    property(fget,fset,fdel,doc)

    class Duck():
        def __init__(self,iname):
            self.hidden_name=iname
        def get_name(self):
            return self.hidden_name
        def set_name(self,iname):
            self.hidden_name=iname
        name=property(get_name,set_name)

    最后一行将get_name,set_name定义为name属性。当访问name时,get_name()会被自动调用。当对name执行赋值操作时,set_name()方法会被调用。

    tt=Duck('Howard')
    >>>tt.name
    'Howard'
    >>>tt.name='Tom'
    >>>tt.name
    'Tom'

    也可以通过装饰器方式定义property。

    • @property,用于指定getter方法
    • @name.setter,用于指定setter方法
    class Duck():
        def __init__(self,iname):
            self.hidden_name=iname
        @property
        def name(self):
            return self.hidden_name
        @name.setter
        def name(self,iname):
            self.hidden_name=iname

    property除指向类中存储的某一属性(如hidden_name),也可以指向计算结果值。

    class Circle():
        def __init__(self,radius):
            self.radius=radius
        @property
        def diameter(self):
            return 2*self.radius
    c=Circle(5)
    >>>c.radius
    5
    >>>c.diameter
    10
    >>>c.radius=7
    >>>c.diameter
    14

    如果没有指定property的setter,将无法从类的外部对它的值进行设置。

    与直接访问属性相比,如果改变某一属性的定义,只需要在类定义中修改代码,不需要在每一处调用修改。

     10、使用__保护私有属性

    把hidden_name改为__name:

    class Duck():
        def __init__(self,iname):
            self.__name=iname
        @property
        def name(self):
            return self.__name
        @name.setter
        def name(self,iname):
            self.__name=iname
    ff=Duck('Tom')
    >>>ff.name
    'Tom'
    >>>ff.name='Do'
    >>>ff.name
    'Do'

    此时name能够正常使用,但是如果试图使用ff.__name则会报错,无法从外部直接访问。

    但是这种方法没有本质上将其变为私有,只是将其名称重整,通过以下方法仍可从外部访问:

    >>>ff._Duck__name
    'Do'

    11、方法类型

    • 以self作为第一个参数的方法都是实例方法
    • 类方法则作用于整个类,对类作出的任何改变都会对它的所有实例对象产生影响。用装饰器@classmethod指定。类方法第一个参数为类本身,写作cls
    • 静态方法用@staticmethod修饰,不需要self参数和cls参数。出现在类的定义中只是为了方便

    12、多态与鸭子类型(duck typing)

     python对多态要求宽松,可以对不同对象调用同名方法,甚至不用管对象的类型。

    多态:

    class Quote():
        def __init__(self,person,words):
            self.person=person
            self.words=words
        def who(self):
            return self.person
        def says(self):
            return self.words+'.'
    class Question(Quote):
        def says(self):
            return self.words+'?'
    class Exclamation(Quote):
        def says(self):
            return self.words+'!'
    t1=Quote('Tom','doc')
    t2=Question('BB','doc')
    t3=Exclamation('JJ','doc')
    >>>print(t1.who(),'says:',t1.says())
    Tom says: doc.
    >>>print(t2.who(),'says:',t2.says())
    BB says: doc?
    >>>print(t3.who(),'says:',t3.says())
    JJ says: doc!

    鸭子类型:

    class Brook():
        def who(self):
            return 'Brook'
        def says(self):
            return 'Babble'
    brook=Brook()
    def who_says(obj):
        print(obj.who(),'says:',obj.says())
    >>>who_says(t1)
    Tom says: doc.
    >>>who_says(t2)
    BB says: doc?
    >>>who_says(t3)
    JJ says: doc!
    >>>who_says(brook)
    Brook says: Babble

    13、特殊方法:__

    建立一个普通的判断字符串相等的类:

    class Word():
        def __init__(self,text):
            self.text=text
        def equals(self,word2):
            rreturn self.text.lower()==word2.text.lower()
    first=Word('ha')
    second=Word('HA')
    third=Word('eh')
    >>>first.equals(second)
    True
    >>>first.equals(third)
    False

    如果通过first==second判断是不是更加简洁?现在把方法equals()改为__eq__():

    class Word():
        def __init__(self,text):
            self.text=text
        def __eq__(self,word2):
            rreturn self.text.lower()==word2.text.lower()
    first=Word('ha')
    second=Word('HA')
    third=Word('eh')
    >>>first==second
    True
    >>>first==third
    False

    相当于重载运算符==.

    • __eq__(self,other)  self==other
    • __ne__(self,other)  self!=other
    • __lt__(self,other)  self<other
    • __gt__(self,other) self>other
    • __le__(self,other) self<=other
    • __ge__(self,other) self>=other
    • __add__(self,other) self+other
    • __sub__(self,other) self-other
    • __mul__(self,other) self * other
    • __floordiv__(self,other)  self // other
    • __truediv__(self,other) self / other
    • __mod__(self,other)  self % other
    • __pow__(self,other) self ** other
    • __str__(self)  str(self)
    • __repr__(self)  repr(self)
    • __len__(self)  len(self)
    • __init__()  根据类的定义以及传入的参数对新创建的对象进行初始化

    14、类组合

    class A():
        def __init__(self,des):
            self.des=des
    class B():
        def __init__(self,des):
            self.des=des
    class C():
        def __init__(self,a,b):
            self.a=a
            self.b=b
        def about(self):
            print('A:',self.a.des,',B: ',self.b.des)
    t1=A('a')
    t2=B('b')
    t3=C(t1,t2)
    >>>t3.about()
    A: a ,B: b

    15、何时使用类

    • 需要许多具有相似行为但不同状态的实例时,使用类和对象
    • 类支持继承,模块不支持
    • 如果想要保证实例的唯一性,使用模块
    • 如果有一系列包含多个值的变量,并且能作为参数传入不同的函数,最好封装到类
    • 用最简单的方法解决问题。使用字典、列表、元组等比使用模块更加简单。使用类更加复杂
  • 相关阅读:
    KAFKA && zookeeper 集群安装
    haproxy安装与配置
    ansible-playbook-常用
    ansible-playbook--jia使用
    ansible-playbook-批量修改主机名
    关于学习的时间定律-21小时、1000小时、5000小时、10000小时
    SVN中trunk,branches,tags用法详解
    TortoiseSVN与VisualSVN Server搭建SVN版本控制系统
    使用httpclient 调用selenium webdriver
    selenium Remote Server 实现原理
  • 原文地址:https://www.cnblogs.com/ivan-count/p/10515702.html
Copyright © 2011-2022 走看看