拍照,音乐消防车-学编曲、即兴伴奏怎能不会扒谱,歌曲养成计划

毫无疑问,函数是 Python 言语里最重要的概念之一。在编程时,咱们将实在国际里的大问题分天庭废物收回大王解为小问题,然后经过一个个函数交出答案。函数便是重复代码的克星,也是对立代码复杂度的最佳兵器。

好像大部分故事都会有结局,绝大多数函数也都是以回来成果作为完毕。函数回来成果的方法,决议了调用它时的体会。所以,了解怎样优胶东在线雅的让函数回来成果,是编写好函数的必备常识。

Python 的函数回来方法

Python 函数经过调用 return 句子来回来成果。运用 returnvalue 能够回来单个值,用 returnvalue1,value2 则能让函数一起回来多个值。

假定一个函数体内没有任何 return 句子,那么这个函数的回来值默以为 None。除了经过 return句子回来内容,在函数内还能够运用抛出反常(raise Exception)的方法四维来“回来成果”。

接下来,我将罗列一些与函数回来相关的常用编程主张。

编程主张

1. 单个函数不要回来多种类型

Python 言语十分灵敏,咱们能用它轻松完结一些在其他言语里很难做到的作业。比方:让一个函数一起回来不同类型的成果。然后完结一种看起来十分有用的“多功能函数”。

就像下面这样:

def
get_users(user_id=
None
):

if
user_id
is

None
:

return

User
.
get
(user_id)

else
:

return

User
.filter(is_active=
True
)
# 回来单个用户
get_users(user_id=
1
)
# 回来多个用户
get_users()

当咱们需求获取单个用户时,就传递 user_id 参数,不然就不传参数拿到全部活泼用户列表。全部都由一个函数 get_users 来搞定。这样的规划好像很合理。

然而在函数的国际里,以编写具有“多功能”的瑞士军刀型函数为荣不是一件功德。这是由于好的函数必定是 “单一责任(Single responsibility)” 的。单一责任意味着一个函数只做好一件事,意图清晰。这样的函数也更不简略在未来由于需求改变而被修正。

而回来多种类型的函数必定是违背“单一责任”准则的,好的函数应该总是供给安稳的回来值,把调用方的处理本钱降到最低。像上面的比方,咱们应该编写两个独立的函数 get_user_by_id(user_id)、 get_active_users()来代替。

2. 运用 partial 结构新函数

假定这么一个场景,在你的代码里有一个参数许多的函数 A,适用性很强。而另一个函数 B 则是彻底经过调用 A 来完结作业,是一种相似方便方法的存在。

比方在这个比方里, double 函数便是彻底经过 multiply 来完结核算的:

def
multiply(x, y):

return
x * y
def
double(value):

# 回来另一个函数调用成果

return
multiply(
2
, value)

关于上面这种场景,咱们能够运用 functools 模块里的 partial() 函数来简化它。

partial(func,*args,**kwargs) 根据传入的函数与可变(方位/关键字)参数来结构一个新函数。全部对新函数的调用,都会在兼并了当时调用参数与结构参数后,署理给原始函数处理。

运用 partial 函数,上面的 double 函数界说能够被修正为单行表达式,更简练也更直接。

import
functools
double = functools.partial(multiply,
2
)

主张阅览:partial 函数官方文档

3. 抛出反常,而不是回来成果与过错

我在前面提过,Python 里的函数能够回来多个值。根据这个才能,咱们能够编写一类特别的函数:一起回来成果与过错信息的函数。

def
create_item(name):

if
len(name) > MAX_LENGTH_OF_NAME:

return

None
,
'name of item is too long'

if
len(CURRENT_ITEMS) > MAX_ITEMS_QUOTA:

return

None
,
'items is full'

return

Item
(name=name),
''
def
create_from_input():
name = input()
item, err_msg = create_item(name)

if
err_msg:

print
(f
'create item failed: {err_msg}'
)

else
:

print
(f
'item<{name}> created'
)

在示例中, create_item 函数的作用是创立新的 Item 方针。一起,为了在犯错时给调用方供给酉阳天气预报过错概况,它运用了多回来值特性,把过错信息摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案作为第二个成果回来。

乍看上去,这样的做法很天然。尤其是对那些有 Go 言语编程经历的人来说更是如此。可是在 Python 国际里,这并非处理此类问题的最佳方法。由于这种做法会添加调用方进行过错处理的本钱,尤其是当许多函数都遵从这个规范并且存在多层调用时。

Python 具有完善的反常(Exception)机制,并且在某种程度上鼓舞咱们运用反常(官方文档关于 EAFP 的阐明)。所以,运用反常来进行过错流程处理才是更地道的做法。

引进自界说反常后,上面的代码能够被改写成这样:

class

CreateItemError
(
E网卡驱动xception
):

"""创立 Item 失利时抛出的反常"""
def
create电脑亮度怎样调_item(name):

"""创立一个新的 Item
:raises: 当无法创立时抛出 CreateItemError
"""

if
len(name) > MAX_LENGTH_OF_NAME:

raise

CreateItemError
(
'name of item is too long'
)

if
len(CURRENT_ITEMS) > MAX_ITEMS_QUOTA:

raise

CreateItemError
(
'items is full'
)

return

Item
(name=name)
def
create_for_input():
name = input()蛇果

try
:
item = create_item(name)

except

CreateItemError
藏宝阁梦境站
as
e:

print
(f
'create item failed: {err_msg}'
)

else
:

print
(f
'item<{name}> created'
)

运用“抛出反常”代替“回来 (成果, 过错信息)”后,整个过错流程处理乍看上去改变不大,但实际上有着十分多不同,一些细节:

  • 新版本函数具有更安稳的回来值类型,它永久只会回来 Item 类型或是抛出反常
  • 尽管我在这里鼓舞运用反常,但“反常”总是会无法防止的让人 感到惊奇,所以,最好在函数文档里阐明或许抛出的反常类型
  • 反常不同于回来值,它在被捕获前会不断往调用栈上层报告。所以 create_item 的一级调用方彻底能够省掉反常处理,交由上层处理。这个特色给了咱们更多的灵敏性,但一起也带来了更大的危险。

Hint:怎样在编程言语里处理过错,是一个至今依然存在争议的主题。比方像上面不引荐的多回来值方法,正是缺少反常的 Go 言语中最中心的过错处理机制。别的,即使是反常机制本身,不同编程言语之间也存在着不同。

反常,或是不反常,都是由言语规划者进行多方取舍后的成果,更多时分不存在绝对性的好坏之分。可是,单就 Python 言语而言,运用公司规章制度反常来表达过错无疑是更契合 Python 哲学,更应该遭到推重的。

4. 慎重运用 None 回来值

None 值一般被用来表明“某个应该存在可是缺失的东西”,它在 Python 里摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案是绝无仅有的存在。许多编程言语里都有与 None 相似的规划,比方 JavaScript 里的 null、Go 里的 nil 等。由于 None 所具有的一起 虚无 气质,它经常被作为函数回来值运用。

当咱们运用 None 作为函数回来值时,一般是下面 3 种状况。

1. 作为操作类函数的默许回来值

当某个操作类函数不需求任何回来值时,一般就会回来 None。一起,None 也是不带任何 return 句子函数的默许回来值。

关于这种函数,运用 None 是没有任何问题的,规范库里的 list.append()、 os.chdir() 均属此类。

2. 作为某些“预料之中”的或许没有的值

有一些函数,它们的意图一般是去尝试性的做某件作业。视状况不同,终究或许有成果,也或许没有成果。而对调用方来说,“没有成果”彻底是预料之中的作业。对这类函数来说,运用 None 作为“没成果”时的回来值也是合理的。

在 Python 规范库里,正则表达式模块 re 下的 re.search、 re.match 函数均属于此类,这两个函数在能够找到匹配成果时回来 re.Match 方针,找不到时则回来 None。

3. 作为调用失利时代表“过错成果”的值

有时, None 也会经常被咱们用来作为函数调用失利时的默许回来值,比方下面这个函数:

def
create_user_from_name(username):

"""经过用户名创立一个 User 实例"""

if
validate_username(username):

return

User
.from_username(username)

else
:

return

None
user = create_user_from_name(username)
if
user:
user.do_something()

当 username 不合法时,函数 create_user_from_name 将会回来 None。但在这个参考文献格局场景下,这样做其实并不好。

不过你或许会觉得这个函数彻底入情入理,乃至你会觉得它和咱们说到的上一个“没有成果”时的用法十分相似。那么怎样区别这两种不同景象呢?关键在于:函数签名(称号与参数)与 None 回来值之间是否存在一种“预料之中”的暗示。

让我解释一下,每逢你让函数回来 None 值时,请仔细阅览函数名,然后问自己一个问题:假定我是该函数的运用者,从这个姓名来看,“拿不到任何成果”是否是该函数称号意义里的一部分?

分别用这两个函数来举例:

  • re.search():从函数名来看, search,代表着从方针字符串里去查找匹配成果,而查找行为,一向是或许有也或许没有成果的,所以该函数合适回来 N狗奸one
  • create_user_from_name():从函数名来看,代表根据一个姓名来构建用户,并不能读出一种 或许回来、或许不回来的意义。所以不合适回来 None

关于那些不能从函数名里读出 None 值暗示的函数来说,有两种修正方法。第一种,假定你坚持运用 None 回来值,那么请修正函数的称号。比方能够将函数 create_user_from_name() 改名为 create_user_or_none()。

第二种方法则更常见的多:用抛出反常(raise Exception)来代替 None 回来值。由于,假定回来不了正常成果并非函数意义里的一部分,这就代表着函数呈现了“预料以外的状况”,而这正是Exceptions 反常 所掌管的范畴。

运用反常改写后的比方:

class

UnableToCreateUser
(
Exception
):

"""当无法创立用户时抛出"""
def
create_user_from_name(username):

""
经过用户名创立一个
User
实例
"
:raises: 当无法创立用户时抛出 UnableToCreateUser
"""

if
validate_username(usernam青纱帐边的女性e):

return

User
.from_username(username)

else
:

raise

UnableToCreateUser
(f
'unable to create user from {username}'
)
try
:
user = create_user_from_name(username)
excerepresentpt

UnableToCreateUser
:

# Error handling
else
:
user.do_something()

与 None 回来值比较,抛出反常除了具有咱们在上个场景说到的那些特色外,还有一个额定的优势:能够在反常信息里供给呈现预料之外成果的原因,这是只回来一个 None 值做不到的。

5. 合理运用“空方针形式”

我在前面说到函数能够用 None 值或反常来回来过错成果,但这两种方法都有一个一起的缺陷。那便是全部需求运用宁晋123函数回来值的当地,都必须加上一个 if 或 try/except 防护句子,来判别成果是否正常。

让咱们看一个可运转的完好示例:

import
decimal
class

CreateAccountError
(
Exception
):

"""Unable to create a account error"""
class

Account
:

"""一个虚拟的银行账号"""

def
__init__(self, username, balance):
self.username = username
self.balance = balance

@classmet妈妈噜hod

def
from_string(cls, s):

"""从字符串初始化一个账号"""

try
:
username, balance = s.split()摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案
balance = decimal.
Decimal
(float(balance))

except

ValueError
:

raise

CreateAccountError
(
'input must follow pattern "{ACCOUNT_NAME} {BALANCE}"'
)

if
balance <
0
:

raise

CreateAccountError
(
'balance can not be negative'
)

return
cls(username=username, balance=balance)
def
caculate_total_balance(accounts_data):

"""核算全部账号的总余额
"""
result =
0

for
account_string
in
accounts_data:

try
:
user =
Account
.from_string(account_string)

except

CreateAccountError
:

pass

else
:
result += user.balance

return
result
accounts_data = [

'piglei 96.5'
,

'cotton 21'
,

'invalid_data'
,

'roland $invalid_balance'
,

'alfred -3'
,
]
print
(caculate_total_balance(accounts_data))

在这个比方里,每逢咱们调用 Account.from_string 时,都必须运用 try/except 来捕获或许发作的反常。假定项目里需求调用许屡次该函数,这部分作业就变得十分繁琐了。针对这种状况,能够运用“空方针形式(Null object pattern)”来改进这个操控流。

Martin Fowler 在他的经典著作《重构》 顶用一个章节具体阐明过这个形式。简略来说,便是运用一个契合正常成果接口的“空类型”来代替空值回来/抛出反常,以此来下降调用方处理成果的本钱。

引进“空方针形式”后,上面的示例能够被修正成这样:

class

Account
:

# def __init__ 已省掉... ...

@classmethod

def
from_string(cls, s):

"""从字符串初始化一个账号
:returns: 假定输入合法,回来 Account object,不然回来 NullAccount
"""

try
:
username, balance = s.split()
balance摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案 = decimal.
Decimal
(float(balance))

except

ValueError
:

return

NullAccount
()

if
balance <
0
:

return

NullAccount
()

return
cls(username=username, balance=balance)
class

NullAccount
:
username =
''
balance =
0

@classmethod

def
from_string(cls, s):

raise

NotImplementedError

在新版代码里,我界说了 NullAccount 这个新类型,用来作为 from_string 失利时的过错成果回来。这样修正后的最大改变体现在 caculate新疆人事考试中心_total_balance 部分:

def
caculate_total_balance(accounts_data):

"""核算全部账号的总余额
"""

return
sum(
Account
.from_摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案string(s).balance
for
s
in
accounts_data)

调整之后,调用方不用再显式运用 try 句子来处理过错,而是能够假定 Account.from_string 函数总是会回来一个合法的 Account 方针,然后大大简化整个核算逻辑。

Hint:在 Python 国际里,“空方针形式”并不罕见,比方大名鼎鼎的 Django 结构里的 AnonymousUser 便是一个典型的 null object。

6. 运用生成器函摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案数代替回来列表

在函数里回来列表特别常见,一般,咱们会先初始化一个列表 results=[],然后在循环体内运用 results.append(item) 函数填充它,最终在函数的结尾回来。

关于这类形式,咱们能够用生成器函数来简化它。粗犷点说,便是用 yielditem 代替 append 句子。运用生成器的函数一般更简练、也更具通用性。

def
foo_func(items):

for
item
in
items:

# ... 处理 item 后直接运用 yield 回来

yield
item

我在 系列第 4 篇文章“容器的门路” 里具体分析过这个形式,更多细节能够拜访文章,查找 “写扩展性更好的代码” 检查。

7. 约束递归的运用

当函数回来本身调用时,也便是 递归 发作时。递归是一种在特定场景下十分有用的编程技巧,但坏消息是:Python 言语对递归支撑的十分有限。

这份“有限的支撑”体现在许多方面。首要,Python 言语不支撑“尾递归优化”。别的 Python 对最大递归层级数也有着严厉的约束。

所以我主张:尽量少写递摄影,音乐消防车-学编曲、即兴配乐怎能不会扒谱,歌曲养成方案归。假定你想用递归处理问题,先想想它是不是能便利的用循环来代替。假定答案是必定的,那么就用循环来改写吧。假定无可奈何,必定需求运用递归时,请考虑下迭目江腾面几个点:

  • 函数输入数据规划是否安稳,是否必定不会超越 sys.getrecursionlimit() 规则的最大层数约束
  • 是否能够经过运用相似 functools.lru_cache 的缓存东西函数来下降递归层数

总结

在这篇文章中,我虚拟了一些与 Python 函数回来有关的场景,并针对每个场景供给了我的优化主张。最终再总结一下关键:

  • 让函数具有安稳的回来值,一个函数只做好一件事
  • 运用 functools.partial 界说方便函数
  • 抛出反常也是回来成果的一种方法,运用它来代替回来过错信息
  • 函数是否合适回来 None,由函数签名的“意义”所决议
  • 运用“空方针形式”能够简化调用方的过错处理逻辑
  • 多运用生成器函数,尽量用循环代替递归

看完文章的你,有没有什么想吐槽的?在谈论区给我留言

小编共享

一.400集python教程(第二季进步篇去水印软件免费共享)

额定收拾的java300集视频教程!

400集python第二季进步篇丶300集java零基础教程+视频教程收取方法:

1、点赞+转发

2、重视《程序员Doctor》

3、私信小编(材料)即可免费收取

假定没有成功收取到教程地址,记得要发材料二字才能够获得!

十分感谢我们对小编的支撑和信赖,搭档也期望我们将此次材料进行共享,转载,让更多人需求的朋友看到经济适用房,这样不只自己得到了协助,也能协助到其他人,是不是感觉很高兴呢!

 关键词: