1. 编程范式考察
1.1 面向对象基础及常考题
什么是面向对象
- 把对象作为基本单元,把对象抽象成类,包含成员和方法
- 数据封装、继承(代码复用)、多肽
- 成员,操作成员的方法
1.2 组合与继承
- 组合是使用其他类示例作为自己的类属性(has a 关系)
- 子类继承父类的属性和方法(is a 关系)
- 优先使用组合保持代码简单
1.3 类变量和实例变量区别
- 类变量:所有实例共享
- 实例变量:实例单独享有,不同实例之间不影响
- 当我们需要在一个类的不同实例之间共享变量时使用类变量
1.4 classmethod 和staticmethod 区别
- 都可以通过
class.method()
方式调用 classmethod
第一个参数是cls
,可以引用类变量staicmethod
:使用起来和普通函数一样,只不过放在类里面去组织
1.5 元类 Meta Class
创建类的类
- 允许控制类的生成,比如修改类的属性
- 使用 type 来定义元类
- 最常用的一个使用场景就是 ORM 框架
class LowercaseMeta(type):
"""修改类的属性名称为小写的元类"""
def __new__(msc, name, bases, attrs):
lower_attrs = {}
for k, v in attrs.items():
if not k.startswith('__'):
lower_attrs[k.lower()] = v
else:
lower_attrs[k] = v
return type.__new__(msc, name, bases, lower_attrs)
class LowercaseClass(metaclass=LowercaseMeta):
BAR = True
def HELLO(self):
print('hello')
print(dir(LowercaseClass))
运行结果:
# BAR、 HELLO 都变为了小写
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'hello']
1.6 封装、继承和多态
面向对象编程有三大重要特征:封装、继承和多态。
封装
指将数据与具体实现代码封装在某个对象内部,使得这些细节不被外界发现,外界只能通过接口使用该对象,而不能通过任何形式修改对象内部实现。
优点
- 使得代码更易维护
- 因为不能直接调用和修改对象内部私有信息,在一定程度上保证了系统安全性
- 类通过经函数和变量封装在内部,实现了比函数更高一级的封装
class Person:
name = 'rose'
age = 'gender'
def say_hi(self):
return 'Hello'
外部不能直接调用类内部变量或函数,只能通过类的实例对象调用或修改。
继承
继承机制实现了代码的复用,多个类公用的部分可以放在一个类中,其他类要想使用可以直接继承该类即可。
继承最大的好处就是子类获得父类的所有变量和方法的同时,也可以根据自身需要进行修改、拓展
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def speak(self):
return self.name + 'speak say hello'
class Student(People):
def __init__(self, name, age, gender):
# 调用父类的实例方法
People.__init__(self, name, age, gender)
def speak(self):
"""重写父类的方法"""
return 'haha'
Python3 继承查找顺序
- 首先从自己内部查找所需变量或方法,若没有则查找所继承的类
- 按照 深度优先的原则查找,即有多个父类时,会从左至右开始查找,每一个类全部查找完毕,才开始查找下一个类
super()函数
子类中如果有与父类同名的方法或变量,会覆盖父类的。如果想要强制调用父类的方法或变量,可以使用 super()
函数:
super(子类名, self).方法名()
class A:
def __init__(self, name):
self.name = name
print('父类 __init__ 方法被调用')
def show(self):
print('父类 show 方法被调用')
class B(A):
def __init__(self, name):
super(B, self).__init__(name=name)
def show(self):
super(B, self).show()
b = B('rose')
b.name
b.show()
父类 __init__ 方法被调用
父类 show 方法被调用
多肽
一个接口,多种方法, 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
多态的三个条件:
- 继承的存在(继承是多态的基础,没有继承就没有多态)
- 子类重写父类的方法(多态下调用子类重写的方法)
- 父类引用变量指向子类对象(子类到父类的类型转换)
重载(overload)和重写(override)是实现多态的两种主要方式。
接口多态性。
继承多态性。
通过抽象类实现的多态性。
class Animal:
def kind(self):
print('I am an animal')
class Dog(Animal):
def kind(self):
print('I am a dog')
class Cat(Animal):
def kind(self):
print('I am a cat')
# 这个函数接收一个animal参数,并调用它的kind方法
def show_kind(animal):
animal.kind()
a = Animal()
d = Dog()
c = Cat()
show_kind(a)
show_kind(d)
show_kind(c)
I am an animal
I am a dog
I am a cat
比较出名的就是鸭子类型,一只鸟走起来像鸭子,叫起来也像鸭子,游泳起来也像鸭子,那就是一只鸭子。
参考:http://www.liujiangblog.com/course/python/44