• Python的面向对象编程


    1、类的定义(class)

    在Python中,定义类是通过class关键字,类名通常是大写开头的单词。语法格式如下:

    class ClassName:
        <statement-1>
        .
        .
        .
        <statement-N>

    类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。

    1.1、构造方法(__init__(self))

    类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用,像下面这样:

    def __init__(self):
        self.data = []

    如下实例化类 MyClass,对应的 __init__() 方法就会被调用:

    x = MyClass()

    注意,__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。当然, __init__() 方法也可以有其他参数,参数通过 __init__() 传递到类的实例化操作上。在构造实例时,self参数不需要传,Python解释器自己会把实例变量传进去。

    示例:

    #!/usr/bin/python3
     
    class Complex:
        def __init__(self, realpart, imagpart):
            self.r = realpart
            self.i = imagpart
    x
    = Complex(3.0, -4.5) print(x.r, x.i) # 输出结果:3.0 -4.5

    类的方法与普通的函数只有一个特别的区别:它们必须有一个额外的第一个参数名称(我们习惯将它命名为 self,但不是必须叫这个名字),除此之外,类的方法和普通函数没有什么区别。self代表的是类的实例,而非类。

    1.2、创建一个类实例

    类对象支持两种操作:属性引用和实例化。属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name

    类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样:

    #!/usr/bin/python3
     
    class MyClass:
        """一个简单的类实例"""
        i = 12345
        def f(self):
            return 'hello world'
     
    # 实例化类
    x = MyClass()
     
    # 访问类的属性和方法
    print("MyClass 类的属性 i 为:", x.i)
    print("MyClass 类的方法 f 输出为:", x.f())

    可以自由地给一个实例变量绑定属性,比如,给实例 x 随便绑定一个name属性:

    x.name = 'Bart Simpson'
    print(bart.name)   #'Bart Simpson'

    和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同。

    1.3、实例属性和类属性

    Python是动态语言,可以给类的实例绑定任意的属性。给实例绑定属性我们可以通过self变量,或者直接给类实例绑定也行:

    class Student(object):
        def __init__(self, name):
            self.name = name
    
    s = Student('Bob')
    s.score = 90    #直接绑定一个属性

    在一个类中定义的属性,这种属性是类属性,归类本身所有:

    class Student(object):
        name = 'Student'     #类属性

    类属性可以直接通过类来访问,也可以通过类实例来访问:

    class Student(object):
    ...     name = 'Student'
    ...
    
    s = Student() # 创建实例s
    print(s.name) #Student 打印出name属性,因为实例并没有name属性,所以会继续查找class的name属性
    
    print(Student.name) #Student  打印类的name属性
    
    s.name = 'Michael'  # 给实例绑定name属性
    print(s.name) #Michael 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
    
    print(Student.name) #Student 但是类属性并未消失,用Student.name仍然可以访问
    
    del s.name # 如果删除实例的name属性
    print(s.name) #Student 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了

    在给一个类实例绑定属性时,建议不要使用和类属性相同的名字。

    实例属性属于各个实例所有,互不干扰。类属性属于类所有,所有实例共享一个属性。建议不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。

    1.4、类的方法

    在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。

    #!/usr/bin/python3
     
    #类定义
    class people:
        #定义基本属性
        name = ''
        age = 0
        #定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
        #定义构造方法
        def __init__(self,n,a,w):
            self.name = n
            self.age = a
            self.__weight = w
        def speak(self):
            print("%s 说: 我 %d 岁。" %(self.name,self.age))
     
    # 实例化类
    p = people('runoob',10,30)
    p.speak()    #输出  runoob 说: 我 10 岁。

    1.5、私有属性和私有方法(以__开头的属性和方法)

    在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。如果外部直接通过实例来访问私有属性和方法的话,代码将直接报错。

    私有属性:以两个下划线开头(比如:__private_attrs)的属性为类的私有属性,该属性不能在类的外部被使用或直接访问,在类内部的方法中使用 self.__private_attrs 进行访问。

    私有方法:以两个下划线开头(比如:__private_method)的属性为类的私有方法,该方法不能在类的外部被使用或直接访问,在类内部的方法中使用 self.__private_method 进行访问。

    私有属性代码示例:

    #!/usr/bin/python3
     
    class JustCounter:
        __secretCount = 0  # 私有变量
        publicCount = 0    # 公开变量
     
        def count(self):
            self.__secretCount += 1
            self.publicCount += 1
            print (self.__secretCount)
     
    counter = JustCounter()
    counter.count()
    print (counter.publicCount)
    print (counter.__secretCount)  # 这里将报错,实例不能访问私有变量

    私有方法代码示例:

    #!/usr/bin/python3
     
    class Site:
        def __init__(self, name, url):
            self.name = name       # public
            self.__url = url   # private
     
        def who(self):
            print('name  : ', self.name)
            print('url : ', self.__url)
     
        def __foo(self):          # 私有方法
            print('这是私有方法')
     
        def foo(self):            # 公共方法
            print('这是公共方法')
            self.__foo()    # 可以通过类内部的方法来访问私有方法
     
    x = Site('菜鸟教程', 'www.runoob.com')
    x.who()        # 正常输出
    x.foo()        # 正常输出
    x.__foo()      # 访问私有方法这里将报错

    1.5.1、通过实例直接访问私有变量

    一般来说,私有变量是不能直接访问的,比如 __name,这是因为Python解释器对外把__name变量改成了_Student__name。但是实际上我们仍然可以通过_Student__name来访问__name变量:obj.__Student_name。

    但是非常不建议这么做,因为不同版本的Python解释器可能会把__name改成不同的变量名。

    2、继承

    Python 同样支持类的继承。基类必须与派生类定义在一个作用域内。

    派生类的定义如下所示:则此时基类 BaseClassName 必须和类 DerivedClassName 定义在同一个作用域内。

    class DerivedClassName(BaseClassName1):
        <statement-1>
        .
        .
        .
        <statement-N>

    除了直接使用类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:

    class DerivedClassName(modname.BaseClassName):

    继承代码示例:

    #!/usr/bin/python3
     
    #类定义
    class people:
        #定义基本属性
        name = ''
        age = 0
        #定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
        #定义构造方法
        def __init__(self,n,a,w):
            self.name = n
            self.age = a
            self.__weight = w
        def speak(self):
            print("%s 说: 我 %d 岁。" %(self.name,self.age))
     
    #单继承示例
    class student(people):
        grade = ''
        def __init__(self,n,a,w,g):
            #调用父类的构函
            people.__init__(self,n,a,w)
            self.grade = g
        #覆写父类的方法
        def speak(self):
            print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
     
     
     
    s = student('ken',10,60,3)
    s.speak()   #输出  ken 说: 我 10 岁了,我在读 3 年级

    2.1、多继承

    Python同样有限的支持多继承形式。继承了多个类的类定义形如下例:

    class DerivedClassName(Base1, Base2, Base3):
        <statement-1>
        .
        .
        .
        <statement-N>

    需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。

    代码实例:

    #!/usr/bin/python3
     
    #类定义
    class people:
        #定义基本属性
        name = ''
        age = 0
        #定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
        #定义构造方法
        def __init__(self,n,a,w):
            self.name = n
            self.age = a
            self.__weight = w
        def speak(self):
            print("%s 说: 我 %d 岁。" %(self.name,self.age))
     
    #单继承示例
    class student(people):
        grade = ''
        def __init__(self,n,a,w,g):
            #调用父类的构函
            people.__init__(self,n,a,w)
            self.grade = g
        #覆写父类的方法
        def speak(self):
            print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
     
    #另一个类,多重继承之前的准备
    class speaker():
        topic = ''
        name = ''
        def __init__(self,n,t):
            self.name = n
            self.topic = t
        def speak(self):
            print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
     
    #多重继承
    class sample(speaker,student):
        a =''
        def __init__(self,n,a,w,g,t):
            student.__init__(self,n,a,w,g)
            speaker.__init__(self,n,t)
     
    test = sample("Tim",25,80,4,"Python")
    test.speak()   #方法名同,默认调用的是在括号中排前地父类的方法   输出:我叫 Tim,我是一个演说家,我演讲的主题是 Python

    2.2、super() 函数

    super() 函数是用于调用父类(超类)的一个方法。

    class A:
         def add(self, x):
             y = x+1
             print(y)
    class B(A):
        def add(self, x):
            super().add(x)
    b = B()
    b.add(2)  # 3

    3、判断对象类型的方法

    3.1、type()

    判断对象类型可以使用type()函数,基本类型都可以用type()判断:

    type(123)  #<class 'int'>
    
    type('str')  #<class 'str'>
    
    type(None)  #<type(None) 'NoneType'>
    
    #函数和类也可以用type()判断:
    type(abs)  #<class 'builtin_function_or_method'>
    type(a)     #<class '__main__.Animal'>

    type()函数返回的返回对应的Class类型。我们可以直接比较两个变量的type类型是否相同:

    type(123)==type(456)  #True
    
    # 判断基本数据类型可以直接写int,str等
    type(123)==int  #True 
    type('abc')==str  #True 
    
    #如果要判断一个对象是否是函数可以使用types模块中定义的常量:
    import types
    def fn():
    ... pass
    ...
    type(fn)
    ==types.FunctionType #True type(abs)==types.BuiltinFunctionType #True type(lambda x: x)==types.LambdaType #True type((x for x in range(10)))==types.GeneratorType #True

    3.2、使用 isinstance(实例, 类)

    对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数:

    #假设继承关系:object -> Animal -> Dog -> Husky
    
    a = Animal()
    d = Dog()
    h = Husky()
    
    isinstance(h, Dog)  #true
    isinstance(h, Animal)  #true
    isinstance(d, Dog) and isinstance(d, Animal)  #true
    isinstance(d, Husky)  #false
    
    isinstance('a', str)  #True
    isinstance(123, int)  #True
    isinstance(b'a', bytes)  #True

    使用 isinstance() 还可以判断一个变量是否是多个类型中的其中一种。比如下面的代码就可以判断是否是list或者tuple:

    isinstance([1, 2, 3], (list, tuple))  #True
    isinstance((1, 2, 3), (list, tuple))  #True
  • 相关阅读:
    【转】做好测试计划和测试用例工作的关键
    【转】RESTful Web Services初探
    最快排序和搜索算法的最简代码实现_转
    排序算法
    libevent简述
    linux异步IO--aio
    长志气戒傲气 必须时刻保持冷静
    LACP-链路聚合
    AM335x移植linux内核_转
    4种用于构建嵌入式linux系统的工具_转
  • 原文地址:https://www.cnblogs.com/wenxuehai/p/14295772.html
Copyright © 2020-2023  润新知