面向对象

  类,就是一种事物,具有共性。比如dict,人,熊猫

  对象,类的实例化后所产生的,具有个性,比如{1:‘vf’},春哥,团团。

申明类:

class 类名:
    '类的文档字符串'#类的静态属性
  def __init__(self,参数)
    实例化所需要的参数代码
  def 功能

面向对象小结——定义及调用的固定模式

class 类名:
    def __init__(self,参数1,参数2):
        self.对象的属性1 = 参数1
        self.对象的属性2 = 参数2

    def 方法名(self):pass

    def 方法名2(self):pass

对象名 = 类名(1,2)  #对象就是实例,代表一个具体的东西
                  #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
                  #括号里传参数,参数不需要传self,其他与init中的形参一一对应
                  #结果返回一个对象
对象名.对象的属性1   #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名()     #调用类中的方法,直接用 对象名.方法名() 即可
面向对象小结——定义及调用的固定模式

 我们定义的类的属性到底存到哪里了?有两种方式查看

dir(类名):查出的是一个名字列表

类名.__dict__:查出的是一个字典,key为属性名,value为属性值

 特殊的类属性

类名.__name__# 类的名字(字符串)

类名.__doc__# 类的文档字符串

类名.__base__# 类的第一个父类(在讲继承时会讲)

类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)

类名.__dict__# 类的字典属性

类名.__module__# 类定义所在的模块

类名.__class__# 实例对应的类(仅新式类中)

class Person:
    country = 'China'
    def __init__(self,name,sex,age,hobby):
        self.name=name
        self.sex=sex
        self.age=age
        self.hobby=hobby
    def func(self):
        print(dir(self))
p1=Person('alex','male',68,'study')
print(dir(Person))
print(dir(p1))
print(p1.__dict__)
print(Person.__name__)
print(Person.__doc__)
print(Person.__base__)
print(Person.__bases__)
print(Person.__module__)
print(Person.__class__)
print(Person.__dict__)
#输出的结果为
'''

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'country', 'func'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'country', 'func', 'hobby', 'name', 'sex'] {'hobby': 'study', 'sex': 'male', 'name': 'alex', 'age': 68} Person None <class 'object'> (<class 'object'>,) __main__ <class 'type'> {'__init__': <function Person.__init__ at 0x0000000000832620>, 'country': 'China', '__doc__': None, '__dict__': <attribute '__dict__' of 'Person' objects>, '__module__': '__main__', 'func': <function Person.func at 0x00000000008326A8>, '__weakref__': <attribute '__weakref__' of 'Person' objects>} '''

 面向对象的组合

  组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

 

 面向对象的命名空间

class name_space:
    code='utf-8'
    def __init__(self,name,sex,age):
        self.name=name
        self.age=age
        self.sex=sex
lhy=name_space('lhy','female',18)
dxx=name_space('dxx','male',23)
print(name_space.code)#utf-8
print(lhy.code)#utf-8
print(lhy.age)#18
#print(name_space.name)#报错
#name_space.__dict__['code']='unicode'#报错
name_space.code='unicode'
print(name_space.code)#unicode
print(lhy.code)#unicode
lhy.__dict__['code']='gbk'
print(lhy.__dict__)#gbk
print(lhy.code)#gbk
print(name_space.code)#unicode
lhy.__dict__.pop('code')#删除code
print(lhy.code)#unicode
 
类的静态变量是可以通过 类.属性名来改变的,但是不可以通过类.__dict__来进行改变。同时静态属性的改变影响对象的静态属性,应为这个属性是绑定在类中并指向一个内存地址的
对象,可也以改变静态属性的。对象名.属性来改变,但是不会影响其他对象以及类的这静态属性的,相当于自己在自己的命名空间开了一新的的空间,不再是绑定关系,删除之后,才会恢复绑定关系

再看代码

class group:
     hobby=['eat','drink','swim']
wjw=group
jjs=group
print(group.hobby)#print(group.hobby)
print(wjw.hobby)#print(group.hobby)
print(jjs.hobby)#print(group.hobby)
wjw.hobby.pop()
print(group.hobby)#['eat', 'drink']
print(wjw.hobby)#['eat', 'drink']
print(jjs.hobby)#['eat', 'drink']

类里的名字有 类变量(静态属性量)+ 方法名(动态属性)
对象里的名字 对象属性
对象 —— > 类
对象找名字 : 先找自己的 找类的 再找不到就报错
对象修改静态属性的值
对于不可变数据类型来说,类变量最好用类名操作
对于可变数据类型来说,对象名的修改是共享的,重新赋值是独立的

面向对象的三大特征:继承,多态,封装

继承

单继承

父类又称超类,基类
子类又称派生类

class A:
    def fun(self):
        print('A')
        pass
class B:
    def fun(self):
        print('B')
        pass

class A_son(A):
    def fun(self):
        print('A_son(A)')
        pass

class AB_son(A,B):
    def fun(self):
        print('AB_son(A,B)')
        pass
print(A_son.__bases__)#(<class '__main__.A'>,) 表示A的子类
print(AB_son.__bases__)#(<class '__main__.A'>, <class '__main__.B'>)表示A和B的子类

提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

继承与抽象:向抽象在继承。

请看代码

class People:
    def eat(self):
        print('%s eat a bread'%self.name)
    def sleep(self):
        print('%s is slepping'%self.name)
    def look_for_sex(self):
            print('%s is %s' % (self.name, self.sex))
class Xiaoming(People):
    def __init__(self,name,sex):
        self.name=name
        self.sex=sex
class Xiaohong(People):
    def __init__(self,name,sex):
        self.name=name
        self.sex=sex
xiaoming=Xiaoming('xiaoming','male')
xiaohong=Xiaohong('xiaohong','female')
xiaoming.eat()#xiaoming eat a bread
xiaohong.look_for_sex()#xiaohong is female

注意:此时的父类定义时没有传参数,故可以直接调用

派生

子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)。

需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

class A:
    def func(self):
        print('it is father function')
class B(A):
    def func(self):
        print('it is son function')
b= B()
b.func()#it is son function
father_and_son_function

父类中没有的属性 在子类中出现 叫做派生属性
父类中没有的方法 在子类中出现 叫做派生方法
只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
如果父类 子类都有 用子类的

  如果还想用父类的,单独调用父类的:

  父类名.方法名 需要自己传self参数

  super().方法名 不需要自己传self

  在外部调用父类方法是super().方法名 需要自己在()中填写(子类名,对象名)

                  内部调用(子类名,self)

  注意区分内外掉用区别

  super().hahaha() 等价super(B,self).hahaha(),一般用前面的

正常的代码中 单继承 === 减少了代码的重复
继承表达的是一种 子类是父类的关系

关于继承传参数

class A:
    def __init__(self,name,sex,age):
        self.name=name
        self.age= age
        self.sex=sex
        print('A传参数完成')
class B(A):
    def __init__(self,name,age,sex,hobby):
        super().__init__(name,age,sex)
        # super(B, self).__init__(name, age, sex)
        #也可以这么写,这样就能统一self
        self.hobby=hobby
        print('hobby传参完成')
a =B('alex',16,'male','study')
#结果
#A传参数完成
#hobby传参完成
继承传参

多继承:

多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么?
经典类中 深度优先
新式类中 广度优先
python2.7 新式类和经典类共存,新式类要继承object
python3 只有新式类,默认继承object
经典类和新式类还有一个区别 mro方法只在新式类中存在

   类名.mro()  查找多继承的顺序

super 只在python3中存在
super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的

砖石继承

 

抽象类与接口类

接口类 : python原生不支持
抽象类 : python原生支持

规范 :接口类或者抽象类都可以
接口类 支持多继承,接口类中的所有的方法都必须不能实现 —— java
抽象类 不支持多继承,抽象类中方法可以有一些代码的实现 —— java

接口类

from abc import ABCMeta,abstractmethod
class start_game(metaclass=ABCMeta):
    @abstractmethod
    def start(self,num):pass
class LOL(start_game):
    def start(self,num):
        print('%s second will be open Lol'%num)
class DNF(start_game):
    def start(self,num):
        print('%s second will be open DNF' % num)
class QQ(start_game):
    def begin(self,num):
        print('%s second will be open QQ' % num)
lol=LOL()
lol.start(5)#5 second will be open Lol
dnf=DNF()
dnf.start(6)#6 second will be open DNF
qq = QQ()
qq.begin(5)#TypeError: Can't instantiate abstract class QQ with abstract methods start

 解析

 接口内的多继承

from abc import abstractmethod,ABCMeta
class Swim_Animal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):pass

class Walk_Animal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):pass

class Fly_Animal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):pass

class Tiger(Walk_Animal,Swim_Animal):
    def walk(self):
        pass
    def swim(self):
        pass
class OldYing(Fly_Animal,Walk_Animal):pass
class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass

抽象类

 与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

为什么要有抽象类

    如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。

  比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

    从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

  从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def read(self):
        '子类必须定义读功能'
        with open('filaname') as f:
            pass
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        '子类必须定义写功能'
        pass
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')
    def write(self):
        print('文本数据的读取方法')
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')
    def write(self):
        print('硬盘数据的读取方法')
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')
    def write(self):
        print('进程数据的读取方法')
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
#输出结果

#文本数据的读取方法
#硬盘数据的读取方法
#进程数据的读取方法
#file
#file
#file

抽象类 : 规范
一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中


抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化
java :
java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题
但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念来解决多继承的规范问题

python
python中没有接口类 :
python中自带多继承 所以我们直接用class来实现了接口类
python中支持抽象类 : 一般情况下 单继承 不能实例化
且可以实现python代码

多态

python 天生支持多态属于动态强类型语言

鸭子类型
list tuple
不崇尚根据继承所得来的相似
我只是自己实现我自己的代码就可以了。
如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
优点 : 松耦合 每个相似的类之间都没有影响
缺点 : 太随意了,只能靠自觉

强类型语言 多态
python 语言 鸭子类型

 封装

广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
只让自己的对象能调用自己类中的方法

狭义上的封装 —— 面向对象的三大特性之一
属性 和 方法都藏起来 不让你看见

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

解析

class conformation:
    def __init__(self,name,sex,age):
        self.__name=name
        self.sex=sex
        self.__age=age
    def __func(self):
        return self.__age+7
    def function(self):
        print(self.__func())
xiaoming = conformation('xiaoming','male',19)
print(xiaoming.sex)
# print(xiaoming.name)#报错
print(xiaoming._conformation__name)
print(xiaoming.__dict__)
#{'sex': 'male', '_age': 19, '_conformation__name': 'xiaoming'}
print(xiaoming._conformation__func())
xiaoming.function()
'''输出结果
male
xiaoming
{'_conformation__name': 'xiaoming', 'sex': 'male', '_conformation__age': 19}
26
26
'''
代码

这种自动变形的特点:

1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

这种变形需要注意的问题是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形

在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B
 

#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A
View Code

会用到私有的这个概念de场景
1.隐藏起一个属性 不想让类的外部调用
2.我想保护这个属性,不想让属性随意被改变
3.我想保护这个属性,不被子类继承

原文地址:https://www.cnblogs.com/accolade/p/10500039.html