Python面向对象编程


  1. 类相关知识
  2. 对象相关知识
  3. 类属性增删改查
  4. 实例属性增删改查
  5. 对象与实例属性
  6. 静态属性
  7. 类方法
  8. 静态方法
  9. 组合
  10. 继承
  11. 接口设计与归一化设计
  12. 继承顺序之mro线性顺序列表
  13. Python2中的继承顺序
  14. 子类调用父类的方法
  15. super调用父类的方法
  16. 多态
  17. 封装
  18. 反射
  19. 动态导入模块
  20. 类的内置属性attr
  21. 继承方式完成包装
  22. 组合方式完成授权
  23. getattribute
  24. item
  25. str与repr
  26. 自定制format
  27. slots属性
  28. doc属性
  29. module和class
  30. 析构方法
  31. call方法
  32. 迭代器协议
  33. 描述符理论
  34. 描述符优先级
  35. 类的装饰器
  36. 自定制property
  37. 元类
  38. 自定义元类

类相关知识

对象相关知识

类属性增删改查

实例属性增删改查

对象与实例属性

静态属性

类方法

静态方法

组合

继承

接口设计与归一化设计

聚成顺序之mro线性顺序列表

Python2中的继承顺序

子类调用父类的方法

super调用父类的方法

多态

封装

反射

动态导入模块

类的内置属性attr

继承方式完成包装

组合方式完成授权

getattribute

item

str与repr

自定制format

slots属性

doc属性

module和class

析构方法

call方法

迭代器协议

描述符理论

描述符优先级

类的装饰器

自定制property

元类

自定义元类

一. 面向对象编程的一些特性

相比于面向过程的编程方式,采用面向对象的编程方式可以提高代码的复用性和灵活性

1. 复用性

设计一个类,就是为了将这个类作为一个模块来使用,一个类多次被使用就提高了这个类的复用性,最终达到减少代码量以及修改一处处处更新的目的。提高代码复用性的方法有两个:组合派生

组合

组合就是将B类加入到A类中,两个类的关系就是A has B,通过这种方式来增强B类的功能和A类的代码重用性。

class Course(object):
    def __init__(self, name, period):
        self.name = name
        self.period = period
class Teacher:
    def __init__(self, name, gender, course):
        self.name = name
        self.gender = gender
        self.course = course

c1 = Course('python', 7)
t1 = Teacher('Hax', 'male', c1)
print(t1.course.period)

>>7

Course类被组合进Teacher类,Teacher就拥有了Course类的所有属性和方法。

派生

子类继承了父类的属性,然后衍生出自己新的属性,如果子类衍生出的新的属性与父类的某个属性的名字相同,那么再调用子类的这个属性,就以子类的这个属性为准了。
类特征可以在子孙类或子类中进行继承。这些子类从基类继承他们的核心属性,并且不影响父类的的特性。

class Human(object):
    def __init__(self, name, gender, birthday):
        self.name = name
        self.gender = gender
        self.birthday = birthday

    def prt(self):
        print('from Human', self.name, self.gender, self.birthday)

    def flag(self):
        print('this is Human class')


class Teacher(Human):
    def __init__(self, name, gender, birthday):
        Human.__init__(self, name, gender, birthday)

    def flag(self):
        print('this is Teacher class')

h1 = Human('Ken', 'female', '2016/1/2')
t1 = Teacher('Joe', 'male', '2017/1/1')

h1.prt()
t1.prt()
h1.flag()
t1.flag()

>>
from Human Ken female 2016/1/2
from Human Joe male 2017/1/1
this is Human class
this is Teacher class

flag方法在子类中实现了,调用时只调用子类的flag方法,而不影响父类的flag方法。prt方法在父类中定义,而在子类中没有定义,那么调用时父类子类都调用父类的prt方法。

2.灵活性

灵活性通过多态多态性实现
多态是从类的定义的维度来定义的,以动物类为例,鸡、鸭、鱼、狗都是动物,但是是不同的动物,又都有动物的特性,即一类事物的不同形态。
**多态性是从类方法的应用维度定义的。还是以动物类为例。所有的动物都有移动这个特性,移动这个特性包括:爬,游,走。为了方便应用可以定义一个函数接受不同的动物作为参数,执行相同的方法--移动,但执行的结果不同--爬,游,走,这就是多态性。

class Animal(object):
    def __init__(self, sex, age):
        self.sex = sex
        self.age = age

    def move(self):
        pass

class Fish(Animal):
    def __init__(self, sex, age):
        Animal.__init__(self, sex, age)

    def move(self):
        print('Fish is swimming')

class Bird(Animal):
    def __init__(self, sex, age):
        Animal.__init__(self, sex, age)

    def move(self):
        print('Bird is flying')

f = Fish('female', 2)
b = Bird('male', 3)

def func(obj):
    obj.move()

func(f)
func(b)

代码中定义的鱼和鸟就是动物类的多态表现,通过func 方法传入不同的动物的实例执行实例对应的方法就是多态性的体现

3. 封装

封装数据:保护隐私
封装方法:隔离复杂度
封装需要提供访问被封装内容的接口,接口调用者只能通过接口访问内部数据,并且不能访问被隐藏内容的细节。此外,可以在接口中设计逻辑,限制调用者的访问方式。
封装分为两个层次
第一个层次就是建立类,当类建立之后,调用者只能通过点的方式访问类内的数据。第二层次是通过
第二个层次是将类内的方法或属性定义为私有的,只能在类内部调用,类外部是调用不到的,或者在有需求时通过设计接口的方式供类外部使用。

使用双下划线设置私有变量

class Teacher(object):
    def __init__(self, name, salary):
        self.name = name
        self.__salary = salary # 变形为_Teacher__salary

    def __set_salary(self, s): # 变形为_Teacher__set_salary
        self.__salary = s

    def get_salary(self):
        return self.__salary

类中所有__ x都会变为_类名 __ xself.__x引用的是变形后的属性;这种变形的目的是在类的外部是无法通过类. __x对象.__x来访问到双下滑先开头定义的属性或方法的。</br>
子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。</br>
这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了。</br>
变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形</br>
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

# 不使用双下滑线定义方法,子类方法覆盖了父类方法
class Human(object):
    def language(self):
        print('speak sth')
    def speak(self):
        self.language()

class China(Human):
    def language(self):
        print('speak chinese')

p = China()
p.speak()

>>speak chinese

# 使用双下滑线定义方法,子类方法没有覆盖父类方法
class Human(object):
    def __language(self):
        print('speak sth')

    def speak(self):
        self.__language()

class China(Human):
    def __language(self):
        print('speak chinese')

p = China()
p.speak()

>>speak sth

python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块名以单下划线开头,那么from module import *时不能被导入,但是通过from module import _private_module依然是可以导入的

property

property是一种特殊的特性,使用该特性后对象调用方法时会使用像对象访问属性一样的方式

import math
class Circle:
    def __init__(self,radius): 
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 

    @property
    def perimeter(self):
        return 2*math.pi*self.radius 

c=Circle(10)
print(c.radius)
print(c.area)   # 像访问数据属性访问area,实际执行函数功能,计算面积
print(c.perimeter)  # 像访问数据属性访问perimeter,实际执行函数功能,计算周长

在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

class Foo:
    def __init__(self, val):
        self.__NAME = val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        pass

    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('%s must be str' % value)
        self.__NAME = value

    @name.getter
    def name(self):
        return self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f = Foo('Jack')
print(f.name)

>>Jack

上述例子通过@name.setter装饰的方法将私有属性在检查过类型后赋值给了self.__NAME,然后通过@name.getter装饰的方法方法获取到了私有属性。

二. 类相关的知识点

1. 类属性及方法的增删改查

2. super

super用于继承中,用来替换父类,简化代码,下面举例说明
python2
在介绍super前先引入一个概念:新式类经典类
Python2中类有新式类经典类两种类,新式类是有父类的类,如果没有实际的父类就使用object作为父类;经典类是没有父类的类。
python2中super方法只对新式类有效
下面的例子就是新式类中super方法的使用范例

 class People(object):
     def __init__(self, name, gender, age):
         self.name = name
         self.gender = gender
         self.age = age
     def walk(self):
         print '%s is walking' % self.name

 class China(People):
     country = 'china'
     def __init__(self, name, gender, age, language='chinese'):
         super(China, self).__init__(name, gender, age)
         self.language = language

super代替People并在其后加上当前类的类名Chinaself作为参数
python3
在``python3`中对语法进行了进一步的精简

class People(object):
    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age

    def walk(self):
        print('%s is walking' % self.name)

class China(People):
    country = 'china'

    def __init__(self, name, gender, age, language='chinese'):
        super().__init__(name, gender, age)
        self.language = language

可以看出将super后面的参数省去了

3. 接口与归一化设计

Python中没有接口的概念,为了实现接口设计,可以使用继承实现;为了实现强制子类实现接口功能,可以使用abc模块

import abc


class File(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def file_write(self):
        pass

    @abc.abstractmethod
    def file_read(self):
        pass


class Text(File):
    def file_write(self):
        print('text file execute write operation')

    def file_read(self):
        print('text file execute read operation')


class Process(File):
    def file_write(self):
        print('process file execute write operation')

    def file_read(self):
        print('process file execute read operation')


class Disk(File):
    def file_write(self):
        print('disk file execute write operation')

    def file_read(self):
        print('disk file execute read operation')

4. 在类内部定义的函数无的三种用途

绑定到对象的方法
只要是在类内部定义的,并且没有被任何装饰器修饰过的方法,都是绑定到对象的

    class Foo:
        def test(self): #绑定到对象的方法
            pass
        def test1(): #也是绑定到对象的方法,只是对象.test1(),会把对象本身自动传给test1,因test1没有参数所以会抛出异常
            pass

绑定到对象,指的是:由对象调用
使用方式:对象.对象的绑定方法(),不用为self传值
特性:调用时会把对象本身当做第一个参数传给对象的绑定方法

绑定到类的方法:classmethod
在类内部定义的,并且被装饰器@classmethod修饰过的方法,都是绑定到类的

    class Foo:
        def test(self): #绑定到对象的方法
            pass
        def test1(): #也是绑定到对象的方法,只是对象.test1(),会把对象本身自动传给test1,因test1没有参数所以会抛出异常
            pass
f = Foo()
f.test1()
>>TypeError: test1() takes 0 positional arguments but 1 was given

绑定到对象,指的是:就给对象去用,
使用方式:对象.对象的绑定方法()
特性:调用时会把对象本身当做第一个参数传给对象的绑定方法

解除绑定的方法:staticmethod
既不与类绑定,也不与对象绑定,不与任何事物绑定
绑定的特性:自动传值(绑定到类的就是自动传类,绑定到对象的就自动传对象)
解除绑定的特性:不管是类还是对象来调用,都没有自动传值这么一说了

所以说staticmethod就是相当于一个普通的工具包

    
class Foo:
    def test1(self):
        pass
    def test2():
        pass
    
    @classmethod
    def test3(cls):
        pass
    @classmethod
    def test4():
        pass
    
    @staticmethod
    def test5():
        pass

test1与test2都是绑定到对象方法:调用时就是操作对象本身
<function Foo.test1 at 0x0000000000D8E488>
<function Foo.test2 at 0x0000000000D8E510>
test3与test4都是绑定到类的方法:调用时就是操作类本身
<bound method Foo.test3 of <class 'main.Foo'>>
<bound method Foo.test4 of <class 'main.Foo'>>
test5是不与任何事物绑定的:就是一个工具包,谁来都可以用,没说专门操作谁这么一说
<function Foo.test5 at 0x0000000000D8E6A8>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容