首页 > 代码库 > 13.面向对象编程

13.面向对象编程

1、前言

前面一直是语法与面向过程编程,这张我们来学oop


2、直接开搞,python中如何创建一个类?

答: 用到关键字 class, 类名是MyFirst 括号的是 扩展的基类object

class MyFirst(object):
    'my first class' #类也有文档字符串哦
    foo = 100

3、静态变量(名字翻译好多:静态属性、类变量、静态数据)

class MyFirst(object):
    'my first class' #类也有文档字符串哦
    foo = 100


print(MyFirst.foo)
foo就是个静态变量………………

概念:它是属于类的,与类的实例对象无关,调用的时候用  类名.静态变量 


4、方法

在类中的定义的函数,准确的说在python中叫方法(又称实例方法、对象方法)

class MyFirst(object):
    'my first class' #类也有文档字符串哦
    foo = 100

    def myNoActionMethod(self):  #self代表当前的类的实例对象,好吧,注意与普通函数的语法区别
        pass


5、怎么调用方法呢?

first = MyFirst()   #这里是得到MyFirst的一个实例对象 ,将引用赋值给变量first
first.myNoActionMethod()
当然首先要得到实例对象,然后  通过 . 调用方法

class MyFirst(object):
    'my first class' #类也有文档字符串哦
    foo = 100

    def myNoActionMethod(self):
        print("我是一个方法")

first = MyFirst() 
first.myNoActionMethod()
输出结果:

>>> 
我是一个方法

6、类特殊的静态变量

C.__name__ 类C的名字(字符串)
C.__doc__ 类C的文档字符串
C.__bases__ 类C的所有父类构成的元组
C.__dict__ 类C的属性
C.__module__ 类C定义所在的模块(1.5 版本新增)
C.__class__ 实例C对应的类(仅新式类中)


7、初始化一个类的实例对象

前面我们已经进行过初始化了,这里再总结下:

first = MyFirst() #在python中就是这么简单………… java中得用new哦


8、__init__(), 构造方法(还有其它名字:构造器,初始器,中文博大精深)

当类被调用时,咱们就去搞实例对象,python会检查是否实现了__init__()方法。

默认情况:如果没有定义或者叫做覆盖(重写)构造方法 __init__(),那就使用默认的,也就是说一个类肯定是有__init()__,没有重写,不代表没有,只是使用默认的。

重写情况:如果你重写了__init()__构造方法,那你创建一个实例对象的时候,就会调用你写的__init()__。


9、__new__(),又一个特殊的方法,先不说了,先知道有它就行


10、__del__(),该方法用于释放实例对象占用的内存,好吧,强行把实例对象占用的内存释放掉………………也是先知道即可…………


11、来个例子吧,包含__init__(), __new__()、__del__()………………叫停吧,书上的例子…慢慢深入


12、又谈到了如果计算一个类创建多少个实例对象,好家伙……用静态变量记录

上栗子:

class Person(object):
    count = 0

    def __init__(self): #构造方法
        Person.count = Person.count + 1

    def __del__(self):  #显示释放一个实例对象的方法
        Person.count -= 1

    def howManyObject(self):
        return Person.count



one = Person()
print(one.howManyObject())
例子重写两个特殊方法,用了一个类变量存储创建实例对象的数量


13、实例变量(又称:实例属性、对象变量)我的妈啊,被翻译就能折腾死是吧,呵呵

上例子:

class HotelRoom(object):
    'Hotel room rate calculator'


    def __init__(self, rt, sales = 0.085, rm = 0.1):   #构造方法,第一个self代表当前实例对象,这个不用传入,一个必选参数rt,两个默认值参数sales与rm
        '''HotelRoom default arguments: 
        sales tax == 8.5% and room tax == 10%'''   #首行的文档字符串
        self.salesTax = sales  #实例变量salesTax
        self.roomTax = rm      #实例变量roomTax
        self.roomRate = rt     #实例变量roomRate

    def calcTotal(self, days = 1): #一个实例方法,第一个参数self,代表当前实例对象,第二个是默认值参数days
        'Calculate total: default to daily rate'
        daily = round((self.roomRate * (1 + self.roomTax + self.salesTax)), 2) #这里还调用了实例变量roomRate、roomTax、salesTax
        return float(days) * daily


sfo = HotelRoom(29)   #得到一个HotelRoom实例对象,将调用__init__()方法,因为构造方法有个必选参数,所以我们必须传入一个参数,这里传入参数为29
print(sfo.calcTotal(10)) #调用实例方法calcTotal,然后再调用print()函数


14、强调了__init__()不可返回其他对象

class Dog(object):

    def __init__(self):
        return 1

myDog = Dog()
输出结果:

Traceback (most recent call last):
  File "D:/temp/Dog.py", line 11, in <module>
    myDog = Dog()
TypeError: __init__() should return None, not 'int'
>>> 
因为构造器只能返回实例对象,返回不是None的实例对象都会抛出异常TypeError,也就是说不要用return


15、又一次强调 dir()函数可以返回所有的类变量(返回的集合是List)、 __dirt__可以看到所有的实例变量(返回的集合是字典)


16、类变量(静态变量)再谈……

例子:

class Dog(object):
    eat = 'meat'

    def __init__(self):
        pass



myDog = Dog()
print(Dog.eat)    #通过类名
print(myDog.eat)  #通过实例对象的引用
类变量:可以通过类名访问、也可以用实例对象访问( 这里与java是一致哦)

不建议通过实例对象去访问类变量(java里也一样不建议这么做,你只需要知道即可)


17、self小结

self是什么?

答:任何一个实例方法定义中的第一个参数都是变量self,它表示调用此实例方法的实例对象


18、插一句啊,如果你的类没有继承任何类,那么默认继承的是object,所以你可以省略(ojbect),下面这俩是一样的…………

class Dog:
    eat = 'meat'

    def __init__(self):
        pass


class Dog(object):
    eat = 'meat'

    def __init__(self):
        pass



19、哈哈,终于到静态方法(又称类方法),等的哥哥花都快谢了…………

静态方法:类中的函数,属于类,不需要实例对象哦,就可以使用哦,亲爱的……


旧版本的python是这么创建静态方法的,看例子:

class TestStatic:

    def foo():
        print("foo()")

    foo = staticmethod(foo) #利用staticmethod函数将foo函数变为静态方法,然后把函数引用赋值给foo

TestStatic.foo() # 利用类直接调用,算是正统

my = TestStatic()

my.foo() #当然实例对象也可以调用静态方法,同样我们不推荐这样使用,你只需知道这种方式可以即可


另外一种方式,看例子:

class TestStatic2:

    def foo(cls):
        print("I am the best")


    foo = classmethod(foo) #利用classmethod函数将foo函数变为类方法,嘿嘿


20、python2.4以后静态方法的创建,我们当然直接用高大上的函数修饰符(又称作函数装饰器………………中文博大精深,翻译一会一个名字对于新人来说,越搞越混乱)

上栗子:

例子A

class TestStatic2:

    @staticmethod #高大上的函数修饰符,又叫装饰器
    def foo():
        print("I am the best")


例子B

class TestStatic2:

    @classmethod #用这个函数修饰符,也可,不过要注意有cls参数
    def foo(cls): #<span style="color:#ff0000;">注意这里的cls参数</span>
        print("I am the best")


21、组合……代码复用的精髓,这个要慢慢体会的哦,亲

这里的类与类之间的关系,称为 has a…………


22、派生(又称继承),也是代码复用的精髓,也要慢慢体会哦,亲

这里的关系称作:is a………………


23、来吧,python怎么创建子类呀?怎么玩继承啊?

答:python支持多继承

class Man(Person, Thinking): #类Man, 继承自Person、Thinking
    pass


24、来个继承经典例子,这里不懂,就代表你还不明白面向对象

class Parent(object):    #定义一个Parent类   扩展自object

    def printParent(self):
        print ('they are parents')


class Child(Parent):        #定义Child类扩展自Parent

    def printChild(self):
        print("hello child")


par = Parent()  #先来个Parent实例对象
par.printParent()  #调用Parent的实例方法

chi = Child()   #再来个Child实例对象
chi.printChild() #调用Child实例方法


chi2 = Child() #再整个Child实例对象
chi2.printParent()  #调用Parent的实例方法  


25、好吧,直接上重写吧(overriding)

class Father(object):

    def eat(self):
        print("老爹吃肉")




class Son(Father):

    def eat(self):   #俺们把从Father那里得到eat方法,又重写了,所以输出结果必然是……往下看
        print("儿子吃素")



s = Son()
s.eat()
输出结果:

>>> 
儿子吃素

疑问1:那我还想调用父类的eat方法呢?怎么办呢?

s = Son()
s.eat() #这里调用的eat方法

Father.eat(s)  #这里调用了父类的eat方法 不推荐这么用啊


疑问2:我想在子类重写的方法里直接调用父类的原方法呢?

建议用super

class Father(object):

    def eat(self):
        print("老爹吃肉")


class Son(Father):

    def eat(self):
        super(Son, self).eat() #利用super函数可以办到 哈哈
        print("儿子吃素")


也可以这样(不建议使用这个):

class Father(object):

    def eat(self):
        print("老爹吃肉")


class Son(Father):

    def eat(self):
        Father.eat(self)
        print("儿子吃素")


26、继承体系下的__init__()方法,python中,不会硬性要求你必须调用父类的构造器,如果你没有调用,python可不会帮你调用哦。 这里和java可不一样

class Father(object):

    def walk(self):
        print("new Father().walk(self)")

    def __init__(self):
        print("老子构造方法")


class Son(Father):

    def __init__(self):
        print("儿子构造方法")



s = Son()
输出结果:

>>> 
儿子构造方法


因为python坑爹的就是不会要求你调用父类的构造器,你如果想的话


显式的调用父类的构造器:

class Father(object):

    def walk(self):
        print("new Father().walk(self)")

    def __init__(self):
        print("老子构造方法")


class Son(Father):

    def __init__(self):
        super(Son, self).__init__() #这里利用super函数,显示的调用父类的构造器,好吧,赞赞啊
        print("儿子构造方法")



s = Son()

27、python从2.2版本开始支持从 基本数据类型扩展子类、即 float int等等,先给老子知道这里就可以。


28、又谈到了多重继承,python啊python,你咋这牛逼呢?慢慢深入吧,一时半会不可能的………………


29、内建函数…………介绍…………一堆,慢慢深入

issubclass() 布尔函数判断一个类是另一个类的子类或子孙类。它有如下语法:

issubclass(sub, sup)


isinstance() 布尔函数在判定一个对象是否是另一个给定类的实例时,非常有用。它有如下

语法:
isinstance(obj1, obj2)


30、后面还有好多高级特性吧、什么 访问控制的 __ 、 _,哈哈,没事我会战胜苦难的,还有元类……还有…………总之类这里绝对没有那么简单,本章我们告一段落……………………………………………………………………加油…………………………深入…………………………


很喜欢这个函数……

def foo(data):
    if isinstance(data, int):
        print 'you entered an integer'
    elif isinstance(data, str):
        print 'you entered a string'
    else:
        raise TypeError, 'only integers or strings!' #raise用于抛出异常, 类似与java中的throw

























13.面向对象编程