编程范式(二)

2020-06-25  本文已影响0人  焰火青春

1. 编程范式考察

1.1 面向对象基础及常考题

什么是面向对象

1.2 组合与继承

1.3 类变量和实例变量区别

1.4 classmethod 和staticmethod 区别

1.5 元类 Meta Class

创建类的类

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

2. 装饰器

什么是装饰器

一切皆对象,函数也可以当做参数传递,装饰器是接收函数作为参数,添加功能返回一个新函数的类
记录函数耗时的装饰器

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)

使用类编写装饰器

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 res 
    return _log

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

给装饰器增加参数

import time 
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
    
@LogTime()
def mysleep():
    time.sleep(1)

3. 设计模式

设计模式总共分为三类:创建型、行为型、结构型

3.1 创建型模式

1、工厂模式

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()

2、 构造模式

3、原型模式

4、单列模式
实现方式有多重

[图片上传失败...(image-a2f03d-1593095673773)]

3.2 结构型模式

1、代理模式
吧一个对象的操作代理到另一个对象
通常使用 has-a 组合关系
之前实现的 Stack/Queue,把操作代理到 deque 中

2、 适配器模式

想象一个多功能充电头,可以给不同充电器充电,充当了适配器,当要给你不同接口实现统一的接口

class Dog:
    def __init__(self):
        self.name = 'Dog'
    
    def bark(self):
        return 'woof!'
    
class Cat:
    def __init__(self):
        self.name = 'cat'
    
    def bark(self):
        return 'meow!'
    
class Adapter:
    def __init__(self, oj, **adapted_methods):
        self.obj = obj
        self.__dict__.update(adapted_methods)
       
    def __getattr__(self, attr):
        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.bark))
for obj in objects:
    print('A {0} goes {1}'.format(obj.name, obj.make_noise()))

3.3 行为型模式

1、 迭代器模式

迭代器必须实现 __iter__()/__next__() 方法,可以用 for 循环迭代

2、 观察者模式

3、策略模式

class Order:
    def __init__(self, price, discount_strategy=None):
        self.price = price
        self.discount_strategy = discount_strategy
        
    def price_after_discount(self):
        if self.discount_strategy:
            discount = self.discount_strategy(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.10
    
    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=ten_percent_discount)
        print(order0)
        print(order1)
        print(order2)

[图片上传失败...(image-26dbd8-1593095673773)]

4. 函数式编程

list(map(lambda x:x*2, range(10)))

什么是闭包

Closure:一个内部函数对外部作用域(而不是全局作用域)的变量进行引用,那么就可以认为这个内部函数时一个闭包

def func1():
    a = 1
    def func2():
        # nonlocal a
        a = a + 1
        return a
    return func2

f1 = func1()
print(f1())

如果不指定 nonllocal 关键字,则会报错:

UnboundLocalError: local variable 'a' referenced before assignment

使用场景

def make_filter(kwd):
    def the_filter(file_name):
        file = open(file_name)
        lines = file.readlines()
        file.close()
        filter_doc = [i for i in lines if kwd in i]
        return filter_doc

    return the_filter

filter = make_filter("pass")
filter_result = filter("result.txt")

如果我们需要取得文件 result.txt 中含有 pass关键字的行

参考文章:https://blog.csdn.net/marty_fu/article/details/7679297

5. 面试题

1、简单介绍项目(主要体现你在项目中充当什么角色)

2、你在项目中遇到最难的部分是什么?怎么解决的?

3、看过 Django admin 源码?看过 flask 源码?如何理解开源?

写过类似 Django admin 的一个组件,叫做 kingadmin

Django 启动时,它会遍历 setting 中 install_app 中所有 app,再通过 __import__ 导入所有 app 中的 admin.py 模块。

admin.py 中将所有要注册的模型注册到 site.register 中。

4、MVC / MTV

1、MVC 模式

将 Web 应用分为:模型(M)、控制器(C)以及视图(V)三部分

2、MTV

Django 特有的,也是 MVC 的一种

还有一个 url 控制器,将一个个 URL 请求分发不同的 view 处理,view 再调用 M 和 T。

[图片上传失败...(image-cbf0af-1593095673773)]

5、缓存怎么用?

数据库、文件、内存、memcached、redis,缓存仅适合页面实时性要求不高的页面

6、中间件是用来干嘛的?

中间件是一个用来处理Django的请求和响应的框架级别的钩子,可以用来处理一些全局性的事情。比如在请求之前干嘛、处理视图函数之前做 csrf 验证等等。

Django 的生命周期是:前端请求--->nginx--->uwsgi.--->中间件--->url路由---->view试图--->orm---->拿到数据返回给view---->试图将数据渲染到模版中拿到字符串---->中间件--->uwsgi---->nginx---->前端渲染。

中间件的作用非常大,可以处理所有的请求内容,中间件其实就是一个类,这个类中一共有5个方法,分别是 process_request, process_response,process_view, process_exception,process_render_template

参考:

7、CSRF 是什么?Django 是如何避免的?XSS 呢?

CSRF:跨站请求伪造,当客户端向服务端发起 post 、delete、put 请求时,必须携带相关证明,才能通过。

分为全局和局部避免:

全局:

# 通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成验证
# 中间件中的process_view 方法中验证csrf,首先检查该函数是否设置了@csrf_exempt如果设置了,就免除验证,否则在这里进行csrf_token的验证

局部:

# 装饰器
# @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
# @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

模板中添加:

# 当要向后台发送 post 请求时
# form 表单,添加 {% csrf_token %} 即可

# ajax
# 添加 {% csrf_token %},它会生成一个隐藏的 input 标签,获取其 value 值,然后一起提交到后台

2、XSS是什么?它的全名是:Cross-site scripting,为了和CSS层叠样式表区分所以取名XSS。是一种网站应用程序的安全漏洞攻击,是代码注入的一种。如果允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。

恶意攻击者往Web页面里插入恶意script代码,当用户浏览该页之时,嵌入其中Web里面的script代码会被执行,从而达到恶意攻击用户的目的。

防御措施:

如果我们真的需要有个script显示到前端就用mark_safe

参考文章:https://www.cnblogs.com/sticker0726/articles/10565286.html

8、如果你来设计 login,简单说一下思路

9、session 和 cookie 的联系和区别?为什么说 session 是安全的?

cookie和session都是用来跟踪浏览器用户身份的会话方式

因为如果 session 存储在客户端上,可能被伪造,拿来攻击服务器

10、uWSGI 和 Nginx 的作用

11、Django 的生命周期

前端请求--->nginx--->uwsgi.--->中间件--->url路由---->view试图--->orm---->拿到数据返回给view---->视图将数据渲染到模版中拿到字符串---->中间件--->uwsgi---->nginx---->前端渲染

**12、__new__()__init__()的区别****

class Foo:
    def __new__(cls):
        return object.__new__(cls)

    def __init__(self):
        pass

13、 Tornado、Flask 和 Django

Tornado

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

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    # 请求方式(get、post、delete...)
    def get(self):
        self.write("Hello, world")

# 路由映射
application = tornado.web.Application([
    (r"/index", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)    # 监听 8888 端口
    tornado.ioloop.IOLoop.instance().start()

非阻塞:

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

import tornado.ioloop
import tornado.web
from tornado import gen
from tornado.concurrent import Future


class AsyncHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        future = Future()
        future.add_done_callback(self.doing)    # 请求成功,回调函数
        yield future
        # 或
        # tornado.ioloop.IOLoop.current().add_future(future,self.doing)
        # yield future

    def doing(self, *args, **kwargs):
        self.write('async')
        self.finish()

application = tornado.web.Application([
    (r"/index", AsyncHandler),
])


if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()

Flask

from flask import Flask

app = Flask(__name__)


@app.route("/")
def index():
    return "Index Page"


if __name__ == "__main__":
    app.run()

14、谈谈对面向对象的理解?

面向对象是向现实世界模型的自然延伸,是一种 万物皆对象 的编程思想。在现实生活中任务物体都可以归为一类事物,而每个个体都是一类事物的实例。面向对象编程是以对象为中心,以消息为驱动,所以程序=对象+消息。

面向对象编程(OOP):是一种解决软件复用的设计和编程方法,它把软件系统中相似近似的操作逻辑和操作应用数据、状态,以类的形式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

15、Python 面向对象继承特点?

在调用方法时,总是首先查找对应类型的方法,若不能在派生类中找到对应的方法,才开始到基类中逐个查找。

16、Python 面向对象深度优先和广度优先是什么?

Python 面向对象多继承查找类方法的方式(算法):

class A(object):
    def test(self):
        print('A')

class B(A):
    def test(self):
        print('B')
        
class C(A):
    def test(self):
        print('C')
        
class D(B):
    def test(self):
        print('E')
        
class E(C):
    def test(self):
        print('E')
        
class F(D, E):
    def test(self):
        print('F')
        
f1 = F()
f1.test()
print(F.__mro__)  

# 新式类
F --> D --> B --> E --> C --> A --> object  

# 经典类
# F --> D --> B --> A --> E --> C
image

17、类中 __new__、__init__ 的区别?

18、静态方法和类方法区别?

class Foo:
    name = 'rose'
    
    @staticmethod
    def func1(gender):
        print(gender)
        
    @classmethod
    def func2(cls):
        print(cls.name)
        
f = Foo()

# Foo.func1("female")
f.func1("male")
Foo.func2()
# f.func2()

19、用尽量多方法实现单例模式

基于new() 方法

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.instance = super().__new__(cls)
            
        return cls.instance

a = Person('p1', 21)
b = Person('p2', 22)

装饰器形式

def sigleton(cls, *args, **kwargs):
    instance_dic = {}
    def inner(*args, **kwargs):
        if cls not in instance_dic:
            instance_dic[cls] = cls(*args, **kwargs)
        return instance_dic[cls]
    return inner

@sigleton
class Person:
    pass

20、装饰器的写法及应用场景

def wrapper(func, *args, **kwargs):
    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        return result

    return inner

应用场景:登录测试、插入日志、性能测试、事务处理、缓存等

上一篇下一篇

猜你喜欢

热点阅读