第六章 Python类(面向对象编程)

什么是面向对象编程?

面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。Python就是这种编程语言。

面向对象程序设计中的概念主要包括:对象、类、继承、动态绑定、封装、多态性、消息传递、方法。

1)对象:类的实体,比如一个人。

2)类:一个共享相同结构和行为的对象的集合。通俗的讲就是分类,比如人是一类,动物是一类。

3)继承:类之间的关系,比如猫狗是一类,他们都有四条腿,狗继承了这个四条腿,拥有了这个属性。

4)动态绑定:在不修改源码情况下,动态绑定方法来给实例增加功能。

5)封装:把相同功能的类方法、属性封装到类中,比如人两条腿走路,狗有四条腿走路,两个不能封装到一个类中。

6)多态性:一个功能可以表示不同类的对象,任何对象可以有不同的方式操作。比如一个狗会走路、会跑。

7)消息传递:一个对象调用了另一个对象的方法。

8)方法:类里面的函数,也称为成员函数。

对象=属性+方法。

属性:变量。

方法:函数。

实例化:创建一个类的具体实例对象。比如一条泰迪。

什么是类?

类是对对象的抽象,对象是类的实体,是一种数据类型。它不存在内存中,不能被直接操作,只有被实例化对象时,才会变的可操作。

类是对现实生活中一类具有共同特征的事物的抽象描述。

6.1 类和类方法语法

# 类
class ClassName():
   pass
    # 类中的方法
    def funcName(self):
      pass

self代表类本身。类中的所有的函数的第一个参数必须是self。

6.2 类定义与调用

#!/usr/bin/python
# -*- coding: utf-8 -*-
class MyClass():
    x = 100
    def func(self, name):
        return "Hello %s!" % name
    def func2(self):
        return self.x
mc = MyClass()  # 类实例化,绑定到变量mc
print mc.x   # 类属性引用
print mc.func("xiaoming")  # 调用类方法
print mc.func2()
 
# python test.py
100
Hello xiaoming!
100

上面示例中,x变量称为类属性,类属性又分为类属性和实例属性:

1)类属性属于类本身,通过类名访问,一般作为全局变量。比如mc.x

2)如果类方法想调用类属性,需要使用self关键字调用。比如self.x

3)实例属性是实例化后对象的方法和属性,通过实例访问,一般作为局部变量。下面会讲到。

4)当实例化后可以动态类属性,下面会讲到。

类方法调用:

1)类方法之间调用:self.<方法名>(参数),参数不需要加self

2)外部调用:<实例名>.<方法名>

6.3 类的说明

给类添加注释,提高可阅读性,可以通过下面方式查看。

方法1:
>>> class MyClass:
...   """
...   这是一个测试类.
...   """
...   pass
...
>>> print MyClass.__doc__
  这是一个测试类.
>>>
方法2:
>>> help(MyClass)
Help on class MyClass in module __main__:
class MyClass
 |  这是一个测试类.

6.4 类内置方法


内置方法


描述

__init__(self, ...) 初始化对象,在创建新对象时调用
__del__(self) 释放对象,在对象被删除之前调用
__new__(cls, *args, **kwd) 实例的生成操作,在__init__(self)之前调用
__str__(self) 在使用print语句时被调用,返回一个字符串
__getitem__(self, key) 获取序列的索引key对应的值,等价于seq[key]
__len__(self) 在调用内建函数len()时被调用
__cmp__(str, dst) 比较两个对象src和dst
__getattr__(s, name) 获取属性的值
__setattr__(s, name, value) 设置属性的值
__delattr__(s, name) 删除属性
__gt__(self, other) 判断self对象是否大于other对象
__lt__(self, other) 判断self对象是否小于other对象
__ge__(self, other) 判断self对象是否大于或等于other对象
__le__(self, other) 判断self对象是否小于或等于other对象
__eq__(self, other) 判断self对象是否等于other对象
__call__(self, *args) 把实例对象作为函数调用

6.5 初始化实例属性

很多类一般都有初始状态的,常常定义对象的共同特性,也可以用来定义一些你希望的初始值。

Python类中定义了一个构造函数__init__,对类中的实例定义一个初始化对象,常用于初始化类变量。当类被实例化,第二步自动调用的函数,第一步是__new__函数。

__init__构造函数也可以让类传参,类似于函数的参数。

__init__构造函数使用:

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class MyClass():
        def __init__(self):
            self.name = "xiaoming"
        def func(self):
            return self.name
    mc = MyClass()
    print mc.func()
    
    # python test.py
    xiaoming

__init__函数定义到类的开头.self.name变量是一个实例属性,只能在类方法中使用,引用时也要这样self.name。

类传参:

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class MyClass():
        def __init__(self, name):
            self.name = name
        def func(self, age):
            return "name: %s,age: %s" %(self.name, age)
    mc = MyClass(‘xiaoming‘)  # 第一个参数是默认定义好的传入到了__init__函数
    print mc.func(‘22‘) 
    
    # python test.py
    Name: xiaoming, Age: 22

6.6 类私有化(私有属性)

   6.6.1 单下划线

实现模块级别的私有化,以单下划线开头的变量和函数只能类或子类才能访问。当from modulename import * 时将不会引入以单下划线卡头的变量和函数。

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class MyClass():
        _age = 21
        def __init__(self, name=None):
            self._name = name
        def func(self, age):
            return "Name: %s, Age: %s" %(self._name, age)
    mc = MyClass(‘xiaoming‘)
    print mc.func(‘22‘)
    print mc._name
    print mc._age
    
    # python test.py
    Name: xiaoming, Age: 22
    xiaoming
    21

_age和self._name变量其实就是做了个声明,说明这是个内部变量,外部不要去引用它。

   6.6.2 双下划线

以双下划线开头的变量,表示私有变量,受保护的,只能类本身能访问,连子类也不能访问。避免子类与父类同名属性冲突。

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class MyClass():
          __age = 21
          def __init__(self, name=None):
              self.__name = name
          def func(self, age):
              return "Name: %s, Age: %s" %(self.__name, age)
    mc = MyClass(‘xiaoming‘)
    print mc.func(‘22‘)
    print mc.__name
    print mc.__age
    
    # python test.py
    Name: xiaoming, Age: 22
    Traceback (most recent call last):
      File "test.py", line 12, in <module>
        print mc.__name
    AttributeError: MyClass instance has no attribute ‘__name‘

可见,在单下划线基础上又加了一个下划线,同样方式类属性引用,出现报错。说明双下划线变量只能本身能用。

如果想访问私有变量,可以这样:

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class MyClass():
        __age = 21
        def __init__(self, name=None):
            self.__name = name
        def func(self, age):
            return "Name: %s, Age: %s" %(self.__name, age)
    mc = MyClass(‘xiaoming‘)
    print mc.func(‘22‘)
    print mc._MyClass__name
    print mc._MyClass__age
    
    # python test.py
    Name: xiaoming, Age: 22
    xiaoming
    21

self.__name变量编译成了self._MyClass__name,以达到不能被外部访问的目的,并没有真正意义上的私有。

   6.6.3 特殊属性(首尾双下划线)

一般保存对象的元数据,比如__doc__、__module__、__name__:

    >>> class MyClass:    
        """
        这是一个测试类说明的类。
        """
        pass
    # dic()返回对象内变量、方法
    >>> dir(MyClass)
    [‘__doc__‘, ‘__module__‘]
    >>> MyClass.__doc__
    ‘\n\t\xd5\xe2\xca\xc7\xd2\xbb\xb8\xf6\xb2\xe2\xca\xd4\xc0\xe0\xcb\xb5\xc3\xf7\xb5\xc4\xc0\xe0\xa1\xa3\n\t‘
    >>> MyClass.__module__
    ‘__main__‘
    >>> MyClass.__name__
    ‘MyClass‘

这里用到了一个新内置函数dir(),不带参数时,返回当前范围内的变量、方法的列表。带参数时,返回参数的属性、方法的列表。

Python自己调用的,而不是用户来调用。像__init__ ,你可以重写。

6.7 类的继承

子类继承父类,子类将继承父类的所有方法和属性,提高代码重用。

 1)简单继承

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class Parent():
        def __init__(self, name=None):
            self.name = name
        def func(self, age):
            return "Name: %s, Age: %s" %(self.name, age)
    class Child(Parent):
        pass
    mc = Child(‘xiaoming‘)
    print mc.func(‘22‘)
    print mc.name
    
    # python test.py
    Name: xiaoming, Age: 22
    xiaoming

   2)子类实例初始化

如果子类重写了构造函数,那么父类的构造函数将不会执行:

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class Parent():
        def __init__(self):
            self.name_a = "xiaoming"
        def funcA(self):
            return "function A: %s" % self.name_a
    class Child(Parent):
        def __init__(self):
            self.name_b = "zhangsan"
        def funcB(self):
            return "function B: %s" % self.name_b
    mc = Child()
    print mc.name_b
    print mc.funcB()
    print mc.funcA()
    
    # python test.py
    zhangsan
    function B: zhangsan
    Traceback (most recent call last):
      File "test2.py", line 17, in <module>
        print mc.funcA()
      File "test2.py", line 7, in funcA
        return "function A: %s" % self.name_a
    AttributeError: Child instance has no attribute ‘name_a‘

抛出错误,提示调用funcA()函数时,没有找到name_a属性,也就说明了父类的构造函数并没有执行。

如果想解决这个问题,可通过下面两种方法:

方法1:调用父类构造函数

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class Parent():
        def __init__(self):
            self.name_a = "xiaoming"
        def funcA(self):
            return "function A: %s" % self.name_a
    class Child(Parent):
        def __init__(self):
            Parent.__init__(self)
            self.name_b = "zhangsan"
        def funcB(self):
            return "function B: %s" % self.name_b
    mc = Child()
    print mc.name_b
    print mc.funcB()
    print mc.funcA()
    
    # python test.py
    zhangsan
    function B: zhangsan
    function A: xiaoming

方法2:使用supper()函数继承

    #!/usr/bin/python    
    # -*- coding: utf-8 -*-
    class Parent(object):
        def __init__(self):
            self.name_a = "xiaoming"
        def funcA(self):
            return "function A: %s" % self.name_a
    class Child(Parent):
        def __init__(self):
            super(Child, self).__init__()
            self.name_b = "zhangsan"
        def funcB(self):
            return "function B: %s" % self.name_b
    mc = Child()
    print mc.name_b
    print mc.funcB()
    print mc.funcA()
    
    # python test.py
    zhangsan
    function B: zhangsan
    function A: xiaoming

6.8 多重继承

每个类可以拥有多个父类,如果调用的属性或方法在子类中没有,就会从父类中查找。多重继承中,是依次按顺序执行。

类简单的继承:

#!/usr/bin/python
# -*- coding: utf-8 -*-
class A:
    def __init__(self):
        self.var1 = "var1"
        self.var2 = "var2"
    def a(self):
        print "a..."
class B:
    def b(self):
        print "b..."
class C(A,B):
    pass
c = C()
c.a()
c.b()
print c.var1
print c.var2

# python test.py
a...
b...
var1
var2

类C继承了A和B的属性和方法,就可以像使用父类一样使用它。

子类扩展方法,直接在子类中定义即可:

#!/usr/bin/python
# -*- coding: utf-8 -*-
class A:
    def __init__(self):
        self.var1 = "var1"
        self.var2 = "var2"
    def a(self):
        print "a..."
class B:
    def b(self):
        print "b..."
class C(A,B):
    def test(self):
        print "test..."
c = C()
c.a()
c.b()
c.test()
print c.var1
print c.var2

# python test.py
a...
b...
test...
var1
var2

在这说明下经典类和新式类。

经典类:默认没有父类,也就是没继承类。

新式类:有继承的类,如果没有,可以继承object。在Python3中已经默认继承object类。

经典类在多重继承时,采用从左到右深度优先原则匹配,而新式类是采用C3算法(不同于广度优先)进行匹配。两者主要区别在于遍历父类算法不同,具体些请在网上查资料。

6.9 方法重载

直接定义和父类同名的方法,子类就修改了父类的动作。

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Parent():
    def __init__(self, name=‘xiaoming‘):
        self.name = name
    def func(self, age):
        return "Name: %s, Age: %s" %(self.name, age)
class Child(Parent):
    def func(self, age=22):
        return "Name: %s, Age: %s" %(self.name, age)
mc = Child()
print mc.func()

# python test.py
Name: xiaoming, Age: 22

6.10 修改父类方法

在方法重载中调用父类的方法,实现添加功能。

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Parent():
    def __init__(self, name=‘xiaoming‘):
        self.name = name
    def func(self, age):
        return "Name: %s, Age: %s" %(self.name, age)
class Child(Parent):
    def func(self, age):
        print "------"
        print Parent.func(self, age)   # 调用父类方法
        print "------"
mc = Child()
mc.func(‘22‘)
# python test.py
------
Name: xiaoming, Age: 22
------

还有一种方式通过super函数调用父类方法:

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Parent():
    def __init__(self, name=‘xiaoming‘):
        self.name = name
    def func(self, age):
        return "Name: %s, Age: %s" %(self.name, age)
class Child(Parent):
    def func(self, age):
        print "------"
        print super(Child, self).func(age)
        print "------"
mc = Child()
mc.func(‘22‘)
# python test.py
------
Traceback (most recent call last):
  File "test2.py", line 15, in <module>
    mc.func(‘22‘)
  File "test2.py", line 11, in func
    print super(Child, self).func(age)
TypeError: must be type, not classobj

抛出错误,因为super继承只能用于新式类,用于经典类就会报错。

那我们就让父类继承object就可以使用super函数了:

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Parent(object):
    def __init__(self, name=‘xiaoming‘):
        self.name = name
    def func(self, age):
        return "Name: %s, Age: %s" %(self.name, age)
class Child(Parent):
    def func(self, age):
        print "------"
        print super(Child, self).func(age)   # 调用父类方法。在Python3中super参数可不用写。
        print "------"
mc = Child()
mc.func(‘22‘)

# python test.py
------
Name: xiaoming, Age: 22
------

6.11 属性访问的特殊方法

有四个可对类对象增删改查的内建函数,分别是getattr()、hasattr()、setattr()、delattr()。

   6.11.1 getattr()

返回一个对象属性或方法。

    >>> class A:    
    ...   def __init__(self):
    ...     self.name = ‘xiaoming‘
    ...   def method(self):
    ...     print "method..."
    ...
    >>> c = A()
    >>> getattr(c, ‘name‘, ‘Not find name!‘)   
    ‘xiaoming‘
    >>> getattr(c, ‘namea‘, ‘Not find name!‘)
    >>> getattr(c, ‘method‘, ‘Not find method!‘)
    <bound method A.method of <__main__.A instance at 0x93fa70>>
    >>> getattr(c, ‘methoda‘, ‘Not find method!‘)
    ‘Not find method!‘

   6.11.2 hasattr()

判断一个对象是否具有属性或方法。返回一个布尔值。

    >>> hasattr(c, ‘name‘)    
    True
    >>> hasattr(c, ‘namea‘)
    False
    >>> hasattr(c, ‘method‘)
    True
    >>> hasattr(c, ‘methoda‘)
    False

   6.11.3 setattr()

给对象属性重新赋值或添加。如果属性不存在则添加,否则重新赋值。

    >>> hasattr(c, ‘age‘)    
    False
    >>> setattr(c, ‘age‘, 22)
    >>> c.age
    22
    >>> hasattr(c, ‘age‘)
    True

   6.11.4 delattr()

删除对象属性。

    >>> delattr(c, ‘age‘)    
    >>> hasattr(c, ‘age‘)             
    False

6.12 类装饰器

与函数装饰器类似,不同的是类要当做函数一样调用:

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Deco:
    def __init__(self, func):
       self._func = func
       self._func_name = func.__name__
    def __call__(self):
       return self._func(), self._func_name
@Deco
def f1():
    return "Hello world!"
print f1()

# python test.py
(‘Hello world!‘, ‘f1‘)

6.13 类内置装饰器

下面介绍类函数装饰器,在实际开发中,感觉不是很常用。

   6.10.1 @property

属性装饰器的基本功能是把类中的方法当做属性来访问。

在没使用属性装饰器时,类方法是这样被调用的:

    >>> class A:    
    ...    def __init__(self, a, b):
    ...      self.a = a
    ...      self.b = b
    ...    def func(self):
    ...      print self.a + self.b
    ...
    >>> c = A(2,2)
    >>> c.func()
    4
    >>> c.func
    <bound method A.func of <__main__.A instance at 0x7f6d962b1878>>

使用属性装饰器就可以像属性那样访问了:

    >>> class A:    
    ...     def __init__(self, a, b):
    ...       self.a = a
    ...       self.b = b
    ...     @property
    ...     def func(self):
    ...       print self.a + self.b
    ...
    >>> c = A(2,2)
    >>> c.func
    4
    >>> c.func()
    4
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: ‘NoneType‘ object is not callable

   6.10.2 @staticmethod

静态方法作用:可以通过类对象访问,也可以通过实例化后类对象实例访问。

实例方法的第一个参数是self,表示是该类的一个实例,称为类对象实例。

而使用静态方法装饰器,第一个参数就不用传入实例本身(self),那么这个方法当做类对象,由Python自身处理。

看看普通方法的用法:

    >>> class A:                         
    ...   def staticMethod(self):   
    ...      print "not static method..."
    ...
    >>> c = A()         
    >>> c.staticMethod()
    not static method...

使用静态方法则是这么用:

    >>> class A:                       
    ...   @staticmethod             
    ...   def staticMethod():       
    ...     print "static method..."
    ...
    >>> A.staticMethod()   # 可以通过类调用静态方法
    static method...
    >>> c = A()   
    >>> c.staticMethod()   # 还可以使用普通方法调用
    static method...

静态方法和普通的非类方法作用一样,只不过命名空间是在类里面,必须通过类来调用。一般与类相关的操作使用静态方法。

   6.10.3 @classmethod

与静态方法类似,区别在于类方法的第一个参数要传入类对象(cls):

    >>> class A:                       
    ...   @classmethod             
    ...   def classMethod(cls):   
    ...     print "class method..."
    ...     print cls.__name__
    ...
    >>> A.classMethod()
    class method...
    A

6.14 __call__方法

可以让类中的方法像函数一样调用。

>>> class A:
...   def __call__(self, x): 
...     print "call..."
...     print x
...
>>> c = A()
>>> c(123)
call...
123
>>> class A:
...   def __call__(self, *args, **kwargs):
...      print args
...      print kwargs
...
>>> c = A()
>>> c(1,2,3,a=1,b=2,c=3)
(1, 2, 3)
{‘a‘: 1, ‘c‘: 3, ‘b‘: 2}
时间: 2024-08-06 20:03:31

第六章 Python类(面向对象编程)的相关文章

perl5 第十三章 Perl的面向对象编程

第十三章 Perl的面向对象编程 by flamephoenix 一.模块简介二.Perl中的类三.创建类四.构造函数 实例变量 五.方法六.方法的输出七.方法的调用八.重载九.析构函数十.继承十一.方法的重载十二.Perl类和对象的一些注释 本章介绍如何使用Perl的面向对象编程(OOP)特性及如何构建对象,还包括继承.方法重载和数据封装等内容.一.模块简介    模块(module)就是Perl包(pachage).Perl中的对象基于对包中数据项的引用.(引用见第x章引用).详见http:

Python 3面向对象编程

这篇是计算机类的优质预售推荐>>>><Python 3面向对象编程> 编辑推荐 本书不是Python 的入门书籍,适合具有Python 基础经验的开发人员阅读.如果你拥有其他面向对象语言的经验,你会更容易理解本书的内容. 内容简介 Python 是一种面向对象的解释型语言,面向对象是其非常重要的特性.本书通过Python 的数据结构.语法.设计模式,从简单到复杂,从初级到高级,一步步通过例子来展示了Python 中面向对象的概念和原则.本书不是Python 的入门书籍,

【WPF学习】第二十六章 Application类——应用程序的生命周期

原文:[WPF学习]第二十六章 Application类--应用程序的生命周期 在WPF中,应用程序会经历简单的生命周期.在应用程序启动后,将立即创建应用程序对象,在应用程序运行时触发各种应用程序事件,你可以选择监视其中的某些事件.最后,当释放应用程序对象时,应用程序将结束. 一.创建Application对象 使用Application类的最简单方式是手动创建它.下面的示例演示了最小的程序:在应用程序入口(Main()方法)处创建名为MainWindow的窗口,并启动一个新的应用程序: 在本质

Python基础----面向对象编程介绍、类和对象

面向对象变成介绍 面向过程编程 核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西.主要应用在一旦完成很少修改的地方,如linux内核.git.apache服务器等 优点:极大的降低了程序的设计复杂度 缺点:可扩展性差,改动一个地方很可能要改多个地方,牵一发而动全身 面向对象编程:不是编程的全部,只是用来解决软件可扩展性的 核心是对象(上帝式思维),对象作为程序的基本单元,一个对象包含了数据和操作数据的函数.面向对象就是把计算

python 中面向对象编程简单总结3--定制类

声明:资源来自慕课网python学习课程,以下只是个人学习总结,仅供参考 1.Python类的特殊方法 特征:以  __ 开头并结尾的方法,比如用于print的__str__() , __getattr__(),__setattr__()等   不需要在代码中直接调用, Python的某些函数和操作符会自动调用. 可以自己定制实现,如__str__()方法 class Person(object): def __init__(self,name,gender): self.name = name

第六章 python高级功能

我们可以写一个小程序,由用户输入数据,将数据存入到列表当中,也可以将数据从列表中查询出来,但像这种操作只适合在缓冲区内进行操作,因为存储在列表中的数据,程序执行完之后,数据会立即消失,所以我们可以通过文件的操作将我们要保存的数据存到文件当中,当然这只是一种方法,实际要存储数据的话我们会选择数据库,这样更方便,那么文件与目录的操作会实现什么样的功能. 第一节    文件读写 目标: a.文件的打开和创建 b.文件读取 c.文件写入 d.内容查找和替换 e.文件删除,复制,重命名 f.目录操作 g.

python的面向对象编程

面向对象编程是一种程序的范式,它把程序看成是对不同对象的相互调用,对现实世界建立的一种模型. 面向对象编程的基本思想,类和实例.类用于定义抽象对象,实例根据类的定义被创建出来. 在python当中我们使用下面的方法来定义类(按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的.): class Python(object): pass 我们实例化方法的话呢就使用: xaioming = Python() 在面向对象之后呢我们要进行属性的设置.

python 之面向对象编程

面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度. 而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象

python之面向对象编程浅谈

1.python中的类与对象 1 Python中定义类的方式比较简单: 2 3 class 类名: 4 5 类变量 6 7 def __init__(self,paramers): 8 9 def 函数(self,...) 10 11 …... 12 13 其中直接定义在类体中的变量叫类变量,而在类的方法中定义的变量叫实例变量.类的属性包括成员变量和方法,其中方法的定义和普通函数的定义非常类似,但方法必须以self作为第一个参数. 举例: 1 >>>class MyFirstTestCl