【python面试指北】3.类和面向对象

面向对象编程

  • 封装、继承、多态
class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def print_name(self):
        print self.name

组合与继承

优先使用组合(has a)而非继承(is a)

类变量和实例变量的区别

  • 类变量由所有实例共享
  • 实例变量由实例单独享有,不同实例之间不影响
  • 当我们需要在一个类的不同实例之间共享变量的时候使用类变量

classmethod/staticmethod区别

  • 都可以通过Class.method()的方式使用
  • classmethod第一个参数是cls,可以引用类变量
  • staticmethod使用起来和普通函数一样,只不过放在类里去组织
class Person(object):
    Country = 'china'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def print_name(self):
        print self.name

    @classmethod
    def print_country(cls):
        print(cls.Country)

    @staticmethod
    def join_name(first_name, last_name):
        return last_name + first_name

什么是元类

元类是创建类的类

  • 元类允许我们控制类的生成,比如修改类的属性等

  • 使用type来定义元类

  • 元类最常见的一个使用场景就是ORM框架

  • new用来生成实例,init用来初始化实例

例子:

【python面试指北】3.类和面向对象_第1张图片

装饰器

  • python中一切皆对象,函数也可以当做参数传递
  • 装饰器是接受函数作为参数,添加功能后返回一个新函数的函数(类)
  • python中通过@使用装饰器,语法糖
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)

mysleep()

# 另一种写法

def mysleep2():
    time.sleep(1)

newsleep = log_time(mysleep2)
newsleep()

使用类编写装饰器

import time
class LogTime:
    def __call__(slef, func): # 接受一个函数作为参数
        def _log(*args, **kwargs):
            beg = time.time()
            res = func(*args, **kwargs)
            print('use time: {}'.format(time.time()-beg))
            return res
        return _log

@LogTime()
def mysleep():
    time.sleep(1)

mysleep()

如何给装饰器增加参数?使用类转时期比较方便实现装饰器参数

import time
class LogTime:
    def __init__(self, use_int=False):
        self.use_int = use_int

    def __call__(slef, 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

@LogTime(True)
def mysleep():
    time.sleep(1)

mysleep()

设计模式

学习设计模式的一个有效的方式是自己尝试写个示例代码来演示它

创建型

工厂模式

  • 解决对象创建问题
  • 解耦对象的创建和使用
  • 包括工厂方法和抽象工厂
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()

构造模式

  • 用于控制复杂对象的构造
  • 创建和表示分离

原型模式

单例模式

  • 单例模式的实现有多种方式
  • 单例模式:一个类创建出来的对象都是同一个
  • ptyhon的模块其实就是单例的,只会导入一次
  • 使用共享同一个实例的方法来创建单例模式
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()
c1 is c2 # true

结构型

代理模式

  • 把一个对象的操作代理到另一个对象
  • 通常使用has a 组合关系

适配器模式

  • 把不同对象的接口适配到同一个接口
  • 当我们需要给不同的对象统一接口的时候可以使用适配器模式

行为型

迭代器模式

  • python内置对迭代器模式的支持
  • 比如我们可以用for遍历各种Interable的数据类型
  • python里可以实现nextiter实现迭代器

观察者模式

  • 发布订阅是一种罪常用的实现方式
  • 发布订阅用于解耦逻辑
  • 可以通过回调等方式实现,当发生事件时,调用相应的回调函数

策略模式

  • 根据不同的输入采取不同的策略
  • 对外暴露统一的接口,内部采用不同的策略计算

函数式编程

map/reduce/filter

reduce(lambda x, y: x+y, range(1,6))

闭包

  • 绑定了外部作用域的变量的函数

  • 即使程序离开外部作用域,如果闭包仍然可见,绑定变量不会销毁

  • 每次运行外部函数都会重新创建闭包

  • 闭包:引用了外部自由变量的函数

  • 自由变量:不在当前函数定义的变量

  • 特性:自由变量会和闭包函数同时存在

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)

为什么用@wraps(func)

因为当使用装饰器装饰一个函数时,函数本身就已经是一个新的函数;即函数名称或属性产生了变化。所以在python的functools模块中提供了wraps装饰函数来确保原函数在使用装饰器时不改变自身的函数名及应有属性。
所以在装饰器的编写中建议加入wraps确保被装饰的函数不会因装饰器带来异常情况。
https://blog.csdn.net/yuyexiaohan/article/details/82860807

你可能感兴趣的:(【python面试指北】3.类和面向对象)