Python基础之面向对象编程(二)

本篇文章主要介绍面向对象编程。

面向对象编程

几个定义

  • 面向过程编程:围绕函数,编写能处理数据的代码块的编程方式。
  • 类、对象:面向对象编程的两个主要方面。一个类(Class)能创建一种新的类型;对象(Object)是类的实例。可这样类比:你可拥有类型 int 的变量,也即,存储整数的变量是 int类 的对象实例。
  • 字段、方法和属性:从属于对象或类的变量叫字段(Field);对象调用从属于类的函数实现某些功能,这些函数叫类的方法(Method);字段和方法统称为累的属性(Attribute)。

Tips: 不同于静态语言,Python 中即使是整数也会被视为对象(int类的对象),同 Java 中装箱与拆箱概念颇为相似。

类和对象

最简单的类结构如下所示:

class Student(object):
    pass # 一个空的代码块

# 创建类对象实例
student = Student()
print(student)  
# 打印:<__main__.Student object at 0x101985f28>   

*Tips: *

  • Python 中所有类均继承自 object;
  • Python 打印对象,默认可查看对象地址。Python 会在它找到的任何空间来存储对象。
类属性和实例属性

方法(Method)

Python 对比于 Java 类方法属性,有两个特殊点:

  • 类中定义的所有方法,第一个参数必须是 self;相当于 Java 中的 this 引用;
  • _init_() 方法:在类的对象被实例化时立即运行;相当于 Java 中的构造方法。
    Tips: Python中不存在方法的重载,方法的重载是对同一个方法使用可变参数来实现,这在后面函数参数这块会提到。

示例代码如下:

class Student(object):
    count = 0  # 类变量

    def __init__(self, name):
        self.name = name  # 实例变量
    
    def say_hi(self):
        print(r'Hello, I'm', self.name)
        
student = Student('Coral')  
student.say_hi()  
# 打印:Hello, I'm Coral

字段(Field)

Python 中字段有两种类型——类变量与对象变量,对比上述示例代码,两者的区别点如下图所示:


类变量和实例变量区别.png

因为 Python 是动态语言,可以给类创建的实例动态绑定属性,那么如何给 实例 绑定属性?如何给 类 绑定属性呢?

1)给实例绑定属性

  • 通过在 _init_ 方法中给 self 绑定属性,这种属性所有对象实例均可访问;
  • 直接给实例绑定,这种属性只适用于该实例,其他实例不能访问该属性。如:
student = Student('Coral')
# grade是给实例动态绑定的属性,name是通过 self绑定的属性
student.grade = 90 
print('{} grade = {} '.format(student.name, student.grade)) 

student2 = Student('Jane')
print(student2.grade)
# 这句会抛出:AttributeError: 'Student' object has no attribute 'grade'

2)给类绑定属性
要让同一个字段属性对所有实例均适用,除了 self 绑定,还可以适用 类属性。

  • 类属性,直接在 class 中定义属性,归整个 Student 类所有,如 count 字段。

Tips: 当 实例属性 和 类属性 同名时,实例属性 优于 类属性,也即,实力属性会覆盖类属性,所以在项目中要避免使用这种同名变量。

访问限制

Java 中有四种访问修饰符,Python 中并没有指定具体的访问修饰符,仅是按照一种约定的写法来,如下图所示:


访问限制.png
获取对象信息

在 Java 中通常会判断一个对象是什么类型,用 instanceOf 来判断,Python 中也有判断对象类型的方法,还可以获取对象拥有的属性和方法,这些都是 Python 内置的方法。常见的如下图所示:


获取对象信息方法.png

这里重点说下 isinstance() 方法,示例如下:

a = list() # a 是 list 类型
b = Animal() # b 是 Animal 类型
c = Dog()  # c 是 Dog 类型

# 1.判断一个变量是否是某个类型可以用 isinstance() 判断:
print('a is list:', isinstance(a, list))     # True
print('b is Animal:', isinstance(b, Animal)) # True
print('c is Dog:', isinstance(c, Dog))       # True
print('c is Animal:', isinstance(c, Animal)) # True

# 2. 能用 type() 判断的基本类型也可以用 isinstance() 判断:
print(isinstance('a', str))    # True
print(isinstance(123, int))    # True
print(isinstance(b'a', bytes)) # True

# 3. 另外,isinstance() 还可以判断一个变量是否是某些类型中的一种:
# 判断变量是否是 list 或 tuple.
def is_list_or_tuple(x):
    return isinstance(x, (list, tuple))

Tips: 区别于 type,对于 class 继承关系,不便使用 type();要判断 class 类型,使用 isinstance() 函数。因为 type() 只能返回对象本身的类型,比如 type(dog) != type(animal), 但是 isinstance(dog, Dog) = isinstance(dog, Animal)。

继承和多态

Python 中允许多继承,没有接口实现的概念。继承和多态总结点如下:


继承和多态.png

Python 中没有方法的重载,但是存在方法的覆盖,子类可以覆盖父类方法,也适用于运行时绑定传入的实例。

关于继承的几个问题
  1. 子类 能否继承 父类绑定的 属性?(每个类通过 self 或者 给实例动态绑定的 属性都是该类实例 独立拥有,跟子类没有任何关联?)
    A: 子类不能继承 父类中通过 self或者 动态绑定的属性;
  2. 子类 是否只能继承 父类绑定的 类属性?
    A:子类能继承 父类中的 类属性,在操作该类属性时,使用 ChildClass.property 访问该类属性;
  3. 子类可以继承 父类的所有方法?
    A:Python 中方法没有 访问限制符修饰;
  4. 每个类通过 self 或者 给实例动态绑定的 属性都是该类实例 独立拥有,跟子类没有任何关联?
    A:是。
  5. 子类和父类有同名的 属性,优先使用哪个?(避免这种情况,直接继承使用父类的属性)
    A:子类优先,但最好不要让子类属性和父类属性同名 。
  6. 子类能否继承父类中 __xxx 隐藏属性?
    A:这个可以看做是每个类通过 self 绑定的属性均属于本类所有,父类中通过 self 绑定的属性不管是否是隐藏属性,子类直接访问就会抛出:AttributeError: 'Dog' object has no attribute '_BaseClass__name' .

你可能感兴趣的:(Python基础之面向对象编程(二))