面向对象进阶及类成员

深入了解多继承

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class A:
    def bar(self):
        print("BAR")
        self.f1()
class B(A):
    def f1(self):
        print("B")
class C:
    def f1(self):
        print("C")
class D(C,B):
    pass
obj = D()
obj.bar()

执行结果

➜  python_test python3 022-exercise-1.py
BAR
C

脚本释义:

  1. 创建了类A,B,C,D;
  2. D继承了CB,B继承了A,D内什么都不做,pass;
  3. 创建一个对象obj,类是D,当执行Dbar方法的时候会先从C里面寻找有没有bar方法;
  4. C内没有bar方法,然后继续从B里面查找,B里面也没有,B的父类是AA里面有bar方法,所以就执行了Abar方法;
  5. Abar方法首先输出了BAR;
  6. 然后又执行了self.f1()self=obj,相当于执行了obj.f1();
  7. 执行obj.f1()的时候先从C里面查找有没有f1这个方法,C里面有f1这个方法;
  8. 最后就执行C里面的f1方法了,输出了C.

执行父类的构造方法

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Animal:
    def __init__(self):
        print("Animal的构造方法")
        self.ty = "动物"

class Cat(Animal):
    def __init__(self):
        print("Cat的构造方法")
        self.n = "猫"
        # 寻找Cat类的父类,然后执行父类的构造方法
        super(Cat,self).__init__()

m = Cat()
print(m.__dict__)

执行结果

➜  python_test python3 022-exercise-2.py
Cat的构造方法
Animal的构造方法
{'ty': '动物', 'n': '猫'}

先执行了Cat的构造方法,然后又执行了Annimal的构造方法。

第二种执行父类的方法如下:

Annimal.__init__(self)

不推荐使用

利用反射查看面向对象成员归属

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:
    def __init__(self,name):
        self.name = name

    def show(self):
        print("show")
obj = Foo("as")

# 如果是类,就只能找到类里面的成员
print(hasattr(Foo,"show"))

# 如果是对象,既可以找到对象,也可以找到类里的成员
print(hasattr(obj,"name"))
print(hasattr(obj,"show"))

执行结果

➜  python_test python3 022-exercise-3.py
True
True
True

利用反射导入模块,查找类,创建对象,查找对象中的字段

s1脚本文件内容:

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

# 导入模块
m = __import__('s2',fromlist=True)

# 去模块中找类
class_name = getattr(m,"Foo")

# 根据类创建对象
obj = class_name("yang")

# 去对象中name对应的值
print(getattr(obj,"name"))

s2脚本内容

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:
    def __init__(self,name):
        # 普通字段,保存在对象中
        self.name = name

执行结果

➜  python_test python3 s1.py
yang
➜  python_te

面向对象类成员之静态字段(类变量)

静态字段存在类中

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

# 静态字段存在的意义就是将每个对象中重复的东西在类里面保存一份即可, 节省开销

class Province:

    country = "China"

    def __init__(self,name):
        self.name = name

    def show(self):
        print(Province.country,self.name)

hebei = Province("河北")
hebei.show()

hubei = Province("湖北")
hubei.show()

执行结果

➜  python_test python3 022-exercise-4.py
China 河北
China 湖北

类里面的成员用类去访问,对象内的成员用对象去访问

面向对象类成员之静态方法

只是名义上归类管理,实际上在静态方法里访问不了类或实例中的任何属性.
@staticmethod # 实际上跟类没什么关系了
#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:

    # 静态方法括号内没有self,并且方法前一行要加上@staticmethod
    @staticmethod
    # def static(arg1,arg2): # 也可以设置参数
    def static():
        print("static")
# 静态方法通过类名.方法名即可执行
Foo.static()
# Foo.static("arg1","arg2")通过类调用的时候传入对应的参数即可

# 静态方法也可以通过对象去访问,对于静态方法用类去访问
obj = Foo()
obj.static()

执行结果

➜  python_test python3 022-exercise-5.py
static
static
class Dog(object):
    n = 123

    def __init__(self,name):
        self.name = name

    @staticmethod # 实际上跟类没什么关系了
    def eat(self):
        print("%s is eating %s" % (self.name,self.n))

    def talk(self):
        print("%s is talking" % self.name)

d = Dog("xx")
d.eat(d)
d.talk()

面向对象类成员之类方法

只能访问类变量,不能访问实例变量
@classmethod
#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:

    # 创建类方法的时候需要在方法前面加上@classmethod
    @classmethod
    def ClassMethod(cls):  # 并且方法的括号内必须带有cls关键字,类方法的参数是当前类的类名
        print("类方法")

# 调用类方法
Foo.ClassMethod()

执行结果

➜  python_test python3 022-exercise-6.py
类方法
class Dog(object):
    n = 123

    def __init__(self,name):
        self.name = name

    @classmethod
    def eat(self):
        print("%s is eating %s" %(self.name,self.n))

d = Dog("xx")
d.eat()

执行会报如下错误
AttributeError: type object 'Dog' has no attribute 'name'

属性方法

面向对象类成员特性: 特性的存在就是将方法伪装成字段

property

把类方法当做普通字段去调用,即用对象调用的时候后面不加括号

# 把一个方法变成一个静态属性,不加括号调用即类似 d.eat(d为一个实例)
@property
def eat(self):
    print('%s is eating %s' % (self.name,'xx')
#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:

    @property
    def Characteristic(self):
        print("类方法的特性")

# 创建一个对象
obj = Foo()
# 调用类方法的时候方法后面不用加括号
obj.Characteristic

输出

➜  python_test python3 025-exercise-1.py
类方法的特性
class Dog(object):
    n = 123

    def __init__(self,name):
        self.name = name
        self.__food = "骨头"

    @property
    def eat(self):
        print("%s is eating %s" % (self.name,self.__food))

    @eat.setter
    def eat(self,food):
        print("set to food: %s" % food)
        self.__food = food

    @eat.deleter # 删除一个属性
    def eat(self):
        del self.__food
        print("删完了")

d = Dog("xxx")
d.eat
d.eat = "包子"
d.eat
del d.eat

属性方法的作用

航班的例子

setter

设置类方法的值

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:
    # 获取Characteristic值
    @property
    def Characteristic(self):
        return "获取Characteristic值"

    # 意思是下面的Characteristic函数用来给上面的Characteristic函数设置值
    @Characteristic.setter
    def Characteristic(self,value):
        return "设置Characteristic值"

obj = Foo()
# 获取Characteristic的值
print(obj.Characteristic)

# 设置Characteristic的值
obj.Characteristic = 123

输出

➜  python_test python3 025-exercise-2.py
获取Characteristic值

deleter

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:

    # 特殊字段
    @property
    def pp(self):
        # 调用特殊字段的时候输出aaa
        print("property")

    @pp.setter
    def pp(self,value):
        # 调用设置方法的时候输出value的值
        print(value)

    @pp.deleter
    def pp(self):
        # 调用删除方法的时候输出del
        print("deleter")

# 创建一个对象obj
obj = Foo()
# 自动执行@property
obj.pp
# 自动执行@pp.setter
obj.pp = 999
# 自动执行@pp.deleter
del obj.pp

输出

➜  python_test python3 025-exercise-3.py
property
999
deleter

另一种调用特殊属性的方法

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

class Foo:

    def f1(self):
        print("f1")

    def f2(self,value):
        print("f2")

    def f3(self):
        print("f3")

    SpeciaFields = property(fget=f1,fset=f2,fdel=f3,doc="我是注释")

# 创建一个对象
obj = Foo()
# 调用类的f1方法
obj.SpeciaFields
# 调用类的f2方法
obj.SpeciaFields = 123
# 调用类的f3方法
del obj.SpeciaFields
# 调用类的doc,这里只能通过类去访问,对象无法访问
print(Foo.SpeciaFields.__doc__)

输出

➜  python_test python3 025-exercise-4.py
f1
f2
f3
我是注释

面向对象类成员内容梳理

字段

  1. 静态字段(类变量, 每个对象都有该属性, 节省开销)
  2. 普通字段(实例变量, 每个对象都不同的数据)

方法

  1. 静态方法(无需使用对象封装内容)
  2. 类方法
  3. 普通方法(适用对象中的数据)

特性

  1. 普通特性(将方法未造成字段?)

快速判断,类执行,对象执行:

  1. self -> 对象调用
  2. 无self -> 类调用