第六章 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__ ,你可以重写。

博客地址:http://lizhenliang.blog.51cto.com and https://yq.aliyun.com/u/lizhenliang

QQ群:323779636(Shell/Python运维开发群)

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

   @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

   @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

   @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-03 08:30:57

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

讲解Python中面向对象编程的相关知识

  这篇文章主要介绍了深入讲解Python中面向对象编程的相关知识,是Python入门学习中的基础知识,需要的朋友可以参考下 Python从第一天开始就是面向对象的语言.正因为如此,创建和使用类和对象是非常地容易.本章将帮助您在使用Python面向对象编程的技术方面所有提高. 如果没有任何以往面向对象(OO)的编程的经验,那么可能要了解一些基本的入门课程就可以了,或者至少某种形式的教程,让你有了解基本概念. 但是,这里会比较少地介绍面向对象编程(OOP): OOP术语概述 类: 用户定义的原型对

《C++面向对象高效编程(第2版)》——第1章 什么是面向对象编程

第1章 什么是面向对象编程 C++面向对象高效编程(第2版)近年来,软件从业人员都将注意力转移到面向对象编程范式,甚至经理.主管和销售人员都对面向对象技术产生了浓厚的兴趣.面向对象软件俨然成为了万众瞩目的焦点,每个人孜孜以求的圣杯.面向对象到底是什么?它与我们已经使用了数十年的方法有何不同?软件开发者心存疑虑,他们认为,正是由于面向对象的出现,让他们历尽艰辛积累的技能再无用武之地.在这种情况下,理解下列内容会有所帮助: 面向对象软件开发究竟是什么?它的优点是什么?它与传统软件开发方法有何不同?它

马士兵J2SE-第六章-常用类-基本数据类型包装类、Maths类、File类

基本数据类型包装类 public class test { public static void main(String[] args) { Integer i=new Integer(100); Double d=new Double("123.456"); int j=i.intValue()+d.intValue(); float f=i.floatValue()+d.floatValue(); System.out.println(j); System.out.println(

第十六章 Python正则表达式

正则表达式在每种语言中都会有,目的就是匹配符合你预期要求的字符串. Python正则表达式主要由re库提供,拥有了基本所有的表达式. 16.1 Python正则表达式 符号 描述 示例 . 匹配除换行符(\n)之外的任意单个字符 字符串123\n456,匹配123:1.3 ^ 匹配字符串开头 abc\nxyz,匹配以abc开头的行:^abc $ 匹配字符串结尾 abc\nxyz,匹配以xyz结束的行:xyz$ * 匹配多个 hello\nword,匹配以w开头d结尾的单词:w*d + 匹配1个或

马士兵J2SE-第六章-常用类-String类、StringBuffer类、枚举ENUM

  public class test { public static void main(String[] args) { String s1="hello"; String s2="world"; String s3="hello"; System.out.println(s1==s3); s1=new String("hello"); s2=new String("hello"); System.ou

Python类及面向对象编程【转】

Python类及面向对象编程 类是用来创建数据结构和新类型对象的主要机制.本章的主题就是类,面向对象编程和设计不是本章的重点.本章假定你具有数据结构的背景知识及一定的面向对象的编程经验(其它面向对象的语言,比如java,c++).(参见第三章,类型和对象 了解对象这个术语及其内部实现的附加信息) WeiZhong补充: 这本书出版于2001年,虽然Python有极佳的向下兼容性,但我们应该学习最新的知识.本章很多地方已经明显过时,为了保证大家学到新的知识并维持这本书的完整性,我会在必要的地方说明

《Python游戏编程入门》——第1章 使用类的Python 1.1 了解Geometry程序

第1章 使用类的Python 本章是Python的一个快速介绍,接触到基本的面向对象编程知识,并帮助读者感受Python语言看上去略有些奇怪的语法.Python既是一种工具,也是一种语言. 根据Python标准,它包括了代码的语法和格式.工具是Python安装时所带的一个软件包,其中包括一个编辑器.这些内容对于第1章来说有点厚重.如果这是你第一次接触Python语言,不要被本章的学习步伐给落下,我们马上会介绍一些重要的细节,但是,本书不会随着后面的每一章而变得越来越难.在本章中,你将学到: 如何

【Python之旅】第四篇(三):Python面向对象编程详解

终于是来到了Python的面向对象编程,以前是没有接触过其它的面向对象编程的语言,因此学习这一部分是相当带劲的,这里也总结一下. 1.面向对象编程的相关名词及解释     世界万物,皆可分类,一切皆为对象.     所谓的面向对象编程,指的是一种编程的思想,通过对具体代码实现过程(面向过程编程)的不断抽象,以形成一个个的类别,以提高我们进行大型程序编写的效率(面向对象的具体实现需要面向过程,大型程序也可以用面向过程来编写,只是比较麻烦).对于面向对象编程的相关名词和解释如下: 对象 :类的实体\

php面向对象编程的封装性

封装的概念 封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作. 例:在人这个类中,人的年龄和工资是隐私的 <?php class Person{ public $name; private $age; private $salary; function __construct($name,$age,$salary){ $this->name=$name; $this->age=$name; $this-&