Python学习笔记--函数

1.如何理解函数?

  • 函数就是一个容器,把原来的代码放到一起。

2.如何运行函数?

  • 函数是分为两个阶段 定义和调用。
  • 调用是函数名+() 来调用。

3.如果直接调用函数名,不加()会发生什么?

  • 会打印出函数名所在的内存地址。
def foo():
    print("hello ")

print(foo)  # 打印foo的内存地址
foo()   # 调用函数()

====结果为====
<function foo at 0x000001526568D3A0>
hello
  • 这里面涉及到一个隐藏的知识点,
  • 就是当我们定义一个x=10的时候,是把10的内存地址给了x,当我们打印x的时候,却没有打印出内存地址,打印出的是数值10,为什么?
  • 这是因为Python对这种简单的做了特殊处理,因为90%人们是希望通过x获取到10的值,而不是打印出10的内存地址。
  • 而函数为什么又打印内存地址呢?
  • 如果调用函数的名字,就打印出函数体里面的内容,这种场景90%的人们都用不上。所以,就没有进行特殊处理。
  • (这里的90%是我瞎说的)

4.如果理解函数先定义后调用?

def foo():
    print("hello ")
    bar()
# foo() 在这执行会报错
def bar():
    print("123")

foo()   # 充分理解, 函数先定义后执行

5.函数可以分为自定义函数和内置函数?

  • 对的

 6.函数的形参和实参如何区分?

  • 定义阶段是形参
  • 调用阶段是实参

def foo(x,y):   # x和y是形参
    return x+y

foo(1,2)    # 1和2是实参
m = 5
n = 6
foo(m,n)    # m和n是实参
  • View Code

7.位置实参必须在关键字实参前面?

  • 是的

def foo(x,y,z):
    pass
foo(1,y=2,3)
# 报错 SyntaxError: positional argument follows keyword argument
  • View Code

8.默认形参该怎么用?

  • 注意:
  • 1.位置形参必须在默认形参前面 
  • 2.默认形参应该是不可以变类型
  • 3.默认形参的值是在定义阶段进行赋值的
  • 示例1:

def foo(name,hobby,hobbies = None):
    if hobbies is None:
        hobbies = []
    hobbies.append(hobby)
    print(f"{name} 爱好是 {hobbies}")

foo("liqi","eat")
foo("tom","read",["movie"])
  • View Code
  • 示例2:

m = 111
def foo(x,y,z=m):
    print(x)
    print(y)
    print(z)
m = 666
foo(1,2)    # 考察z在定义阶段
  • View Code

9.当往函数里面传参数时,不确定实参的数量,该怎么办?

  • 定义函数的时候,用*或者**来解决。
  • 实参无非两种形式
  • 溢出的位置参数 —— *
  • 溢出的关键字参数—— **
  • 代码1

# 溢出的位置参数用*
def func(x,*y):
    print(x)
    print(y)

func(1,2,3,4,5)
# 1
# (2, 3, 4, 5)
# *会以元组的形式接受溢出的位置参数,赋给y
  • View Code
  • 代码2

# 溢出的关键字参数**
def func(m,**kwargs):
    print(m)
    print(kwargs)

func(3,x=3,y=10,z=8)
# 3
# {'x': 3, 'y': 10, 'z': 8}
# **会将溢出的关键字参数合并为一个字典,赋给kwargs
  • View Code

10.可变参数有什么应用吗?

  • 比如,求任意几个数的和

def func(*x):
    res = sum(x)
    print(res)

func(1,2,3,4,5,999)
  • View Code

 11.在定义阶段,*的做用时汇集,在调用阶段,*的作用是什么?

  • 打散
  • 比如:

def fun(x,y,z):
    print(x,y,z)

# fun([1,2,3]) 报错
fun(*[1,2,3])
# 1 2 3
  • View Code
  • ** 的示例

def fun(x,y,z):
    print(x,y,z)

fun(**{"x":1,"y":3,"z":5})  # **会打散为关键字参数 x=1,y=3,z=5
# 1 3 5
  • View Code

12.函数调函数,*和**可以把参数原封不动的转交给另外一个函数吗?

  • 可以
  • 示例

def index(x,y,z):
    print(x,y,z)

def wrapper(*args,**kwargs):
    print(args)
    print(kwargs)
    index(*args,**kwargs)   # 会报错,相当于index(1,2,4,5,6,a=1,b=2,c=3)

wrapper(1,2,4,5,6,a=1,b=2,c=3)
  • View Code

13.函数名可以当做变量来使用吗?

  • 可以。
  • 示例代码

def func():
    print("from func")

# f = func  # 当做变量赋值
# f()   # 调用
def aaa(x):
    print("aaa执行了")
    x()

aaa(func)   # 函数名可以当做变量来传递
  • View Code

14.如何优雅的改下if的多分支功能?

  • 把函数名当做容器的元素

1 def withdraw():
 2     print("取款")
 3 def deposit():
 4     print("存款")
 5 def check_balance():
 6     print("查询余额")
 7 def transfer():
 8     print("转账".center(20,"="))
 9 
10 bank_dict = {
11     "1":["取款",withdraw],
12     "2":["存款",deposit],
13     "3":["查询余额",check_balance],
14     "4":["转账",transfer],
15 }
16 while True:
17     print("0 退出")
18     for k,v in bank_dict.items():
19         print(k,v[0])
20         
21     choice = input("输入要执行的编号:")
22     if choice == "0":
23         break
24         
25     if choice in bank_dict:
26         bank_dict[choice][1]()
27     else:
28         print("输入有误!!")
  • View Code

 15.什么是名称空间,顶级名称空间有哪些?

  • Namespaces are one honking great idea -- let's do more of those!
  • 名称空间,是python的一个伟大的思想。
  • 顶级名称空间最简单的划分就是,观察是否在函数体内。
  • 例如,
x = 10
if x >2:
    y = 20
with open("a.txt","wt",encoding="utf-8")as f:
    date = f
    
while True:
    Z = 99
  • 名称空间

16.名称空间的一些区别?

  1. 内置名称 (跨模块名称)
  2. 全局名称
  3. 局部名称
  • 范围由大到小是: 1 > 2 > 3  
  • 查找循序是:根据目前所在的位置由下(3)至上(1)查找。
  • LEGB是什么?(面试会问)
  • 是名称空间的访问顺序,local --从局部开始查找..

 

17. 名字空间与作用域的关系是在定义阶段就决定了?

  • 是的
x = 111
def fun_1():
    print(x)

def func_2():
    x = 222
    fun_1()

func_2()
#答案是 111
x = 111
def func():
    print(x)    
    # 这个报错是,在语法扫描的时候,在本函数内找到了,绑定在本函数内。
    # 但执行的时候,是先执行,后定义,所以执行错误。 
    x = 222

func()

18.闭包函数是什么?

  • 闭:该函数定义在函数内的函数
  • 包:该函数引用了一个外层函数作用域的名字
def outter():
    x = 111
    def wrapper():
        print(x)

19.闭包函数,可以把内部的函数扔出来吗?

  • 可以
def outter():
    x = 111
    def wrapper():
        print(x)
    return wrapper    # 不加括号,把内部函数扔出来

 20.闭包函数如何传参数?

  •  最简单的一种
def outter(x):
    def wrapper():
        print(x)
    return wrapper

f = outter(111)
f()

21.什么是装饰器?

  • 给原有的工具增加的新的功能

22.为何要用装饰器?

  • 开放封闭原则:一旦项目上线后,应该对修改源代码封闭,对外扩展开发
  • 原则1:不修改源代码
  • 原则2:不改变源代码的调用方式
  • 装饰器就是在遵循原则1和原则2的前提下,实现给原来的函数增加新功能的东西。

23.如何实现装饰器?

  • 构造一个简单的装饰器的功能
  • 第一步,正常加功能,
  • 第二步,构造外层函数
  • 第三步,返回未闭合的内部函数名
  • 第四步,偷梁换柱
def index():
    time.sleep(1)
    print("from index")

def outter(index):  # 第二步 构造外函数 -为后面第三步构造未闭合机制做准备

    def wrapper():  # 第一步 构造新功能
        start_time = time.time()
        index()
        end_time = time.time()
        print(end_time-start_time)

    return wrapper  # 第三步,构造未闭合的机制 必须借助这个return来实现

index = outter(index)   # 偷梁换柱
index()

24.装饰器的精髓是什么?

  • 伪装

 25.装饰器如何加参数?

  • 在23的基础上,增加参数呗
def index(x,y,z): # 加了参数
    time.sleep(1)
    print("from index",x,y,z)

def outter(func):  # 第二步 构造外函数 -为后面第三步构造未闭合机制做准备

    def wrapper(x,y,z):  # 第一步 构造新功能 ==加了参数
        start_time = time.time()
        func(x,y,z) # == 加了参数
        end_time = time.time()
        print(end_time-start_time)

    return wrapper  # 第三步,构造未闭合的机制 必须借助这个return来实现

index = outter(index)   # 偷梁换柱
index(1,22,33)
  • 通用写法:
def index(x,y,z):
    time.sleep(1)
    print("from index",x,y,z)

def outter(func):  # 第二步 构造外函数 -为后面第三步构造未闭合机制做准备

    def wrapper(*args):  # 第一步 构造新功能    # 更进一步
        start_time = time.time()
        func(*args) # 更进一步
        end_time = time.time()
        print(end_time-start_time)

    return wrapper  # 第三步,构造未闭合的机制 必须借助这个return来实现

index = outter(index)   # 偷梁换柱
index(4,5,6)

26.装饰器25在参数层面已经ok,如何拿到返回值呢?

  • 加个res接受就ok了
def index(x,y):
    time.sleep(1)
    print("from index",x,y)
    return 123

def outter(func):  # 第二步 构造外函数 -为后面第三步构造未闭合机制做准备

    def wrapper(*args):  # 第一步 构造新功能    # 更进一步
        start_time = time.time()
        res = func(*args)   ##拿到返回值
        end_time = time.time()
        print(end_time-start_time)
        return res          ##拿到返回值

    return wrapper  # 第三步,构造未闭合的机制 必须借助这个return来实现

index = outter(index)   # 偷梁换柱
res = index(4,5)
print(res)

27.装饰器可以在26的基础上更炫酷一点吗?

  • 用语法糖简化
import time

def outter(func):  # 第二步 构造外函数 -为后面第三步构造未闭合机制做准备
    def wrapper(*args):  # 第一步 构造新功能    # 更进一步
        start_time = time.time()
        res = func(*args)  ##拿到返回值
        end_time = time.time()
        print(end_time - start_time)
        return res  ##拿到返回值
    return wrapper  # 第三步,构造未闭合的机制 必须借助这个return来实现

@outter  # 语法糖的方式 index=outter(index)
def index(x, y):
    time.sleep(1)
    print("from index", x, y)
    return 123
@outter # 语法糖 home=outter(home)
def home(name):
    time.sleep(2)
    print(f"welcome {name} !!!")
    return name

# index = outter(index)  # 偷梁换柱   这一步可以改成语法糖的方式
if __name__ == '__main__':
    res = index(4, 5)
    print(res)
    res_name = home("liqi")
    print(res_name)

28.如何把函数的属性也都装起来,伪装的更像?

 

  • 笨方法是用# wrapper.__doc__ = func.__doc__
  • 更彻底的是用@wraps取代
import time
from functools import wraps # 导入自带的wraps

def outter(func):  # 第二步 构造外函数 -为后面第三步构造未闭合机制做准备

    @wraps(func)    # 把所有属性都给warpper 等同于下面的__doc__赋值
    def wrapper(*args):  # 第一步 构造新功能
        # wrapper.__doc__ = func.__doc__    # 用wraps取代
        start_time = time.time()
        res = func(*args)
        end_time = time.time()
        print(end_time - start_time)
        return res
    return wrapper  # 第三步,构造未闭合的机制 必须借助这个return来实现

@outter  # 语法糖的方式
def index(x, y):
    """这是index"""
    time.sleep(1)
    print("from index", x, y)
    return 123

if __name__ == '__main__':
    res = index(4, 5)
    print(res)
    print(index.__name__)
    print(index.__doc__)

29.默写一个装饰器?

from functools import wraps
import time

def outter(func):
    @wraps(func)    # 这里要传参数
    def wrapper(*args):
        start = time.time()
        res = func(*args)
        end = time.time()
        print("用时:",end - start)
        return res
    return wrapper

# 测试一下
@outter
def index(x,y):
    """你好 index"""
    print(x,y)
    time.sleep(0.5)
    return x,y

if __name__ == '__main__':
    res = index(1,2)
    # print(index.__doc__)
    # print(res)

30.装饰器模板是?

from functools import wraps
def outter(func):
    @wraps(func)
    def index(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return index
  • 思路是
  • 先写个闭合函数
  • 加上参数
  • 加上返回值
  • 同步属性

31.用装饰器写一个认证功能?需要,认证通过才能执行代码,不通过不执行。

  • 代码
# 装饰器的认证功能
from functools import wraps
def login(func):
    @wraps(func)
    def index(*args,**kwargs):
        username = input("请输入账号")
        password = input("请输入密码")
        if username == "liqi" and password == "123":
            res = func(*args, **kwargs)
            return res
        else:
            print("认证失败!")

    return index
@login
def home(x):
    print("执行home")
    return x

home(9)

 

32.多层装饰器的执行顺序是?

  • 执行前1-->执行前2-->执行前3-->home-->执行后3-->执行后2-->执行后1

python 文件eof函数 python foo函数_迭代


def outter1(func):
    def index(*args,**kwargs):
        print("执行1")
        res = func(*args,**kwargs)
        print("执行1后")
        return res
    return index

def outter2(func):
    def index(*args,**kwargs):
        print("执行2")
        res = func(*args,**kwargs)
        print("执行2后")
        return res
    return index

def outter3(func):
    def index(*args,**kwargs):
        print("执行3")
        res = func(*args,**kwargs)
        print("执行3后")
        return res
    return index


@outter1
@outter2
@outter3
def home():
    print("home")
home()
# 执行顺序是
''' 执行前1-->执行前2-->执行前3-->home-->执行后3-->执行后2-->执行后1'''
  • View Code

33.什么是迭代器?

  • 迭代器是迭代取值的工具
  • 什么是迭代?
  • 迭代是一个重复的过程,但每次重复都在上次的基础上有变化。
  • (爸爸是迭代1号,我是迭代2号,我孩子是迭代3号)
l = [11,22,33]
i = 0
while i<len(l):
    print(l[i])
    i+=1  #迭代的每次变化

34.为何要用迭代器?

  • 迭代器提供了一种不依赖索引,通用的迭代取值的方案
  • 节省内存

35.如何使用迭代器?

  • 可迭代对象
  • 内置有__iter__方法的对象的都叫可迭代对象
  • 调用可迭代对象的__iter__方法,返回的是对应的迭代器
  • 迭代器对象
  • 内置有__next__方法
  • 内置有__iter__方法
  • 调用迭代器对象的__iter__方法,返回的是它自己。
  • 调用迭代器对象的__next__方法,返回的是下一个值,不依赖索引。
  • (扩展)内置的函数都是可迭代对象
  • 元组,列表,字典,字符串,集合。是可迭代对象,仅有__iter__方法。
  • 注意:文件是迭代器对象,不仅有__iter__,还有__next__方法。

36.迭代器的示例?

  • 代码
# l = [1,2,3,4]
l = {"name":"123","age":99}
n = l.__iter__()    # 返回一个迭代器
print(n.__next__())
print(n.__next__())

37.for循环可以用迭代器实现?

  • 是的

nums_iter = nums.__iter__()
while True:
try:
print(nums_iter.__next__())
except StopIteration:
break
nums_iter = iter(nums)
while True:
    try:
        print(next(nums_iter))
    except StopIteration:
        break

 38.生成器是什么?

  • 是自定义的一种迭代器。
  • 利用yield关键字构造生成器
  • 示例
def func():
    yield "xxx"
    yield "yyy"
    yield "zzz"
res = func()
print(res.__next__())
print(res.__next__())

39.用生成器,生成一个可以产生无穷值的生成器?

  • so easy
def endless():
    i = 0
    while True:
        i+=1
        print(i)
        yield i
# 测试
g = endless()
while True:
    next(g)

40.生成器有缺点么?

  • 单向流通,不能回退取值
  • 不能指定索引取值。
  • 不能知道里面的长度
  • 同一个迭代器,有记忆性,取干净就没了。

41.下面的代码是,有什么区别?

nums = [11,22,33]
x = iter(nums)
# for i in x:   # x.__iter__()
#     print(i)
# print("="*20)
# for i in x:   # x.__iter__()
#     print(i)

for i in nums:  # nums.__iter__() 新迭代器
    print(i)
print("="*20)
for i in nums:  # nums.__iter__()
    print(i)
# 下面的是每次产生一个新的迭代器,上面的是每次都用用一个迭代器
  • 下面的每次产生一个新的迭代器,上面的是用同一个迭代器。

42.三元表达式是什么?

  • 取代简单函数判断的方式
x = 11
y = 22
# def func():
#     if x > y:
#         return x
#     else:
#         return y
# res = func()
# print(res)
# 三元表达式
res_3 = x if x > y else y
print("三元表达式", res_3)
  • res = x if x >y else y

43.列表生成器是什么?

  • 可以快速生成列表的
# 列表生成器
# l = []
# for i in range(10):
#     l.append(i)
# print(l)
l = [i for i in range(10)]
# l = ["x" for i in range(10)] 前面"x"可以任意,是个函数也可以,只要是可以产生值的就可以。
print(l)

43.1 字典生成器怎么写?

res={i:i**2 for i in range(5)}
print(res)

 

44.列表生成器可以执行列表?(常用)

  • 是的
def func():
    return [i for i in range(10)]
l = [func() for i in range(8)]
print(l)
  • (扩展)也有字典生成器,集合生成器,不常用。

45.简单代码的原则是什么?

  • 在不丧失代码可读的情况下,可以简化。

46.需求,给列表里的元素加个烧饼?

names = ["lxx","wxx","lili","jjj"]
l = [i+"_烧饼" for i in names]
print(l)

47.需求,把列表里没有烧饼的筛选出来

  • 先写循环【i for i in names】,后面写条件 【if “烧饼” not in i】
names = ['lxx_烧饼', 'wxx_烧饼', 'lili_烧饼', 'jjj_烧饼',"egon"]
# new_names = [i for i in names if i.endswith("烧饼")]
new_names = [i for i in names if "烧饼" not in i]
print(new_names)

48.如何写一个生成器表达式?

  • 用小括号
res = (i for i in range(10))
print(res)  # 这里是个老母鸡
print(next(res))
print(next(res))
print(next(res))

 49.什么是函数的递归调用?

  • 递归调用就是反复调用自己。
  • 大前提示:递归调用一定要在某一层结束
  • 递归的两个阶段:
  • 1、回溯:向下一层一层挖井
  • 2、递推:向上一层一层返回

50.如何把数学表达式写成递归的形式?

  • age(5) = age(4) + 10
  • age(4) = age(3) + 10
  • age(3) = age(2) + 10
  • age(2) = age(1) + 10
  • age(1) = 18
def age(n):
  if n ==1:
        return 18
    return age(n-1) +10

51.如何把像下面的列表里的数字都取出来

  • 列表是 l = [1,[2,[3,[4,[5,[6,[7]]]]]]]
l = [1,[2,[3,[4,[5,[6,[7]]]]]]]
# 第一步 写个简单for循环
# for i in l:
#     if type(i) is list:
#         pass
#     else:
#         print(i)
# 第二步 缩进到函数里,把pass替换为函数
def get(l):
    for i in l:
        if type(i) is list:
            get(i)  
        else:
            print(i)
get(l)

 52.写一个二分查找?

  • 第一步:写一个if 条件
  • 第二步:用函数封装,循环调用自身
  • 第三步:异常处理
l = [-3, 2, 4, 6, 7, 9, 11, 14, 15, 27, 34, 46, 57, 62, 68, 69, 71]
find_num = 2
def get(l, find_num):
    try:
        mid_num = len(l) // 2
        if l[mid_num] == find_num:
            print("找到了",)
        elif l[mid_num] < find_num:  # 如果要找的数大于中位数,继续在右边找
            new_l = l[mid_num + 1:]
            get(new_l, find_num)  # 继续找
        elif l[mid_num] > find_num:  # 如果要找的数小于中位数,继续在左边找
            new_l = l[:mid_num]
            get(new_l, find_num)  # 继续找
    except IndexError:
        print("找不到!!")

get(l,find_num)

53.写一个二分法?(方式二)

  • 用Len判断长度为0
l = [-3, 2, 4, 6, 7, 9, 11, 14, 15, 27, 34, 46, 57, 62, 68, 69, 71]
find_num = 71
def get(l, find_num):
    # print(l)
    mid_num = len(l) // 2
    if mid_num == 0:
        print("not exits")
        return
    if l[mid_num] == find_num:
        print("找到了",)
    elif l[mid_num] < find_num:  # 如果要找的数大于中位数,继续在右边找
        new_l = l[mid_num + 1:]
        get(new_l, find_num)  # 继续找
    elif l[mid_num] > find_num:  # 如果要找的数小于中位数,继续在左边找
        new_l = l[:mid_num]
        get(new_l, find_num)  # 继续找

get(l,find_num)

 54.算法是什么?

  • 高效解决问题的一种方式,
  • 在你月薪3万以下,基本用不到算法

 55.什么是匿名函数?

  • 匿名匿名,就是没有名字的函数。
  • 有名函数,写完了,可以多次调用。
  • 那匿名函数,写完了,只能调用一次。适用于,临时用一次
  • 下面的用法可以,但很少这样用。
# 匿名函数
# f= lambda x,y:x+y
# res = f(1,2)
# print(res)

# res = (lambda x,y:x+y)(1,4)
# print(res)
  • lambda(条件: 返回的结果)

 56.匿名函数的应用

  • 跟max适用,拿到薪资最高人的名字
salaries = {
    "lxx":3000,
    "egon":100000,
    "zxx":1000
}
# def func(k):
#     return salaries[k]
# print(max(salaries,key=func))   # max会遍历字典的人名,每遍历一次人名告诉后面的max的比较依据key说比较的是字典值
print(max(salaries,key=lambda k :salaries[k]))
  • (扩展)min 和sorted:
salaries = {
    "lxx":3000,
    "egon":100000,
    "zxx":1000
}
print(max(salaries,key=lambda k :salaries[k]))
print(min(salaries,key=lambda k :salaries[k]))
print(sorted(salaries,key=lambda k :salaries[k]))   # 从小到大 排列薪资
print(sorted(salaries,key=lambda k :salaries[k],reverse=True))   # 从大到小 排列薪资

57.什么是函数式编程?

  • 类似上面56的这种
  • sorted(salaries,key=lambda k :salaries[k],reverse=True)
  • 函数套函数去解决问题的,是函数式编程
  • 类似的还有map ,filter ,reduce
  • Python支持函数式编程,但不是常用的选项。
  • 参考资料 : 阮一峰知乎

 58.介绍几种函数式编程的关键词的用法

  • map(函数,可迭代的对象)
names = ["lxx","zxx","exx","yxx"]
res = list(map(lambda name:name+"_你好",names))   # map要转换为list,本身应该是个map对象,是个迭代器,打印不出来结果。
print(res)

 

  • filter(函数(筛选出布尔值为真的),可迭代对象)
names = ["lxx_ii","jxx_ii","egon","wxx_ii"]
print([ i for i in names if i.endswith("ii")])  # 筛选出ii
res = filter(lambda name:name.endswith("ii"),names)
print(list(res))
  • reduce(合并函数,可迭代对象,[可选初始值])   注意 这个本身有返回值
from functools import reduce    

res = reduce(lambda x,y:x+y ,[11,22,33])
print(res)  # 两两合并,减少序列值为一个值
res = reduce(lambda x,y:x+y ,[11,22,33],100)
print(res)  # 增加可选初始值100

59.面向过程的编程思想

  • 核心是过程。
  • 那什么是过程?就是做事的一系列步骤。
  • 基于该思想,好比在设计流水线。
  • 好处:
  • 复杂的问题简单化,流程化。
  • 计算机的底层思想也是过程的思想,可以说过程思想是一切思想的基石。
  • 缺点:
  • 牵一发而动全身,扩展性差 

 60.面向过程的编程思想跟面向对象的有高低之分吗?

  • 没有。
  • 武林门派,没有高低之分,习武之人,有高低之分。
  • 也就是,编程思想,看你用在合适的场景里。没有什么low不low的,low的只是人们的无知。

 61.什么是框架?

  • 本质上,就是有人发现大量的人都在写重复的代码。有人跳出来说,我帮你们把这部分公共的写好,你们在我的基础上再写自己的东西。
  • 可以认为是一种抄别人代码的事情。
  • 只不过,面试的时候,不能直接说,我的工作就是抄别的代码,然后在修修改改。
  • 所以,面试的时候,说是用xx框架,做二次开发。
  • 但,回过头来,抄别人的代码,真的是不可取的,是不对的吗?
  • 目前的公司,或者业务,都是需要你快速开发,快速产生价值。那么使用框架确实节省时间。那么就是有价值的。
  • 比如,目前的社会分工许多,难道说,你吃一顿猪肉白菜的饺子,一定要先从养猪,再种白菜 开始吗?