喵吉欧尼酱

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::
面向对象的编程
    面向过程的编程:根据操作数据的函数或语句块来设计程序的。
    面向对象的编程:把数据和功能结合起来, 用称为对象的东西包裹起来组织程序的方法。
    类和对象是面向对象编程的两个主要方面。“类”创建一个新类型, 而“对象”是这个类的实例。
    域:属于一个对象或类的变量。
    方法:属于类的函数, 被称为类的方法。
    域和方法可以合称为类的属性。
    域有两种类型——属于每个实例/类的对象或属于类本身。它们分别被称为实例变量和类变量。
    类使用class关键字创建。类的域和方法被列在一个缩进块中。

self 参数
    类的方法与普通的函数只有一个特别的区别——它们“必须”有一个额外的第一个参数名称, 但是在调用这个方法的时候你不为这个参数赋值, Python会提供这个值。这个特别的变量指对象本身, 按照惯例它的名称是self。
    虽然你可以给这个参数任何名称, 但是“强烈建议”使用self这个名称——其他名称都是不赞成使用的。
    使用一个标准的名称有很多优点——1.方便别人阅读;2.有些IDE(集成开发环境)也可以帮助你。
    Python中的self等价于C++中的self指针和Java、C#中的this参考。

    例:
    class Person:
        def sayHi(self):  # self参数必须写
            print('Hello, how are you?')

    p = Person()
    p.sayHi() # self参数不需赋值
    print(p)  # 打印: <__main__.Person instance at 0xf6fcb18c>   (已经在__main__模块中有了一个Person类的实例)


类的变量和对象的变量
    类的变量: 由一个类的所有对象(实例)共享使用。当某个对象对类的变量做了改动的时候, 这个改动会反映到所有其他的实例上。
    对象的变量: 由类的每个对象/实例拥有。它们不是共享的, 在同一个类的不同实例中, 虽然对象的变量有相同的名称, 但是是互不相关的。
    使用的数据成员名称以“双下划线前缀”且不是双下划线后缀,比如__privatevar, Python的名称管理体系会有效地把它作为私有变量。
    惯例: 如果某个变量只想在类或对象中使用, 就应该以单下划线前缀。而其他的名称都将作为公共的, 可以被其他类/对象使用。

    例:
    class Person:
        '''Represents a person.'''
        population = 0 # 类的变量

        def __init__(self, name):
            '''Initializes the person's data.'''
            # 每创建一个对象都增加1
            Person.population += 1 # 调用类的变量,必须用 类名.变量名,如果写 self.变量名 则是对象的变量了
            self.name = name # 对象的变量,每个对象独立的
            print('(Initializing %s) We have %d persons here.' % (self.name, Person.population))

        def __del__(self):
            '''I am dying.'''
            print('%s says bye.' % self.name)
            Person.population -= 1

        def sayHi(self):
            self.__sayHi2() # 调用私有方法,外部不能调用的

        # 以双下划线开头(但没有双下划线结尾),则变成私有,仅供内部调用
        def __sayHi2(self): # 使用 self.population 也可以读取类的变量,只是改变的时候却只改变对象的变量
            print('Hi, my name is %s. We have %d persons here.' % (self.name, self.population))

    swaroop = Person('Swaroop')
    swaroop.sayHi() # 打印: Swaroop, 1

    kalam = Person('Abdul Kalam')
    kalam.sayHi() # 打印: Abdul Kalam, 2

    swaroop.sayHi() # 打印: Swaroop, 2
    print(Person.population) # 打印: 2
    del swaroop # 调用对象的 __del__ 方法
    print(Person.population) # 打印: 1

    print(Person.__doc__) # 打印类的docstring
    print(Person.__init__.__doc__) # 打印类的方法的docstring


对象序列化
    class A(object):
        a = 5

        # 如果 __repr__、 __str__、 __unicode__ 只想写一个的话,建议写 __repr__,因为 str/unicode/repr 函数都会调用到
        def __repr__(self):return 'repr:%s' % self.a

        def __str__(self):return 'str:%s' % self.a

        def __unicode__(self):return 'unicode:%s' % self.a

    a = A()
    print str(a) # 先 __str__, 再找 __repr__, 没有就用 object 默认的
    print unicode(a) # 先 __unicode__, 再找 __str__, 再找 __repr__, 没有就用 object 默认的
    print repr(a) # 先 __repr__, 没有就用 object 默认的



特殊的方法
__init__ 方法
    创建完对象后调用, 对当前对象的实例的一些初始化, 无返回值
    注意, 这个名称的开始和结尾都是双下划线。( __init__ 方法类似于C++、C#和Java中的 constructor )

__new__ 方法
    创建对象时调用, 返回当前对象的一个实例


    例:
    class Person:
        def __init__(self, name):
            self.test_name = name
        def sayHi(self):
            print('Hello, my name is ' + self.test_name)
            self.test = 'sss'  # 属性可以随处定义,不需事先定义
            print('the test is ' + self.test)

    p = Person('Swaroop')
    p.sayHi() # 打印: Swaroop , sss
    print('the Person test is ' + p.test) # 打印: sss
    p.test2 = 'haha...'
    print('the Person test2 is ' + p.test2) # 打印: haha...

    名称   说明
    __init__(self,...) 这个方法在新建对象恰好要被返回使用之前被调用。
    __del__(self) 在对象要被删除之前调用。如使用 del 删除时。
    __str__(self) 在我们对对象使用 print 语句或是使用 str() 的时候调用。
    __lt__(self,other) 当使用 小于 运算符 (<) 的时候调用。
    __gt__(self,other) 当使用 大于 运算符 (>) 的时候调用。
    __eq__(self,other) 当使用 等于 运算符 (==) 的时候调用。
    __ne__(self,other) 当使用 不等于 运算符 (!=) 的时候调用。
    __le__(self,other) 当使用 小于等于 运算符 (<=) 的时候调用。
    __ge__(self,other) 当使用 大于等于 运算符 (>=) 的时候调用。
    __add__(self,other)当使用 加 运算符 (+) 的时候调用。
    __getitem__(self,key) 使用x[key]索引操作符的时候调用。
    __len__(self) 对序列对象使用内建的 len() 函数的时候调用。


类变量,容易出错的:
    ##### 范例1, 错误示范 #####
        class A(object):
            x = 1

        class B(A):
            pass

        class C(A):
            pass

        # 初始化正常
        print(A.x, B.x, C.x) # 打印: 1 1 1

        # 改变类变量的值,也正常
        B.x = 2
        print(A.x, B.x, C.x) # 打印: 1 2 1

        # 下面就晕菜了,怎么改变 A 会影响 C,而又不影响 B ?
        A.x = 3
        print(A.x, B.x, C.x) # 打印: 3 2 3


    ##### 解说 范例1 #####
        python 的类变量是存放在一个内部处理的字典中,这字典通常被称为方法解析顺序(Method Resolution Order, 缩写为 MRO)
        所以, 在上面的代码中, 由于属性 x 未能在 C 类中找到, 它会被抬起到其父类中查找(即 A 类)。换句话说, C 不具有自己独立于 A 的 x 属性。
        所以, C.x 其实是一个 A.x 的引用。而 B.x 被赋值过,所以它有自己的 x 属性了。

        #### 把上面的 x 属性是否在类的 __dict__ 判断打印出来,会更容易理解 ####
        class A(object):
            x = 1

        class B(A):
            pass

        class C(A):
            pass

        # A 类里面有 x 属性, 而 B、C 类里面没有, B、C 类得去到父类里面才能找到这个属性
        print(A.x, B.x, C.x) # 打印: 1 1 1
        print('x' in A.__dict__, 'x' in B.__dict__, 'x' in C.__dict__) # 打印: True, False, False

        # B 类赋值了一个 x 属性, 所以有了自己独立于 A 类的 x 属性
        B.x = 2
        print(A.x, B.x, C.x) # 打印: 1 2 1
        print('x' in A.__dict__, 'x' in B.__dict__, 'x' in C.__dict__) # 打印: True, True, False

        # 改变了 A 类的 x 属性的值, C 类里面由于没有这个属性, 所以得用 A 类的。 B 类有自己独立的 x 属性,就用自己的了。
        A.x = 3
        print(A.x, B.x, C.x) # 打印: 3 2 3
        print('x' in A.__dict__, 'x' in B.__dict__, 'x' in C.__dict__) # 打印: True, True, False

 

posted on 2017-08-19 10:18  喵吉欧尼酱  阅读(97)  评论(0)    收藏  举报