Python的Zen指出,应该只有一种方法可以做事情-但我经常遇到决定何时使用函数以及何时使用方法的问题。
让我们举一个简单的例子-ChessBoard对象。假设我们需要某种方式使董事会上所有合法的King举动均可用。我们是否编写ChessBoard.get_king_moves()或get_king_moves(chess_board)?
这是我看过的一些相关问题:
Why does python use 'magic methods'?
Is there a reason Python strings don't have a string length method?
我得到的答案基本上没有定论:
为什么Python为什么将方法用于某些功能(例如list.index()),却对其他功能(例如len(list))使用?
主要原因是历史。函数用于一组类型通用的操作,
甚至可以用于根本没有方法的对象
(例如元组)。具有可以
使用时很容易应用于无定形的对象集合
Python的功能特性(map(),apply()等)。
实际上,将len(),max(),min()实现为内置函数实际上比将它们实现为每种类型的方法要少。
人们可能会质疑个别情况,但这是Python的一部分,并且
现在进行这样的根本性改变为时已晚。功能有
保留以避免大量代码损坏。
尽管很有趣,但是上面并没有真正说明采用哪种策略。
这是原因之一-使用自定义方法,开发人员将
可以自由选择其他方法名称,例如getLength(),length(),
getlength()或任何东西。 Python强制执行严格的命名,以便
可以使用通用函数len()。
稍微有趣一点。我认为函数在某种意义上是接口的Pythonic版本。
最后,from Guido himself:
谈论能力/接口使我想到了一些我们的
“流氓”特殊方法名称。在《语言参考》中,“
类可以实现由特殊调用的某些操作
语法(例如算术运算或下标和切片)
用特殊名称定义方法。”但是所有这些方法
具有特殊名称,例如__len__
或__unicode__
提供用于内置功能的好处,而不是为了
支持语法。大概在基于接口的Python中,这些
方法将在ABC上变成常规命名的方法,因此
__len__
将成为
class container:
...
def len(self):
raise NotImplemented
虽然,再想一想,我不明白为什么所有的句法
操作不仅会调用适当的通常命名的方法
在特定的ABC上。例如,“ <
”大概会调用
“ object.lessthan
”(或者也许是“ comparable.lessthan
”)。所以另一个
好处是可以使Python断断续续
奇怪的名称,对我来说似乎是HCI的改进。
嗯我不确定我是否同意(图:-)。
我想解释两点“ Python基本原理”
第一。
首先,出于HCI的原因,我选择len(x)而不是x.len()(def
来得晚得多)。实际上,HCI有两个相互交织的原因:
__len__()
(a)对于某些操作,前缀符号的读取效果比
postfix-前缀(和infix!)操作在
喜欢表示法在视觉帮助下的数学
数学家思考问题。比较我们的简单性
将像x*(a+b)
这样的公式重写为x*a + x*b
使用原始的OO符号做同样的事情。
(b)当我读到写着len(x)
的代码时,我知道它正在询问
东西的长度。这告诉我两件事:结果是
整数,参数是某种容器。与此相反的,
当我阅读x.len()
时,我必须已经知道x
是某种
容器实现接口或从类继承
具有标准的len()
。看到我们偶尔会有的困惑
未实现映射的类具有get()
或keys()
方法,或者不是文件的东西都具有write()
方法。
用另一种方式说同样的事情,我认为“ len”是内置的
操作。我不想失去那个。我不能肯定地说你是不是真的,但是“ def len(self):...”听起来确实像你
想要将其降级为普通方法。我对此坚决为-1。
我答应解释的Python基本原理的第二点是原因
为什么我选择特殊的方法查看__special__
而不是
special
。我期待类可能要进行的许多操作
覆盖某些标准(例如__add__
或__getitem__
),有些则不是
标准(例如,很长时间,咸菜的__reduce__
代码)。我不希望这些特殊操作使用普通
方法名称,因为然后是预先存在的类或由
对于所有特殊方法都没有百科全书的用户,
可能会意外地定义了他们本不想执行的操作
实施,可能会造成灾难性的后果。伊凡·克斯蒂奇
在他的信息中更简洁地解释了这一点。
全部写下来。
--
--Guido van Rossum(主页:http://www.python.org/~guido/)
我对此的理解是,在某些情况下,前缀表示法更有意义(即从语言的角度来看,Duck.quack比quack(Duck)更有意义。)而且,这些函数还允许使用“接口”。
在这种情况下,我的猜测是仅基于Guido的第一点实现get_king_moves。但这仍然留下很多未解决的问题,例如,使用类似的push和pop方法实现堆栈和队列类-它们应该是函数还是方法? (在这里我会猜测功能,因为我真的很想发信号通知推送界面)
TLDR:有人可以解释决定何时使用函数还是方法的策略是什么?
参考方案
我的一般规则是-是在对象上执行还是由对象执行操作?
如果是由对象完成的,则应该是成员操作。如果它也可以应用于其他事物,或者由对象的其他事物完成,那么它应该是一个函数(或者可能是其他事物的成员)。
引入编程时,传统上(尽管实现不正确)以现实世界中的对象(例如汽车)来描述对象。您提到了一只鸭子,所以让我们开始吧。
class duck:
def __init__(self):pass
def eat(self, o): pass
def crap(self) : pass
def die(self)
....
在“对象是真实的事物”类比的上下文中,为对象可以执行的任何操作添加类方法是“正确的”。所以说我想杀死一只鸭子,我添加一个
.kill()对鸭子?不,据我所知,动物不会自杀。因此,如果我想杀死一只鸭子,我应该这样做:
def kill(o):
if isinstance(o, duck):
o.die()
elif isinstance(o, dog):
print "WHY????"
o.die()
elif isinstance(o, nyancat):
raise Exception("NYAN "*9001)
else:
print "can't kill it."
远离这种类比,为什么我们要使用方法和类?因为我们要包含数据并希望以某种方式构造我们的代码,以便将来可重用和扩展。这使我们想到了面向对象设计非常重要的封装概念。
封装原理实际上就是它的含义:作为设计人员,您应该隐藏有关实现和类内部的所有内容,对于任何用户或其他开发人员而言,都不一定要访问它。因为我们处理类的实例,所以这简化为“什么操作对于该实例至关重要”。如果操作不是实例特定的,则它不应是成员函数。
TL; DR:
@布莱恩说了什么。如果它在实例上运行并且需要访问类实例内部的数据,则它应该是成员函数。
我有一个Python脚本在某些深度学习模型上运行推理。有什么办法可以找出GPU资源的利用率水平?例如,使用着色器,float16乘法器等。我似乎在网上找不到太多有关这些GPU资源的文档。谢谢! 参考方案 您可以尝试在像Renderdoc这样的GPU分析器中运行pyxthon应用程序。它将分析您的跑步情况。您将能够获得有关已使用资源,已用缓冲区,不同渲染状态上…
Python sqlite3数据库已锁定 - python我在Windows上使用Python 3和sqlite3。我正在开发一个使用数据库存储联系人的小型应用程序。我注意到,如果应用程序被强制关闭(通过错误或通过任务管理器结束),则会收到sqlite3错误(sqlite3.OperationalError:数据库已锁定)。我想这是因为在应用程序关闭之前,我没有正确关闭数据库连接。我已经试过了: connectio…
Python exchangelib在子文件夹中读取邮件 - python我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…
python-docx应该在空单元格已满时返回空单元格 - python我试图遍历文档中的所有表并从中提取文本。作为中间步骤,我只是尝试将文本打印到控制台。我在类似的帖子中已经看过scanny提供的其他代码,但是由于某种原因,它并没有提供我正在解析的文档的预期输出可以在https://www.ontario.ca/laws/regulation/140300中找到该文档from docx import Document from…
Python ThreadPoolExecutor抑制异常 - pythonfrom concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED def div_zero(x): print('In div_zero') return x / 0 with ThreadPoolExecutor(max_workers=4) as execut…