python进阶-- 03 面向对象编程

1.定义

1.1类定义

在Python中,类通过 class 关键字定义。

按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。

class Person(object): # python 2语法

# class Person(): # python3语法

    pass

1.2实例创建

创建实例使用 类名+(),类似函数调用的形式创建。

xiaoming = Person()

xiaohong = Person()

2属性

2.1添加实例属性

由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值,该属性不必在类中声明。

class Person(object):

    pass

p1 = Person()

p1.name = 'Bart'

p2 = Person()

p2.name = 'Adam'

p3 = Person()

p3.name = 'Lisa'

2.2.初始化实例属性

虽然我们可以自由地给一个实例绑定各种属性,但是,现实世界中,一种类型的实例应该拥有相同名字的属性。

在定义 Person 类时,可以为Person类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用,我们就能在此为每个实例都加上统一属性

举例

class Person(object):

    def __init__(self, name, gender, birth):

        self.name = name

        self.gender = gender

        self.birth = birth

2.3.内部属性(私有属性)实现

如果一个属性由双下划线开头(__),该属性就无法被外部访问

但是,如果一个属性以"__xxx__"的形式定义,那它又可以被外部访问了,以"__xxx__"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"__xxx__"定义。

单下划线开头的属性"_xxx"也可以被外部访问。

重要:即使该私有属性与后来实例绑定的属性同名,并且后来实例的属性被改变,该私有属性也不会改变。

>>> class test_c(object):

         def __init__(self):

                   self.__test=3

         def get_test_a(self):

                   return self.__test

         test_a=property(get_test_a)

         @property

         def test_b(self):

                   return "bbb"

>>> a=test_c()

>>> a.test_a

3

>>> a.__test=5

>>> a.test_a

3

2.4类属性

2.4.1概念

在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。

2.4.2特点

由于Python是动态语言,类属性也是可以动态添加和修改的

因为类属性只有一份,所以,Person类的address改变时,所有实例访问到的类属性都改变了。

2.4.3定义

定义类属性可以直接在 class 中定义:

#给 Person 类添加一个类属性 count,每创建一个实例,count 属性就加 1,这样就可以统计出一共创建了多少个 Person 的实例。

class Person(object):

    count=0

    def __init__(self,name):

        Person.count+=1

        self.name=name

2.4.4类属性与实例属性冲突问题

当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。

使用实例来修改类属性是错误的,因为你的修改相当于给实例绑定了一个实例属性而已,并没有改变类属性的值。

class Person(object):

    address = 'Earth'

    def __init__(self, name):

        self.name = name

p1 = Person('Bob')

p2 = Person('Alice')

print 'Person.address = ' + Person.address

p1.address = 'China'

print 'p1.address = ' + p1.address

print 'Person.address = ' + Person.address

print 'p2.address = ' + p2.address

2.4.5类属性的__xx

直接使用“类名.__类属性名”访问无法访问到

使用“类对象._类名__类属性名”可以访问到

3.方法

3.1实例方法

定义

实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的。

def 实例方法名(self,参数1,参数2,...):

    方法块

调用

实例.实例方法名(参数1,参数2,...) #self不需要显式传入

3.2动态将方法添加到实例上

因为方法也是一个属性,所以,它也可以动态地添加到实例上(只是添加到了此实例上,一般不用)。

import types

def fn_get_grade(self):

    if self.score >= 80:

        return 'A'

    if self.score >= 60:

        return 'B'

    return 'C'

class Person(object):

    def __init__(self, name, score):

        self.name = name

        self.score = score

p1 = Person('Bob', 90)

p1.get_grade = types.MethodType(fn_get_grade, p1, Person)

print p1.get_grade()

# => A

p2 = Person('Alice', 65)

print p2.get_grade()

# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'

# 因为p2实例并没有绑定get_grade

3.3类方法

3.3.1定义

通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例;

类方法的第一个参数将传入类本身,通常将参数名命名为 cls;

3.3.2特点

因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。类方法一般用来处理内部类变量。

3.3.3举例

下面的 cls.count 实际上相当于 Person.count。

class Person(object):

    __count = 0

    @classmethod

    def how_many(cls):

        return cls.__count

    def __init__(self,name):

        self.name=name

        Person.__count +=1

print Person.how_many()

p1 = Person('Bob')

print Person.how_many()

4.继承

4.1定义

新类不用重头编写

新类从现有的类继承,就自动拥有了现有类的所有功能

新类只需编写现有类缺少的功能

父类/基类/超类---子类/派生类/继承类

4.2优点

复用已有代码

自动拥有现有类的所有功能

只需编写缺少的新功能

4.3特点

子类 is a 父类 (学生 is a 人)

Python的任何类必须继承于某个类

不要忘记调用super(subClass,self).__init__(*args) # args不能再写self

4.4举例

class Person(object):

    def __init__(self, name, gender):

        self.name = name

        self.gender = gender

class Teacher(Person):

    def __init__(self, name, gender, course):

        # 此处也可以写成Person.__init__(self,name,gender)

        super(Teacher,self).__init__(name,gender) # python2.7语法

  # super().__init__(name,gender) # python3语法

        self.course=course

4.5isinstance()判断类型

可用来判断某个对象是否为某类型。

注:一个对象是某子类类型,一定也是该子类的父类对应的类型。

isinstance(object, class-or-type-or-tuple) -> bool

# 详见python基础-- 06 函数

4.6多重继承

多重继承的目的是从两种继承树中分别选择并继承出子类,以便组合功能使用

举个例子,Python的网络服务器有TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer,而服务器运行模式有 多进程ForkingMixin 和 多线程ThreadingMixin两种。

要创建多进程模式的 TCPServer:

class MyTCPServer(TCPServer, ForkingMixin)

    pass

要创建多线程模式的 UDPServer:

class MyUDPServer(UDPServer, ThreadingMixin):

    pass

如果没有多重继承,要实现上述所有可能的组合需要 4x2=8 个子类

5.多态

5.1定义

1.一般地(如JAVA中),父类具有某方法,其子类通过不同实现,实现了该方法,是多态;

2.由于Python是动态语言,所以,传递给多态方法的参数 x 不一定是父类或基类类型。任何数据类型的实例都可以,只要它有一个与多态方法同样名字的方法即可。

5.2原理

1.一般地(如JAVA中),方法调用将作用在 x 的实际类型上。s 是Student类型,它实际上拥有自己的 whoAmI()方法以及从 Person继承的 whoAmI方法,但调用 s.whoAmI()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止;

2. 由于Python是动态语言,所以,传递给多态方法的参数 x 不一定是父类或基类类型。任何数据类型的实例都可以,只要它有一个与多态方法同样名字的方法即可。

5.3动态语言的多态

动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。

理解:

Python提供了open()函数来打开一个磁盘文件,并返回 File 对象。File对象有一个read()方法可以读取文件内容:

例如,从文件读取内容并解析为JSON结果:

import json

f = open('/path/to/file.json', 'r')

print json.load(f)

由于Python的动态特性,json.load()并不一定要从一个File对象读取内容。任何对象,只要有read()方法,就称为File-like Object,都可以传给json.load()。

import json

class Students(object):

    def __init__(self):

        pass

    def read(self):

        return r'["Tim", "Bob", "Alice"]'

s = Students()

print json.load(s)

# result: [u'Tim', u'Bob', u'Alice']

6.类中常用函数

6.1setattr()

         setattr(object, name, value)

         用来设置对象的属性,详细使用help(setattr)查看

原文地址:https://www.cnblogs.com/yc913344706/p/7749416.html