面向对象基础及py类常考问题
什么是面向对象编程?
Object Oriented Programming(OOP)
把对象作为基本单元, 把对象抽象成类(class) 包含成员和方法
数据封装, 继承, 多态
? Py中使用类来实现, 过程式编程(函数), OOP(类)
Py中如何创建类?
class Person(object): #py3 直接class Person def __init__(self, name, age): self.name = name self.age = age def print_name(self): print('my name is {}'.format(self.name))
成员|方法|私有属性|魔术方法
组合与继承
优先使用组合而非继承
组合是使用其他的类实例作为自己的一个属性(Has-a 关系)
? 子类继承父类的属性和方法(is a 关系)
? 优先使用组合保持代码简单
? 之前实现栈/队列使用组合
类变量和实例变量的区别
区分类变量和实例变量
类变量由所有实例共享
? 实例变量由实例单独享有, 不同实例之间不影响
? 当我们需要一个类的不同实例之间共享变量的时候使用类变量
class Person: Country = 'china' #类变量 def __init__(self, name): self.name = name #实例属性/变量 def print_name(self): print(self.name) laowang = Person('laowang') laoli = Person('laoli') laoli.print_name() print(laowang.Country) print(laoli.Country)
classmethod/staticmethod区别
都可以通过Class.method()的方式使用
classmethod第一个参数是cls, 可以引用类变量,为了使用类变量
staticmethod使用起来和普通函数一样, 只不过放在类里去组织 是代码组织的需要, 完全可放到类之外
class Person: Country = 'china' #类变量 def __init__(self, name): self.name = name #实例属性/变量 @classmethod def print_country(cls): print(cls.Country) @staticmethod def join_name(first_name, last_name): return last_name + first_name #last_name
什么是元类? 使用场景
元类(Meta Class)是创建类的类
元类允许我们控制类的生成, 比如修改类的属性等
? 使用type来定义元类
? 元类最常见的一个使用场景就是ORM框架
__new__ 生成实例 __init__ 初始化
总结
什么是面向对象?py如何使用类
? 组合vs继承 类变量vs实例变量 classmethod vs staticmethod
? 元类的创建和使用
py装饰器常见考题
什么是装饰器
Decorator
py中一切皆对象, 函数也可以当做参数传递
装饰器是接受函数作为参数, 添加功能后返回一个新函数的函数(类)
py中通过@使用装饰器
编写一个记录函数耗时的装饰器
import time def log_time(func): #接受一个函数作为参数 def _log(*args, **kwargs): beg = time.time() res = func(*args, **kwargs) print('use time: {}'.format(time.time()-beg)) return res return _log @log_time #@装饰器语法糖 def mysleep(): time.sleep(1) newsleep = log_time(mysleep) newsleep()
如何使用类编写装饰器
import time class LogTime: def __call__(self, func): def _log(*args, **kwargs): beg = time.time() res = func(*args, **kwargs) print('use time: {}'.format(time.time()-beg)) return _log @LogTime() def mysleep2(): time.sleep(1) mysleep2()
如何给装饰器增加参数?
使用类装饰器比较方便实现装饰器参数
class LogTimeParams: def __init__(self, use_int=False): self.use_int = use_int def __call__(self, func): def _log(*args, **kwargs): beg = time.time() res = func(*args, **kwargs) if self.use_int: print('use time: {}'.format(int(time.time()-beg))) else: print('use time: {}'.format(time.time()-beg)) return res return _log
设计模式:
创建型,结构型,行为型 23种设计模式
创建型模式 py应用面试题
常见创建型设计模式
- 工厂模式(Factory):解决对象创建问题
- 构造模式(Buider): 控制复杂对象的创建
- 原型模式(Prototype):通过原型的克隆创建新的实例
- 单例(Borg/Singleton): 一个类只能创建同一个对象
- 对象池模式(Pool):预先分配同一类型的一组实例
- 惰性计算模式(Lazy Evaluation): 延迟计算(py中的property)
工厂模式
什么是工厂模式(Factory)
- 解决对象创建问题 解耦对象的创建和使用 包括工厂方法和抽象工厂
class DogToy: def speak(self): print("wang wang") class CatToy: def speak(self): print("miao miao") def toy_factory(toy_type): if toy_type == 'dog': return DogToy() elif toy_type == 'cat': return CatToy()
构造模式(Builder):
用来控制复杂对象的承诺
创建和表示分离, 比如你要买电脑, 工厂模式直接给你需要的电脑
而构造模式允许你自己定义电脑配置, 组装完成后给你
class Computer: def __init__(self, serial_number): self.serial = serial_number self.memory = None #in gigabytes self.hdd = None self.gpu = None def __str__(self): info = ('Memory: {}GB'.format(self.memory), 'Hard Disk: {}GB'.format(self.hdd), 'Graphics Card: {}'.format(self.gpu)) return '\n'.join(info) class ComputerBuilder: def __init__(self): self.computer = Computer('AG23385193') def configure_memory(self, amount): self.computer.memory = amount def configure_hdd(self, amount): self.computer.hdd = amount def configure_gpu(self, gpu_model): self.computer.gpu = gpu_model class HardwareEngineer: def __init__(self): self.builder = None def construct_computer(self, memory, hdd, gpu): self.builder = ComputerBuilder() [step for step in (self.builder.configure_memory(memory), self.builder.configure_hdd(hdd), self.builder.configure_gpu(gpu))] @property def computer(self): return self.builder.computer #use builder create 多个builder类实现不同的组装方式 engineer = HardwareEngineer() engineer.construct_computer(hdd=500, memory=8, gpu='geForce GTX 650 Ti') computer = engineer.computer print(computer)
原型模式
通过克隆原型来创建新的实例
可以使用相同的原型,通过修改部分属性来创建新的示例
用途: 对于一些创建实例开销比较高的地方可以用原型模式
单例模式
实现有多种方式
单例模式:一个类创建出来的对象都是同一个
py的模块其实就是单例的,只会导入一次
使用共享同一个实例的方式来创建单例模式
#单例模式
class Singleton: def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): _instance = super().__new__(cls, *args, **kwargs) cls._instance = _instance return cls._instance class MyClass(Singleton): pass c1 = MyClass() c2 = MyClass() assert c1 is c2 print(id(c1)) print(id(c2)) print(c1 is c2)
设计模式:结构型模式python应用面试题
结构型模式常考题
常见结构型设计模式
装饰器模式(Decorator):无需子类化扩展对象功能
代理模式(Proxy):把一个对象的操作代理到另一个对象
适配器模式(Adapter):通过一个简接层适配统一接口
外观模式(Facade):简化复杂对象的访问问题
享元模式(Flyweight):通过对象复用(池)改善资源利用,eg: 连接池
Model-View-Controller(MVC):解耦展示逻辑和业务逻辑
什么是代理模式(proxy)
把一个对象的操作代理到另一个对象
之前实现的Stack/Queue, 把操作代理到deque
通常使用has-a组合关系
什么是适配器模式
把不同的对象的接口适配到同一接口
一个多功能充电头,可以给不同的电器充电, 充当了适配器
当需要给不同的对象统一接口的时候可以使用适配器模式
#适配器模式的例子 class Dog(object): def __init__(self): self.name = "Dog" def bark(self): return "woof!" class Cat(object): def __init__(self): self.name = "Cat" def meow(self): return "meow!" class Adapter: def __init__(self, obj, **adapted_methods): """We set adapted methods in the object's dict""" self.obj = obj self.__dict__.update(adapted_methods) def __getattr__(self, attr): """All non-adapted calls are passed to the object""" return getattr(self.obj, attr) objects = [] dog = Dog() objects.append(Adapter(dog, make_noise=dog.bark)) cat = Cat() objects.append(Adapter(cat, make_noise=cat.meow)) for obj in objects: print("A {0} goes {1}".format(obj.name, obj.make_noise()))
设计模式:行为型模式Python应用面试题
行为型模式常考题
常见学习行为型设计模式
迭代器模式(Iterator):通过统一的接口迭代对象
观察者模式(Observer):对象发生改变的时候,观察者执行相应动作
策略模式(Strategy): 针对不同规模输入使用不同的策略
迭代器模式(Iterator)
py内置对迭代器模式的支持
''' 可以用for遍历各种Iterable的数据类型 py可以实现_next_和_iter_实现迭代器 ''' from collections import deque class Stack(object): #使用组合的例子 def __init__(self): self._deque = deque() #has a deque() def push(self, value): return self._deque.append(value) def pop(self): return self._deque.pop() def empty(self): return len(self._deque) == 0 def __iter__(self): res = [] for i in self._deque: res.append(i) for i in reversed(res): yield i s = Stack() s.push(1) s.push(2) for i in s: print(i)
观察者模式
发布订阅是一种最常用的实现方式
发布订阅用于解耦逻辑
可以通过回调等方式实现, 当发生事件时,调用相应的回调函数
#发布订阅模式 class Publisher: #发布者 def __init__(self): self.observers = [] #观察者 def add(self, observer): #加入观察者 if observer not in self.observers: self.observers.append(observer) else: print('Failed to add: {}').format(observer) def remove(self, observer): #移除观察者 try: self.observers.remove(observer) except ValueError: print('Failed to remove: {}').format(observer) def notify(self): #调用观察者的回调 [o.notify_by(self) for o in self.observers] class Formatter(Publisher): #继承自发布者 def __init__(self, name): super().__init__() self.name = name self._data = 0 @property def data(self): return self._data @data.setter def data(self, new_value): self._data = int(new_value) self.notify() #data 在合法赋值以后会执行notify class BinaryFormatter: """订阅者""" def notify_by(self, publisher): print("{}: '{}' has now bin data = {}".format( type(self).__name__, publisher.name, bin(publisher.data)) ) df = Formatter('formatter') #发布者 bf = BinaryFormatter() #订阅者 df.add(bf) #添加订阅者 df.data = 3 #设置的时候调用订阅者的notify_by
策略模式(Strategy)
1.根据不同的输入采用不同的策略
2.比如买东西超过10个打八折,超过20个打七折
3.对外暴露统一的接口,内部采用不同的策略计算
#策略模式 class Order: def __init__(self, price, discount_strategy=None): self.price = price self.discount_startegy = discount_strategy def price_after_discount(self): if self.discount_startegy: discount = self.discount_startegy(self) else: discount = 0 return self.price - discount def __repr__(self): fmt = "<Price: {}, price after discount: {}>" return fmt.format( self.price, self.price_after_discount() ) def ten_percent_discount(order): return order.price * 0.25 + 20 def on_sale_discount(order): return order.price * 0.25 + 20 def main(): order0 = Order(100) order1 = Order(100, discount_strategy=ten_percent_discount) order2 = Order(1000, discount_strategy=on_sale_discount) print(order0) print(order1) print(order2) main()
py函数式函数式编程
过程式编程,OOP, 简单函数式
py支持部分函数式编程特性
把电脑的运算视作数学上的函数计算(lambda演算)
高阶函数: map/reduce/filter
无副作用, 相同的参数调用始终产生同样的结果
map(lambda x:x*2, range(10)) list(map(lambda x:x*2, range(10))) [i*2 for i in range(10)] 推荐列表推导代替map from functools import reduce reduce(lambda x,y: x+y, range(1, 6)) filter(lambda x: x % 2 == 0, range(10)) [i for i range(10) if i % 2 == 0]
什么是闭包?
Closure
绑定了外部作用域的变量的函数
即使程序离开外部作用域,如果闭包仍然可见,绑定变量不会销毁
每次运行外部函数都会重新创建闭包
from functools import wraps def cache(func): #装饰器 store = {} #外部变量 @wraps(func) def _(n): #闭包函数 if n in store: return store[n] else: res = func(n) store[n] = res return res return _ @cache def f(n): #斐波拉契数列 if n <= 1: return 1 return f(n - 1) + f(n - 2) #闭包:引用了外部自由变量的函数 #自由变量:不在当前函数定义的变量 #特性:自由变量会和闭包函数同时存在