建议:减少self.x = x; self.y = Y; self.z = z样板代码 [英] Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code

查看:94
本文介绍了建议:减少self.x = x; self.y = Y; self.z = z样板代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

*************** *** ****************************

此帖子也有HTML格式:
http://cci.lbl.gov/~rwgk/ python / adop ... 005_07_02.html

***************************** ********************* ****************************


嗨其他Python程序员,


我经常发现自己写作::


班级分组:


def __init __(self,x,y,z):

self.x = x

self.y = y

self.z = z

#真实代码,最后


这对于长期的复杂应用程序来说是一个严重的麻烦/>
参数列表,特别是如果长变量名称对于管理复杂性的
必不可少。因此我建议Python包含

内置支持,以减少``self.x = x``混乱。以下是

以下方法的参数(*请*不要太激动

关于这里的语法,它确实是次要考虑因素)::


班级分组:


def __init __(self,.x,.y,.z):

#真正的代码就在这里


使用现有语法进行仿真::

def __init __(self,x,y,z):

self.x = x

del x

self.y = y

del y

self.z = z

del z

真的那么重要吗?

------------- ---------------


对于非平凡大小的应用,是的。这是一个真实世界的例子

(源树中的众多之一):
http://cvs.sourceforge.net/viewcvs.p...py?view=markup


来自此档案的片段::


班级经理:


def __init __(self,

crystal_symmetry =无,

model_indices =无,

conformer_indices =无,

site_symmetry_table =无,

bond_params_table =无,

shell_sym_tables =无,

nonbonded_pa​​rams =无,

nonbonded_types =无,

nonbonded_function =无,

nonbonded_distance_cutoff =无,

nonbonded_buffer = 1,

angle_proxies =无,

dihedral_proxies =无,

chirality_proxies =无,

planarity_proxies =无,

plain_pairs_radius =无):

self.crystal_symmetry = crystal_symmetry

self.model_indices = model_indices

self.conformer_indices = conformer_indices

self.site_symmetry_table = site_symmetry_table

self.bond_params_table = bond_params_table

self.shell_sym_tables = shell_sym_tables

self.nonbonded_pa​​rams = nonbonded_pa​​rams

self.nonbonded_types = nonbonded_types

self。 nonbonded_function = nonbonded_function

self.nonbonded_distance_cutoff = nonbonded_distance_cutoff

self.nonbonded_buffer = nonbonded_buffer

self.angle_proxies = angle_proxies

self.dihedral_proxies = dihedral_proxies

self.chirality_proxies = chirality_proxies

self.planarity_proxies = planarity_proxies

self.plain_pairs_radius = plain_pairs_radius

#真实代码,最后


不完全是你想要用高级语言看到的东西。

有没有办法用Python作为 - 是?

------------------------- ------------


是的。如果你花时间查看CVS中的文件,你会发现我有点作弊。为了减少上面可怕的混乱,我实际上使用了一个简单的技巧$


adopt_init_args(self,locals())


为了完整性,``adopt_init_args()``的实现在这里:
http://cvs.sourceforge.net/viewcvs.p...py?view=markup


虽然这显然有很长的路要走,但它有几个缺点:


- 解决方案没有附带Python - >每个人都必须重新发明。


- 人们不愿意使用这个技巧,因为脚本会依赖于非标准功能而变成




- 很难记住哪个``import``用于

`uncome_init_args``(因为每个人都有本地版本/品种)。


- ``adopt_init_args(self,locals())``咒语很难

记住并且难以向新来者解释。

- 在``__init __()``方法中,同一个对象有两个名字,

eg ``x``和``self.x``。当我在一个错误的地方不小心分配到``x``而不是``self.x``或者#

时,这导致了几次微妙的错误

(这些错误通常在

重构时引入)。


- 在某些情况下,发现了``adopt_init_args()``开销

引入了显着的性能损失(特别是下面讨论的

增强版本)。


- 记住Python的来源:它可以追溯到教学

语言,让凡人都能接受编程。

``take -init_args(self,locals())``肯定不会辜负

这个遗产。

最小的建议

----------------


我的最小建议是添加一个增强版的``adopt_init_args()``

作为标准的Python内置函数(实际名称是辅助!)::


班级分组:


def __init __(self,x,y,z):

adopt_ init_args()

#真实代码


这是一个参考实现:
http://cvs.sourceforge.net/viewcvs.p .. ..2& view = markup


此提案的实施将消除上面列出的所有缺点

。但是,还有另一个之前没有提到的问题:

禁用所选变量的采用很麻烦。例如::


班级分组:


def __init __(self,keep_this,and_this,but_not_this,but_this_again):

self.keep_this = keep_this

self.and_this = and_this

self.but_this_again = but_this_again

#真实代码,最后


将翻译成::


班级分组:


def __init __(self,keep_this,and_this,but_not_this ,but_this_again):

adopt_init_args(exclusions = [" but_not_this"])

#real code

增强的语法提案

------------------------


排除问题表明这些替代方案::


班级分组:


def __init __(self,self.keep_this,self.and_this,but_not_this,

self.but_this_again ):

#真实代码就在这里


这在概念上类似于现有的元组自动解包。


一个较短的选择(我的个人喜欢,因为最低限度多余)::


班级分组:


def __init __(self,.keep_this,.and_this,but_not_this,.but_this_again ):

#真实代码就在这里


我想这两个版本都可以实现,这样用户就不会招致

a性能损失与``self.x = x``替代相比。在过度乐观的危险中:我可以想象我最喜欢的

替代品实际上会更快(并且最快)。

增强__slot__语义提案

------------------------------------


当使用`__slots__``时(很酷的功能!)样板问题

变得更糟::


班级分组:


__slots__ = [" keep_this"," and_this"," but_this_again"]


def __init __(self, keep_this,and_this,but_not_this,but_this_again):

self.keep_this = keep_this

self.and_this = and_this

self.but_this_again = but_this_again

#真实代码,最后


每个变量名称出现四次!想象一下,鉴于上面的实际例子,你自己不得不做b $ b做这个练习。哎哟。


基于增强语法提案上面我看到了这个潜力

改进::


班级分组:


__slots__ = True


def __init __(self,.keep_this,.and_this,but_not_this,.but_this_again):

#真实代码就在这里


每个变量名称只出现一次。 P !.


作者: rw**@yahoo.com ,2005年7月2日


PS:如果您回复此消息,请明确区分

命名/语法问题,提供内置支持的核心问题

旨在减少混乱。


__________________________________________________ __

Yahoo!体育

重燃竞争。注册Fantasy Football
http://football.fantasysports.yahoo.com

解决方案

" Ralf W. Grosse-Kunstleve" < RW ** @ yahoo.com>写道:

班级分组:

def __init __(self,.keep_this,.and_this,but_not_this,.but_this_again):
#real code right here



我真的很不高兴。一方面,我的第一个想法是你

不应该写带有参数列表的构造函数这么长,以至于这是b $ ba问题,但是你展示了一个这个论点的合理反例。

我是DRY(不要重复自己)的忠实粉丝,有时表达为曾经

且只有一次 ;和你的提议允许你这样做。


它还有一个很好的功能,它不会破坏任何现有的代码;

建议的语法目前不是合法的Python。


如果我这样做会发生什么:


def __init __( self,.x,.y,.z):

x = 0


赋值x的作用是什么?是否会自动升级到self.x的

分配?它是否会产生错误?


我心中的一个重要问题不是这是否有用? (因为它显然是),

但是公用事业是否证明成本合理?。换句话说,是否经常使用

来弥补语言增加的复杂性?

我不相信这一点。


已经有一些提议浮出来实现一个with>

关键字,这将创建隐式命名空间。这就是你在这里提出的b $ b b。我不相信这两个都是个好主意,但是如果它们被采纳,我肯定希望看到它们穿着制服,

逻辑上一致的方式。


" Ralf W. Grosse-Kunstleve" < RW ** @ yahoo.com>在留言中写道

新闻:ma ************************************ *** @ pyt hon.org ...

班级分组:

def __init __(self,.x,.y,.z):
#real code在这里
使用现有语法进行仿真::
def __init __(self,x,y,z):
self.x = x
del x
self.y = y
del y
self.z = z
del z




我认为这是一个不好主意,原因很简单。


在Python中,与许多其他语言不同,形式参数的名称是函数界面的一部分。例如:


def f(x,y):

返回xy


现在f(3, 4)是-1而f(y = 3,x = 4)是1.


实例变量的名称通常不属于类''

接口 - 它们是其实现的一部分。


这个建议的功能,无论何时使用,都会将类的实现与

接口联系起来每种使用该功能的方法。据我所知,

如果不以这种方式约束实现

就不可能使用该功能。


出于这个原因,我宁愿让参数

名称和实例变量之间的映射是明确的。


" Andrew Koenig" < ar*@acm.org>写道:

在Python中,与许多其他语言不同,形式参数的名称是函数接口的一部分。例如:

def f(x,y):
返回xy

现在f(3,4)是-1而f(y = 3, x = 4)是1.

实例变量的名称通常不是类'
接口的一部分 - 它们是其实现的一部分。
无论何时使用,此提议的功能都会将类的实现与使用该功能的每个方法的接口联系起来。据我所知,
不能以这种方式约束实现就不可能使用该功能。




虽然我认为从理论的角度来看,确实如此,作为一个实际的问题,我认为这不是什么大不了的事。我不认为

我曾经编写了一个__init__方法,它保存了参数并使用了不同名称的参数和相应的实例变量。

这样做会让人感到困惑(至少对于我写的那种代码而言)。


此外,它并没有真正把它绑在任何硬盘上快捷的方式。现在,我将
写道:


def __init__(self,x,y,z):

self.x = x

self.y = y

self.z = z

blah


under新提案,我会写:


def __init__(self,.x,.y,.z):

blah


如果在将来的某个时间,如果我决定需要更改实例变量的名称

而不更改公开的接口,那么它将是

很容易做到:


def __init__(self,.x,.y,z):

self.zeta = z

blah


我仍​​然不相信我们需要这个,但暴露的界面问题

并不用担心我。 br />


************************************************** ****************************
This posting is also available in HTML format:
http://cci.lbl.gov/~rwgk/python/adop...005_07_02.html
************************************************** ****************************

Hi fellow Python coders,

I often find myself writing::

class grouping:

def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
# real code, finally

This becomes a serious nuisance in complex applications with long
argument lists, especially if long variable names are essential for
managing the complexity. Therefore I propose that Python includes
built-in support for reducing the ``self.x=x`` clutter. Below are
arguments for the following approach (*please* don''t get too agitated
about the syntax right here, it really is a secondary consideration)::

class grouping:

def __init__(self, .x, .y, .z):
# real code right here

Emulation using existing syntax::

def __init__(self, x, y, z):
self.x = x
del x
self.y = y
del y
self.z = z
del z
Is it really that important?
----------------------------

For applications of non-trivial size, yes. Here is a real-world example
(one of many in that source tree):
http://cvs.sourceforge.net/viewcvs.p...py?view=markup

Fragment from this file::

class manager:

def __init__(self,
crystal_symmetry=None,
model_indices=None,
conformer_indices=None,
site_symmetry_table=None,
bond_params_table=None,
shell_sym_tables=None,
nonbonded_params=None,
nonbonded_types=None,
nonbonded_function=None,
nonbonded_distance_cutoff=None,
nonbonded_buffer=1,
angle_proxies=None,
dihedral_proxies=None,
chirality_proxies=None,
planarity_proxies=None,
plain_pairs_radius=None):
self.crystal_symmetry = crystal_symmetry
self.model_indices = model_indices
self.conformer_indices = conformer_indices
self.site_symmetry_table = site_symmetry_table
self.bond_params_table = bond_params_table
self.shell_sym_tables = shell_sym_tables
self.nonbonded_params = nonbonded_params
self.nonbonded_types = nonbonded_types
self.nonbonded_function = nonbonded_function
self.nonbonded_distance_cutoff = nonbonded_distance_cutoff
self.nonbonded_buffer = nonbonded_buffer
self.angle_proxies = angle_proxies
self.dihedral_proxies = dihedral_proxies
self.chirality_proxies = chirality_proxies
self.planarity_proxies = planarity_proxies
self.plain_pairs_radius = plain_pairs_radius
# real code, finally

Not exactly what you want to see in a high-level language.
Is there a way out with Python as-is?
-------------------------------------

Yes. If you take the time to look at the file in the CVS you''ll find
that I was cheating a bit. To reduce the terrible clutter above, I am
actually using a simple trick::

adopt_init_args(self, locals())

For completeness, the implementation of ``adopt_init_args()`` is here:
http://cvs.sourceforge.net/viewcvs.p...py?view=markup

While this obviously goes a long way, it has several disadvantages:

- The solution doesn''t come with Python -> everybody has to reinvent.

- People are reluctant to use the trick since scripts become
dependent on a non-standard feature.

- It is difficult to remember which ``import`` to use for
``adopt_init_args`` (since everybody has a local version/variety).

- The ``adopt_init_args(self, locals())`` incantation is hard to
remember and difficult to explain to new-comers.

- Inside the ``__init__()`` method, the same object has two names,
e.g. ``x`` and ``self.x``. This lead to subtle bugs a few times
when I accidentally assigned to ``x`` instead of ``self.x`` or vice
versa in the wrong place (the bugs are typically introduced while
refactoring).

- In some cases the ``adopt_init_args()`` overhead was found to
introduce a significant performance penalty (in particular the
enhanced version discussed below).

- Remember where Python comes from: it goes back to a teaching
language, enabling mere mortals to embrace programming.
``adopt_init_args(self, locals())`` definitely doesn''t live up
to this heritage.
Minimal proposal
----------------

My minimal proposal is to add an enhanced version of ``adopt_init_args()``
as a standard Python built-in function (actual name secondary!)::

class grouping:

def __init__(self, x, y, z):
adopt_init_args()
# real code

Here is a reference implementation:
http://cvs.sourceforge.net/viewcvs.p....2&view=markup

Implementation of this proposal would remove all the disadvantages
listed above. However, there is another problem not mentioned before:
It is cumbersome to disable adoption of selected variables. E.g.::

class grouping:

def __init__(self, keep_this, and_this, but_not_this, but_this_again):
self.keep_this = keep_this
self.and_this = and_this
self.but_this_again = but_this_again
# real code, finally

would translate into::

class grouping:

def __init__(self, keep_this, and_this, but_not_this, but_this_again):
adopt_init_args(exclusions=["but_not_this"])
# real code
Enhanced syntax proposal
------------------------

The exclusion problem suggests these alternatives::

class grouping:

def __init__(self, self.keep_this, self.and_this, but_not_this,
self.but_this_again):
# real code right here

This is conceptually similar to the existing automatic unpacking of tuples.

A shorter alternative (my personal favorite since minimally redundant)::

class grouping:

def __init__(self, .keep_this, .and_this, but_not_this, .but_this_again):
# real code right here

I guess both versions could be implemented such that users don''t incur
a performance penalty compared to the ``self.x=x`` alternative. At the
danger of being overly optimistic: I can imagine that my favorite
alternative will actually be faster (and the fastest).
Enhanced __slot__ semantics proposal
------------------------------------

When ``__slots__`` are used (cool feature!) the boilerplate problem
becomes even worse::

class grouping:

__slots__ = ["keep_this", "and_this", "but_this_again"]

def __init__(self, keep_this, and_this, but_not_this, but_this_again):
self.keep_this = keep_this
self.and_this = and_this
self.but_this_again = but_this_again
# real code, finally

Each variable name appears four times! Imagine yourself having to
do this exercise given the real-world example above. Ouch.

Based on the "Enhanced syntax proposal" above I see this potential
improvement::

class grouping:

__slots__ = True

def __init__(self, .keep_this, .and_this, but_not_this, .but_this_again):
# real code right here

Each variable name appears only once. Phew!

Author: rw**@yahoo.com, July 02, 2005

P.S.: If you reply to this message, please clearly separate
naming/syntax issues from the core issue of providing built-in support
designed to reduce clutter.


__________________________________________________ __
Yahoo! Sports
Rekindle the Rivalries. Sign up for Fantasy Football
http://football.fantasysports.yahoo.com

解决方案

"Ralf W. Grosse-Kunstleve" <rw**@yahoo.com> wrote:

class grouping:

def __init__(self, .keep_this, .and_this, but_not_this, .but_this_again):
# real code right here



I''m really torn about this. On the one hand, my first thought was "you
shouldn''t be writing constructors with arguments lists so long that this is
a problem", but you showed a reasonable counter-example to that argument.
I''m a big fan of DRY (Don''t Repeat Yourself), sometimes expressed as "Once
And Only Once", and your proposal lets you do that.

It also has the nice feature that it doesn''t break any existing code; the
suggested syntax is not currently legal Python.

What happens if I do:

def __init__ (self, .x, .y, .z):
x = 0

what does the assignment x do? Does it automatically get promoted to an
assignment to self.x? Does it generate an error?

The big question in my mind is not "Is this useful" (since it clearly is),
but "Does the utility justify the cost?". In other words, will it be used
frequently enough to compensate for the added complexity to the language?
I''m not convinced of that.

There have been some proposals floating around to implement a "with"
keyword which would create implicit namespaces. That''s sort of what you''re
proposing here. I''m not convinced either is a good idea, but if they were
to be adopted, I''d certainly want to see the them done in a uniform,
logically consistent way.


"Ralf W. Grosse-Kunstleve" <rw**@yahoo.com> wrote in message
news:ma***************************************@pyt hon.org...

class grouping:

def __init__(self, .x, .y, .z):
# real code right here Emulation using existing syntax:: def __init__(self, x, y, z):
self.x = x
del x
self.y = y
del y
self.z = z
del z



I think this is a bad idea, for a subtle reason.

In Python, unlike many other languages, the names of formal parameters are
part of a function''s interface. For example:

def f(x, y):
return x-y

Now f(3, 4) is -1 and f(y=3,x=4) is 1.

The names of instance variables are generally not part of a class''
interface--they are part of its implementation.

This proposed feature, whenever used, would tie a class'' implementation to
the interface of every method that uses the feature. As far as I can see,
it is impossible to use the feature without constraining the implementation
in this way.

For this reason, I would much rather have the mapping between parameter
names and instance variables be explicit.


"Andrew Koenig" <ar*@acm.org> wrote:

In Python, unlike many other languages, the names of formal parameters are
part of a function''s interface. For example:

def f(x, y):
return x-y

Now f(3, 4) is -1 and f(y=3,x=4) is 1.

The names of instance variables are generally not part of a class''
interface--they are part of its implementation.

This proposed feature, whenever used, would tie a class'' implementation to
the interface of every method that uses the feature. As far as I can see,
it is impossible to use the feature without constraining the implementation
in this way.



While I suppose that''s true from a theoretical point of view, as a
practical matter, I don''t see it being much of a big deal. I don''t think
I''ve ever written an __init__ method which saved its parameters and used
different names for the parameter and the corresponding instance variable.
Doing so would just be confusing (at least for the kind of code I write).

Also, it doesn''t really tie it in any hard and fast way. Right now, I
would write:

def __init__ (self, x, y, z):
self.x = x
self.y = y
self.z = z
blah

under the new proposal, I would write:

def __init__ (self, .x, .y, .z):
blah

If at some time in the future, if I decided I need to change the name of
the instance variable without changing the exposed interface, it would be
easy enough to do:

def __init__ (self, .x, .y, z):
self.zeta = z
blah

I''m still not convinced we need this, but the exposed interface issue
doesn''t worry me much.


这篇关于建议:减少self.x = x; self.y = Y; self.z = z样板代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆