一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

python面向对象的学习笔记

时间:2015-03-24 编辑:简简单单 来源:一聚教程网


创建类:


#!/usr/bin/python
# Filename: simplestclass.py
 
class Person:
    pass # An empty block
 
p = Person()
print p
$ python simplestclass.py
<__main__.Person instance at 0xf6fcb18c>

我们使用类名后跟一对圆括号来创建一个对象/实例。为了验证,我们简单地打印了这个变量的类型。它告诉我们我们已经在__main__模块中有了一个Person类的实例。
可以注意到存储对象的计算机内存地址也打印了出来。这个地址在你的计算机上会是另外一个值,因为Python可以在任何空位存储对象。

对象中的方法

我们已经讨论了类/对象可以拥有像函数一样的方法,这些方法与函数的区别只是一个额外的self变量。现在我们来
学习一个例子。


#!/usr/bin/python
# Filename: method.py
 
class Person:
    def sayHi(self):
        print 'Hello, how are you?'
 
p = Person()
p.sayHi()
$ python method.py
Hello, how are you?

这里我们看到了self的用法。注意sayHi方法没有任何参数,但仍然在函数定义时有self。

__init__方法:

__init__方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的 初始化 。


#!/usr/bin/python
# Filename: class_init.py
 
class Person:
    def __init__(self, name):
        self.name = name
    def sayHi(self):
        print 'Hello, my name is', self.name
 
p = Person('Swaroop')
p.sayHi()
$ python class_init.py
Hello, my name is Swaroop

类与对象的方法

我们已经讨论了类与对象的功能部分,现在我们来看一下它的数据部分。事实上,它们只是与类和对象的名称空间 绑定 的普通变量,即这些名称只在这些类与对象的前提下有效。
有两种类型的 域 ——类的变量和对象的变量,它们根据是类还是对象 拥有 这个变量而区分。
类的变量 由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。
对象的变量 由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。通过一个例子会使这个易于理解。

使用类与对象的变量


#!/usr/bin/python
# Filename: objvar.py
 
class Person:
    '''Represents a person.'''
    population = 0
 
    def __init__(self, name):
        '''Initializes the person's data.'''
        self.name = name
        print '(Initializing %s)' % self.name
 
        # When this person is created, he/she
        # adds to the population
        Person.population += 1
 
    def __del__(self):
        '''I am dying.'''
        print '%s says bye.' % self.name
 
        Person.population -= 1
 
        if Person.population == 0:
            print 'I am the last one.'
        else:
            print 'There are still %d people left.' % Person.population
 
    def sayHi(self):
        '''Greeting by the person.
 
        Really, that's all it does.'''
        print 'Hi, my name is %s.' % self.name
 
    def howMany(self):
        '''Prints the current population.'''
        if Person.population == 1:
            print 'I am the only person here.'
        else:
            print 'We have %d persons here.' % Person.population
 
swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()
 
kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()
 
swaroop.sayHi()
swaroop.howMany()
$ python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one.

使用继承:


#!/usr/bin/python
# Filename: inherit.py
 
class SchoolMember:
    '''Represents any school member.'''
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print '(Initialized SchoolMember: %s)' % self.name
 
    def tell(self):
        '''Tell my details.'''
        print 'Name:"%s" Age:"%s"' % (self.name, self.age),
 
class Teacher(SchoolMember):
    '''Represents a teacher.'''
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)
        self.salary = salary
        print '(Initialized Teacher: %s)' % self.name
 
    def tell(self):
        SchoolMember.tell(self)
        print 'Salary: "%d"' % self.salary
 
class Student(SchoolMember):
    '''Represents a student.'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)
        self.marks = marks
        print '(Initialized Student: %s)' % self.name
 
    def tell(self):
        SchoolMember.tell(self)
        print 'Marks: "%d"' % self.marks
 
t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)
 
print # prints a blank line
 
members = [t, s]
for member in members:
    member.tell() # works for both Teachers and Students
$ python inherit.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)

Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"22" Marks: "75"

Python不会自动调用基本类的constructor

Python面向对象特征总结


一、封装

面向对象程序设计中的术语对象(Object)基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。传统意义上的“程序=数据结构+算法”被封装”掩盖“并简化为“程序=对象+消息”。对象是类的实例,类的抽象则需要经过封装。封装可以让调用者不用关心对象是如何构建的而直接进行使用。

一个简单的Python类封装如下:


Encapsulation
 

上面简单的示例代码可以看出,Python中的类包含了一般面向对象编程语言的主要元素,比如构造方法、绑定方法、静态方法、属性等,如果深入下去,还可以发现Python中内置了很多面向对象的“高级”主题,比如迭代器、反射、特性等等,提供了封装的直接构造要素。

 

二、继承

1、类继承

继承给人的直接感觉是这是一种复用代码的行为。继承可以理解为它是以普通的类为基础建立专门的类对象,子类和它继承的父类是IS-A的关系。一个简单而不失经典的示例如下:


Inheritance
 

一个显而易见的特点是,Python的面向对象的继承特征是基于类(class)的,比javascript基于原型(prototype)的继承更容易组织和编写代码,也更容易让人接受和理解。

ps:最近几天Anders大神搞出来的TypeScript横空出世,看它的语言规范里继承也是基于类的:


TypeScript-SimpleInheritance
 

感觉基于类的继承的语言好像在实现OO的可读性和编程体验上都不太差,据传说javascript是码农最想喷也是喷过最多f**k的语言。

2、多重继承

不同于C#,Python是支持多重类继承的(C#可继承自多个Interface,但最多继承自一个类)。多重继承机制有时很好用,但是它容易让事情变得复杂。一个多重继承的示例如下:


MultInheritance
 

如你所看到的那样,多重继承的好处显而易见,我们可以轻而易举地通过类似“组合”的方式复用代码构造一个类型。

有个需要注意的地方,即如果一个方法从多个超类继承,那么务必要小心继承的超类(或者基类)的顺序:


MultInheritance
 

我们为动物和机器各实现一个相同名称的move方法,但是输出因为继承的顺序而有所不同,Python在查找给定方法或者特性时访问超类的顺序被称为MRO(Method Resolution Order,方法判定顺序)。

三、多态

多态意味着可以对不同的对象使用同样的操作,但它们可能会以多种形态呈现出结果。在Python中,任何不知道对象到底是什么类型,但又需要对象做点什么的时候,都会用到多态。

能够直接说明多态的两段示例代码如下:

1、方法多态


Method-Polymorphism
 

对于一个临时对象obj,它通过Python的随机函数取出来,不知道具体类型(是字符串、元组还是自定义类型),都可以调用count方法进行计算,至于count由谁(哪种类型)去做怎么去实现我们并不关心。

有一种称为”鸭子类型(duck typing)“的东西,讲的也是多态:


DuckTyping
就in_the_forest函数而言,参数对象是一个鸭子类型,它实现了方法多态。但是实际上我们知道,从严格的抽象来讲,Person类型和Duck完全风马牛不相及。

2、运算符也多态


Operator-Polymorphism
 

上例中,显而易见,Python的加法运算符是”多态“的,理论上,我们实现的add方法支持任意支持加法的对象,但是我们不用关心两个参数x和y具体是什么类型。

一两个示例代码当然不能从根本上说明多态。普遍认为面向对象最有价值最被低估的特征其实是多态。我们所理解的多态的实现和子类的虚函数地址绑定有关系,多态的效果其实和函数地址运行时动态绑定有关。在C#中实现多态的方式通常有重写和重载两种,从上面两段代码,我们其实可以分析得出Python中实现多态也可以变相理解为重写和重载。在Python中很多内置函数和运算符都是多态的。

号外:在C#中,我们熟知接口(Interface)和多态相关,在处理多态对象时,只要关心它的接口(或者称为“协议”)而不需要显式指定特定实现类型即可,这也是IoC中面向接口(抽象)而不依赖于具体实现编程的基础。可惜在Python中根本没有Interface(有抽象类)。而在TypeScript的Specification中引入了Interface的概念:


TypeScript-Interface
 

TypeScript语言规范里对Interface的定义是命名的对象类型(Programmers can give names to object types; we call named object types interfaces. )。它直接等价于下面的Ojbect Type:

var Friend: () => {
    name: string; favoriteColor?: string;
};
上面这个Object Type在Playgound中等价的javascript代码如下:

var Friend;
在TypeScript编程规范文档里,对Interface的一些说明:

Interfaces provide the ability to give names to object types and the ability to compose existing named object types into new ones.
Interfaces have no run-time representation—they are purely a compile-time construct. Interfaces are particularly useful for documenting and validating the required shape of properties, objects passed as parameters, and objects returned from functions.

Interface可以继承自Interface:


TypeScript-InterfaceInheritInterface
 

我们尝试让类继承自Interface:


interface Mover
{
    move(): void;
}

class SimpleMover  extends Mover{
    move() {
  alert("move")
    }
 
 
}

var mover=new SimpleMover();
mover.move();
 

实践证明类是不能继承实现Interface的:A export class may only extend other classes, Mover is an interface.

现在大家知道TypeScript里的Interface和我们所认识和理解的接口的区别了吗?相同的一个名词Interface,不同语境下意义并不完全相同,看上去好像是挺傻的,但是学习和使用语言不做对比几乎是不可能的。

热门栏目