Python 语法(一)

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

1、Python 语言特性

1.1 Python 是静态还是动态?强还是弱类型

# 如:1 + '1'
# js,不会报错,因为内部进行了隐式类型转换
1 + '1' = '11'

# Python,报错
1 + '1' 

1.2 python 作为后端语言的优缺点

1.3 鸭子类型

当看到一只鸟走起来像鸭子,游泳起来像鸭子, 叫起来也像鸭子,那么这只鸟就可以被称为鸭子

class Duck:
    def quack(self):
        print('gua gua')
class Persopn:
     def quack(self):
        print('我是人类,但我也会 gua gua')
        
def in_the_forest(duck):
    duck.quack()

def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_fores(john)

我们关注的不应该是什么类型,而是实现了什么方法。上面鸭子和人类不是同一种类型,但是都实现了 quack() 方法,且都会 gua gua 叫,即也可以把人看做为 “鸭子”...

1.4 monkey patch(猴子补丁)

什么是猴子补丁,哪些地方用到?自己如何实现?

import socket
print(socket.socket)

print('after monkey patch')
from gevent import monkey
monkey.patch_socket()
print(socket.socket)

import select
print(select.select)
monkey.patch_select()
print('after monkey patch')
print(select.select)
<class 'socket.socket'>
after monkey patch              # 使用猴子补丁之后
<class 'gevent._socket3.socket'>
<built-in function select>
after monkey patch
<function select at 0x000001BF93821488>

应用场景:比较出名的是 gevent (Python 并发模块)使用猴子补丁修改了 socket 模块内部属性,使其变得非阻塞。

自己实现,替换内置的 time.time() 方法:

# 运行替换
import time
print(time.time())
 
def _time():
    return 1234
time.time = _time
print(time.time())

1.5 自省机制

所谓自省机制是运行时判断一个对象的类型和能力。

在日常生活中,自省(introspection)是一种自我检查行为。

计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力

也可以说:自省就是面向对象的语言所写的程序在运行时,能够知道对象的类型。

Python中比较常见的自省(introspection)机制(函数用法)有: dir(),type(), hasattr(), isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。

1、dir()

返回传递给它的任何对象的属性名称经过排序的列表。如果不指定对象,则 dir() 返回当前作用域中的名称。

>>> import keyword
>>> dir(keyword)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'iskeyword', 'kwlist', 'main']

# 也可以用来检查一个对象的所有方法或属性
class Foo:
    a = 1
    def func(self):
        return 'Hello World!'

f = Foo()
print(dir(f))

# 运行结果
['__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__', 'a', 'func']

2、type()

返回对象的类型:

>>> type(99)
<class 'int'>

3、hasattr()

判断对象是否拥有某个属性或方法

class Foo:
    a = 1
    def func(self):
        return 'Hello World!'

f = Foo()
print(hasattr(f, 'func'))

4、isinstance()

判断对象是否是某个类型:

>>> isinstance("python", str)
True


def add(a, b):
    is isinstance(a, int):
        return a + b
    elif  isinstance(a, str):
        return a.upper() + b

is 与 == 的区别

# 双等号比较的是两者值是否相等,is 比较的是内部内存地址是否相同
l1 = [1, 2, 3]
l2 = [1, 2, 3]
l1 == l2

l1 is l2        # False,内部比较的是 id(li)

1.6 列表和字典推导式

快速生成一个列表或字典或集合的方式

a = [''a', 'b', 'c']
b = [1, 2, 3]

# d = {'a': 1, 'b': 2, 'c': 3}
d = {}
for i in range(len(a)):
    d[a[i]] = b[i]
print(d)

d = {k: v for km v in zip(a, b)}

1.7 知道python 之禅?

输入 import this 即可查看

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

1.8 Python2/3 的差异

Python3 的变化

# type hint
def hello(name: syr) -> str:
    return 'hello' + nam
a, b,_c = range(10) # 丢弃后面的参数不要

Python3 改进

# 限定关键字参数
def (a, b, c=3):
    pass

# 抛出异常
import shutil

# python2 里会丢失原来的 traceback信息
def mycopy(source, dest):
    try:
        shutil.copy2(source, dest)
    except OSError:
        raise NotImportedError('automatic sudo injection from OSError)

mycopy('old' ,'new')

新增的语法

Python2/3 兼容工具

2、Python 函数

2.1 函数传参

函数传参常考的,传递的参数分为可变和不可变类型,下面是一个小示例:

# 可变不可变。传参类型
def flist(l):
    l.append(0)
    print(l)

ll = []
flsit(ll)        # [0]
flist(ll)        # [0, 0]

def fstr(s):
    s += 'a'
    print(s)

ss = 'hehe'
fstr(ss)     # hehea
fstr(ss)     # hehea

这是因为形参和实参指向的是同一个对象,可变对象可以修改对象的值,不可变对象不可修改,因此它在进行赋值的时候只能重新新建一个,然后标识(变量)重新指向新的值。

Python 如何传参(容易混淆的问题)

image

2.2 可变不可变类型

2.3 可变参数作为默认参数

默认参数只计算一次

def flist(l=[1]):
    l.append(l)
    print(l)

flist()
flist()

2.4 *args, 和 **kwargs

def fuunc(*args):
    print(type(args), args)
    for index, value, enumerate(args):
        printidnex, value)

2.5 异常机制

异常类继承关系:

[图片上传失败...(image-1e0dd7-1593094235780)]

使用场景

image

如何自定义异常

class MyException(Exception):
    pass

try:
    raise MyException('my exception')
exception exception as e:
    print(e)

3. 分析和优化 GIL 问题

GIL(Global Interpretyer Lock) 全局解释锁,这是从 Python 解释器层面给进程加的一把锁,其目的是为了保证线程的安全

其核心思想是,无论开了个少个线程,有多少个 CPU(多核),Python 解释器在执行时,在同一时刻只允许一个线程运行。只有 cpython 采用 GIL。

优缺点

区分 CPU 和IO 密集程序 (如何规避 GIL 影响)

[图片上传失败...(image-521445-1593094235780)]

多线程有面临着安全问题,上一个线程没有执行完毕,就被另一个线程覆盖:
[图片上传失败...(image-3baefc-1593094235780)]

3.1 为什么有了 GIL 还要关注线程安全

Python 中声名操作才是原子的?一步到位完成的

[图片上传失败...(image-a1d205-1593094235780)]

[图片上传失败...(image-817b9a-1593094235780)]

通过加锁来保证线程安全

[图片上传失败...(image-16b6ee-1593094235781)]

3.2 如何剖析程序性能

使用各种 profile 工具(内置或第三方)

3.3 服务端性能优化

Web 应用一般语言不会成为瓶颈

4. 生成器和协程

4.1 生成器 generator

def func():
    yield 'hello'
    yield 'world'
f = func()
print(next(f))

4.2 基于生成器的协程 Python2

Python3 之前的没有原生协程, 只有基于生成器的协程

image

[图片上传失败...(image-1f98d6-1593094235781)]

协程装饰器(参考书籍:流畅的 Python)

[图片上传失败...(image-8692d3-1593094235781)]

原生协程

async /await 支持原生的协程(native coroutine)

impory asyncio
import datetime
import random

async def display_date(num, loop):
    end_time = loop.time() + 50.0
    while True:
        pirnt('Loop: {} Time: {}' .formate(num, datatime.datetime.now()))
        if (loop.time() + 1.0) >= end_time:
            break
        await asyncio.sleep(random.randint(0, 5))

loop = asyncio.get_event_loop()
asyncio.ensure_future(dsiplay_date(1, loop))
asyncio.ensure_future(display_date(2, loop))
loop.run_forever()

5. 单元测试

为什么写单元测试

相关库

如何设计测试用例(等价类划分)
正常值功能测试
边界值测试(如最大最小,最左最右)
异常值(如 None,空值,非法值)

下面是一个 pytest 的小示例,需要先安装:pip3 install pytest

def binary_search(array, target):
    if not array:
        return -1
    beg, end = 0, len(array)
    while beg < end:
        mid = beg + (end - beg) // 2
        if array[mid] == target:
            return mid
        elif array[mid] > target:
            end = mid
        else:
            beg = mid + 1

    return -1


def test():
    assert binary_search([0, 1, 2, 3, 4, 5], 1) == 1

使用方法:pytest xxx.py,会自动执行 test开头的函数:

=============================== test session starts ===========================================
platform win32 -- Python 3.6.5, pytest-5.0.0, py-1.8.0, pluggy-0.12.0
rootdir: E:\Python_virtualenvs\for_django\Projects\restfulwork
plugins: celery-4.3.0
collected 1 item                                                                                                              

t.py .                                          [100%]                                                                                      
=============================== 1 passed in 1.01 seconds =====================================

6. Python 常见练习题

1、深拷贝和浅拷贝区别

2、Python 中如何正确初始化一个二维数组?

7. 面试题

1、请至少列举 5 个 PEP8 规范

每一级四个缩进、类名首字母大写、导入包和类函数之间使用两个空格、规定每行最多 79 个字符、不能一句 import 导入多个库

2、什么是动态、静态语言,编译型、解释性语言?

3、ascii、Unicode、utf-8、gbk 的区别

4、字节码和机器码区别?

5、Python2/3的区别

6、lambda 表达式格式及应用场景

比传统函数更加灵活,可以在程序中被传递和调用,用来替换局部函数

lambda 参数: 表达式      # lambda x: 2x
# 示例
func2 = lambda a1, a2: a1 * a2
print(func2(12, 1000))

# sort 中对列表排序,key 会作用到列表的每个元素,x 为参数,即列表的每个元素,x[1] 即每个元组的第二个元素,这里指的是用元组的第二个元素来排序
a = [('b', 4), ('a', 12), ('d', 7), ('h', 6), ('j', 3)]
a.sort(key=lambda x: x[1])
print(a)        # [('j', 3), ('b', 4), ('h', 6), ('d', 7), ('a', 12)]

常与一些内置函数相结合使用,如过滤、排序等

7、正则表达式匹配文本

import re

url = 'http://127.0.0.1:8000?name=rose&age=18'
pattern1 = re.compile('name=(.+?)&')
pattern2 = re.compile('http.*?name=(.+?)&')
pattern3 = re.compile('.*?name=(.+?)&')

result1 = re.findall(pattern, url)  # 查询所有,列表
print(result1)

result2 = re.search(pattern2, url) # 查询第一个
print(result2.group(1)) if result2 else print('没有匹配成功')

result3 = re.match(pattern3, url) # 从头开始匹配
print(result3.group(1)) if result3 else print('没有匹配成功')

8、可变与不可变类型

9、浅拷贝与深拷贝的实现方式、区别,deepcopy 如果你来设计,如何实现?

# 由于共享内存导致的结果
import copy

a = [1, 2, 3, [4, 5]]

b = copy.copy(a)
print(b)

b[3][0] = 'h'
print(a)
print(b)

a[0] = 'e'
print(a)
print(b)

--------

[1, 2, 3, [4, 5]]
[1, 2, 3, ['h', 5]]
[1, 2, 3, ['h', 5]]
['e', 2, 3, ['h', 5]]
[1, 2, 3, ['h', 5]]

浅拷贝只拷贝第一层,a 修改第一层, 对 b 没影响,b 修改第二层,对 a 的第二层有影响。两种共享第二层内存

深拷贝:

import copy

a = [1, 2, 3, [4, 5]]

b = copy.deepcopy(a)
print(b)

b[3][0] = 'h'
print(a)
print(b)

a[0] = 'e'
print(a)
print(b)

------
[1, 2, 3, [4, 5]]
[1, 2, 3, [4, 5]]
[1, 2, 3, ['h', 5]]
['e', 2, 3, [4, 5]]
[1, 2, 3, ['h', 5]]

内存地址完全不共享,修改 a 的第一层,对比 b 无影响,修改 b 的第二层对 a 不影响。

9、__new__()__init__()的区别

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

    def __init__(self):
        pass

10、你知道几种设计模式

单例、享元、工厂、装饰器

11、编码和解码你了解?

>>> b = b"example"                    
>>> s = "example"                     
>>> sb = bytes(s, encoding='utf-8')   
>>> sb                                
b'example'                            
>>> str(b, encoding='utf-8')          
'example'                             
>>> str.encode(s)                     
b'example'                            
>>> bytes.decode(b)                   
'example'                             

12、列表推导 list comprehension 和生成器的优劣

列表推导式:

l = [x**2 for x in range(10) if x % 2 == 0]
print(l)

生成器:

# 生成器函数
def func(li):
    for x in li:
        yield x**2

li = [1, 2, 3, 4]
f = func(li)
print(next(f))
print(next(f))
print(next(f))

# 生成器表达式
li = (x**2 for x in range(10) if x % 2 == 0)
print(li)
print(next(li))

将列表生成式中[]改成() 之后数据结构是否改变? 答案:是,从列表推导式变为变为生成器

12、什么是装饰器;如果想在函数之后进行装饰,应该怎么做?

装饰器可以用来装饰一个函数或者类,让函数或类拥有额外的功能,在执行函数之前, 进行一些提前的处理。如:检查 Django 登录、login_required

@check_login
def func():
    pass

13、手写个使用装饰器实现的单例模式

def singleton(cls):
    isintances = {}
    def wrapper(*args, **kwargs):
        if cls not in isintances:
            isintances[cls] = cls(*args, **kwargs)
        return isintances[cls]
    retun wrapper


@singleton
class Bar:
    pass

s = SingleSton()

14、使用装饰器的单例和使用其他方法的单例,在后续使用中,有何区别

Import 方法改变了类本身,new方法,只是把所有实例对象共享属性,每次产生一个新对象。算作伪单例,共享属性方法实例化了许多个相同属性。所以,装饰器方法最为实用。

10、手写:正则邮箱地址

[a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z]+     # + 表示匹配多个

15、
介绍下垃圾回收:引用计数/分代回收/孤立引用

采用的是引用计数为主,标记清除和分代回收为辅的策略。

PythonGC 模块主要运用了引用计数来跟踪和回收垃圾,在引用计数的基础上,还可以通过 标记-清除 解决容器对象可能产生的循环引用的问题,通过分代回收以空间换取时间进一步提高垃圾回收的效率。

在Python中,为了解决内存泄露问题,采用了对象引用计数,并基于引用计数实现自动垃圾回收。

16、多进程与多线程的区别;CPU密集型适合用什么

原因:进程全局锁(Global Interpreter Lock), 即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程

17、进程通信的方式有几种

队列 Queue、管道、Managers

https://www.cnblogs.com/guguobao/p/9398653.html

18、介绍下协程,为何比线程还快

进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户自己控制切换的时机,不再需要陷入系统的内核态。

因为线程会等待,遇到 IO 会阻塞,而协程遇到 IO 阻塞可以去处理别的请求,等 IO 阻塞过去了,可以调用回调函数执行别的操作

19、xrange 与 range 的区别

20、将IP地址字符串(比如“172.0.0.1”)转为32位二进制数的函数

十进制转二进制:

>>> a = 172
>>> b = '{:08b}'.format(a)      # 高位补零
>>> b
'10101100'
    
>>> '{:8b}'.format(8)           # 高位不补零
'    1000'
def transfer():
    s = []
    for i in ips:
        ret = '{:08b}'.format(int(i))
        s.append(ret)

    return '.'.join(s)

if __name__ == '__main__':
    ip = '172.0.0.1'
    ips = ip.split('.')
    print(transfer())

结果:

10101100.00000000.00000000.00000001

参考文档:https://blog.csdn.net/daydayjump/article/details/80705131

Python 内置进制转换

# 十进制转十六进制
>>> hex(8)
'0x8'

# 十进制转八进制
>>> oct(8)
'0o10'

# 十进制转二进制
>>> bin(8)
'0b1000'

# 转换一个[0, 255]之间的整数为对应的ASCII字符
>>> chr(65)
'A'
>>> chr(97)
'a'

# 一个ASCII字符转换为对应整数
>>> ord('A')
65

int(x, base=10) 函数

int() 函数可以将一个字符串(整数字符串)转换为整数,默认转换为十进制,也可以自定义转换进制:

# 十六进制转十进制
>>> int('0x10', base=16)
16
>>> int('10', 16)       # 简写
16

# 八进制转十进制
>>> int('0o10', base=8)
8
>>> int('10', base=8)
8

# 二进制转十进制
>>> int('0b1010', base=2)
10
>>> int('1010', base=2)
10

参考文章:Python内置进制转换函数(实现16进制和ASCII转换)

21、不用中间件,交换 a 和 b 的值

a, b = b, a

22、import 原理

23、编码问题

24、跨域问题

浏览器的同源策略限制,不是同源的脚本不能操作其他源下面的资源,想操作另一个源下面的资源就属于跨域。

只要协议、域名、端口有任何一个不同,都被当作是不同的域,不同域之间的请求就是跨域操作。AJAX跨域就是AJAXA服务器下对B服务器发送了 ajax 请求,一般情况下会被浏览器禁止。

解决办法:

<script>
    // 向另一台服务器 JSONP2 发送请求
    // 使用 jQuery 发送,不需要创建新的 script 标签,其内部会自动帮忙创建,并删除
    function btn3() {
    $.ajax({
        url: 'http://127.0.0.1:8000/app/index/',
        type: 'get',
        dataType: 'jsonp',
        jsonp: 'callback',
        jsonpCallback: 'list'
    })
}

function list(arg) {
    console.log(arg);
}
</script>

如果缺少了同源策略,浏览器很容易受到XSS(跨站脚本攻击 cross site scripting)和CSRF(跨站请求伪造cross-site request forgery)等攻击。

参考文章:python 跨域处理方式

25、手写 IP 正则

这里讲的是IPv4的地址格式,总长度 32位=4段*8位,每段之间用.分割, 每段都是0-255之间的十进制数值。

将0-255用正则表达式表示,可以分成一下几块来分别考虑:

|   或
?   匹配前面的字符或数字 0 次,或 1次
\d  匹配一个数字
\.  将 . 转义为一个普通的点,点在正则中有特殊含义,所有需要转义
取值区间 特点 正则写法 可合并的写法 可合并的写法 可合并的写法
0-9 一位数,只有个位,取值是0~9 \d [1-9]?\d (1\d{2})|([1-9]?\d) (25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))
10-99 两位数,十位取值1-9,个位取值是0~9 [1-9]\d
100-199 三位数,最高位取值为1,十位取值0-9,个位取值0-9 1\d{2} -
200-249 三位数,最高位取值为2,十位取值0-4,个位取值0-9 2[0-4]\d - -
250-255 三位数,最高位取值为2,十位取值5,个位取值0-5 25[0-5] - -

IP地址格式可表示为:XXX.XXX.XXX.XXX,XXX取值范围是0-255,前三段加一个.重复了三次,在与最后一段合并及组成IP地址的完整格式。

所以IP地址的正则表示法如下:

((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))

26、请简述值传递和引用传递的区别?

27、Kafka 怎么判断重复消费,怎么清除历史记录

kafka是一个分布式消息队列。具有高性能、持久化、多副本备份、横向扩展能力。生产者往队列里写消息,消费者从队列里取消息进行业务逻辑。一般在架构设计中起到解耦、削峰、异步处理的作用。

28、ajax、csrf、jsonp

1、Ajax

Ajax:Asynchronous JavaScript and XML (异步的 JavaScript 和 XML),是一种创建交互式网页应用的网页开发技术方案。

利用 Ajax 可以偷偷向后台发送请求,而页面不会刷新,在有些方面有很大作用:

  1. 注册时,输入用户名自动检测用户名是否已存在。
  2. 登录时,提示用户名和密码错误。
  3. 删除数据行时,将 ID 发送到后台,后台在数据库删除,数据库删除成功后,在前端 DOM 中也将数据行删除。

实现 ajax 的三种方法:

  1. 原生 Ajax:不需要客户端加载 jQuery,依赖浏览器类库,但是 IE 早期版本没有提供相应类库(XMLHttpResponse 对象)。
  2. jQuery 实现:发起请求时,会将 jQuery 加载到客户端,对于一些比较小的 Web 程序无疑增加了负担。
  3. iframe 标签 + form 表单:兼容性最好

29、jsonp 跨域请求

这是在前端解决跨域请求问题,也可以从 Django 后端解决:有相应插件(中间件形式)

要想向远程服务器发送请求,那么必须 绕过浏览器的同源策略、或者让浏览器觉得这是可信性的

浏览器同源策略: XMLHttpResponse 对象只能在本地发送请求,不能向远程服务器发送请求,响应会被浏览器阻止。

解决方法: JSONP 是一种绕过浏览器同源策略的方式,利用的是 HTML 中某些含 src 属性的标签不遵循同源策略的特性,巧妙地绕过同源策略。如:script 标签

每发送一次请求,便新建一个 scrip 标签,src 路径为远程服务器地址,请求完毕获得数据后便将其删除

30、 RabbitMQ、celery

1、Celery

Celery 是一个 基于 Python 开发的分布式异步消息任务队列,可以实现任务异步处理,制定定时任务等

Celery 在执行任务时需要通过一个消息中间件来接收和发送任务消息,以及存储任务结果, 一般使用 rabbitMQRedis(默认采用 RabbitMQ)

优点:

Celery 主要模块:

image

应用场景:


2、RabbitMQ

RabbitMQ 是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。

特点:

应用场景:比如业务服务模块解耦,异步通信,高并发限

参考:https://www.cnblogs.com/wanglijun/p/10896896.html

31、手写一个装饰器

1、手写个使用装饰器实现的单例模式

def singleton(cls):
    isintances = {}
    def wrapper(*args, **kwargs):
        if cls not in isintances:
            isintances[cls] = cls(*args, **kwargs)
        return isintances[cls]
    retun wrapper


@singleton
class Bar:
    pass

s = SingleSton()

2、手写一个装饰器

登录认证

def check_login(func):
    def wrapper(request, *args, **kwargs):
        is_login = request.session.get('is_login', False)
        if is_login:
            func(request, *args, **kwargs)
        else:
            return redirect('/')
    return wrapper

带参数装饰器:

def log(text):
    def inner(func):
        def wrapper(*args, **kwargs):
            pass
        return wrapper
    return inner

@log('hello')
def index(name, age, gender):
    return 'index 返回'

i = index('rose', 18, 'female')
print(s)

32、短路求值

a = 10
b = 20
print(a and b)  # a、b 皆为真,所以取最后一个真,即 20
print(a or b)   # a、b 皆为真,所以取第一个真,即 10

运行结果:

20
10
a = 10
b = 0

print(a and b)  # a 为真,b 为假,取第一个假值,即 0

33、is 和 == 的区别

34、求值(函数闭包)

def num():
    return [lambda x: x * i for i in range(4)]

print(m(4) for m in num())

# 结果为 [12, 12, 12, 12]

原因:i 在闭包作用域,闭包中用到的变量的值,是在内部函数被调用时查询得到的,所以 num() 返回的是 [lambda x: 3x, lambda x: 3x, lambda x: 3x, lambda x: 3x],再乘以 4,就是四个 12 了。

35、谈谈对函数闭包的理解?

一个外部函数定义了一个内部函数,内部函数调用了外部函数的临时变量,并且外部函数的返回值是内部函数的引用,这样就构成了一个闭包。

36、一行代码实现删除列表中重复的值?

list(set(li))

先转换为集合,再转换为列表

37、json 序列化支持的数据类型?如何支持 datatime 时间类型?

支持的类型:string、int、list、tuple、dict、bool、None

import json
import datetime

class CJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        # 若是 datetime 类型就转换为字符串,否则使用默认的方式序列化
        if isinstance(obj, datetime.date):
            return obj.strftime("%Y-%m-%d %H:%M:%S")
        else:
            return json.JSONEncoder.default(self, obj)
        
now = datetime.datetime.now()
print(json.dumps(now, cls=CJsonEncoder))

38、json 序列化时,遇到中文默认会转换为 Unicode,若想保留中文,该怎样做?

json.dumps(obj, ensure_ascii=False)

39、用代码实现查看列举目录下所有文件

import os
path = "C:\\Users\\hj\\Desktop\\笔记"
file_list=[]

def check_file(path):
    if os.path.isdir(path):
        for file in os.listdir(path):
            base_url = os.path.join(path, file)
            if os.path.isfile(base_url):
                file_list.append(file)
        return file_list
    else:
        return os.path.basename(path)
    
print(check_file(path))
上一篇下一篇

猜你喜欢

热点阅读