我正在编写python库API中,经常遇到我的用户需要多个不同名称的情况,以便相同的功能和变量。
如果我有一个带有函数 foo()
的python类,并且我想对其制作一个名为 bar()
的别名,那非常容易:
class Dummy:
def __init__(self):
pass
def foo(self):
pass
bar = foo
现在我可以使用没问题:
d = Dummy()
d.foo()
d.bar()
我想知道什么是使用常规变量(例如字符串)而不是函数的类属性来完成此操作的最佳方法是什么?如果我有此代码:
d = Dummy()
print(d.x)
print(d.xValue)
我想要 dx
和 d.xvalue
始终打印同一件事。如果 dx
更改,则应更改 d.xvalue
(以及Vice-vices-vice-code)。
我可以想到多种方法,但是它们看起来都不如我想要的那样流畅:
- 编写自定义注释
- 使用
@property
注释,并与setter混在一起
- 覆盖
__ setAttr __
类函数
这些方法最好?还是还有另一种方式?我忍不住觉得,如果使功能的别名如此容易,那么对于任意变量来说,它应该很容易...
I'm in the midst of writing a Python library API and I often run into the scenario where my users want multiple different names for the same functions and variables.
If I have a Python class with the function foo()
and I want to make an alias to it called bar()
, that's super easy:
class Dummy:
def __init__(self):
pass
def foo(self):
pass
bar = foo
Now I can do this with no problem:
d = Dummy()
d.foo()
d.bar()
What I'm wondering is what is the best way to do this with a class attribute that is a regular variable (e.g. a string) rather than a function? If I had this piece of code:
d = Dummy()
print(d.x)
print(d.xValue)
I want d.x
and d.xValue
to always print the same thing. If d.x
changes, it should change d.xValue
also (and vice-versa).
I can think of a number of ways to do this, but none of them seem as smooth as I'd like:
- Write a custom annotation
- Use the
@property
annotation and mess with the setter
- Override the
__setattr__
class functions
Which of these ways is best? Or is there another way? I can't help but feel that if it's so easy to make aliases for functions, it should be just as easy for arbitrary variables...
发布评论
评论(6)
这可以与类方法完全相同的方式解决。例如:
两个值将始终保持同步。您可以使用所需的属性名称编写实际的属性代码,然后用所需的任何遗留名称来校正。
This can be solved in exactly the same way as with class methods. For example:
The two values will always stay in sync. You write the actual property code with the attribute name you prefer, and then you alias it with whatever legacy name(s) you need.
您可以提供
You can provide a
__setattr__
and__getattr__
that reference an aliases map:当您的一半用户决定使用
dx
和另一半d.xvalue
时,您将要做什么?当他们尝试共享代码时会发生什么?当然,如果您知道所有的别名,它将起作用,但这会很明显吗?当您放弃一年的代码时,您会很明显吗?最后,我认为这种善良或奢侈品是一个邪恶的陷阱,最终会造成比好的混乱。
您可以通过这种方式制作属性的别名:
但是出于上述原因,我认为这不是一个好设计。它
使假人更难阅读,理解和使用。对于每个用户,您都将
用户必须知道的API大小才能了解虚拟。
更好的选择是使用适配器设计模式。
这使您可以保持虚拟,紧凑,简洁的效果:
亚域中那些希望使用其他词汇的用户可以这样做
通过使用适配器类:
对于虚拟中的每种方法和属性,您只需连接类似的方法和属性
将繁重的举重委托给虚拟的实例。
它可能是更多的代码行,但是它可以让您保留虚拟设计,更容易维护,文档和单位测试。人们会编写有意义的代码,因为该类将限制API可用的内容,并且给定他们选择的班级只有一个概念的名称。
What are you going to do when half your users decide to use
d.x
and the other halfd.xValue
? What happens when they try to share code? Sure, it will work, if you know all the aliases, but will it be obvious? Will it be obvious to you when you put away your code for a year?In the end, I think this kind of niceness or luxury is an evil trap that will eventually cause more confusion than good.
You could make aliases with properties this way:
But for the reasons mentioned above, I don't think this is a good design. It
makes Dummy harder to read, understand and use. For each user you've doubled the
size of the API the user must know in order to understand Dummy.
A better alternative is to use the Adapter design pattern.
This allows you to keep Dummy nice, compact, succinct:
While those users in the subdomain who wish to use a different vocabulary can do so
by using an Adaptor class:
For each method and attribute in Dummy, you simply hook up similar methods and properties
which delegate the heavy lifting to an instance of Dummy.
It might be more lines of code, but it will allow you to preserve a clean design for Dummy, easier to maintain, document, and unit test. People will write code that makes sense because the class will restrict what API is available, and there will be only one name for each concept given the class they've chosen.
您可以使用Activestate Python食谱中显示的一些想法,标题为 与描述符 的缓存和混叠。这是其中显示的代码的简洁版本,可提供您寻求的功能。
编辑:一个包含
别名
属性的类可以自动删除您del> del
一个(and vice-vices-vices-vices-vice-vice-vice-vice-vice-vice-vice-vice-vices-a)自动删除任何关联的目标属性。我的答案的代码现在说明了一种简单的方法,可以使用便利的类装饰器来完成此操作,该级别的__ delattr __()
在属性别名
可以使用时可以进行专门的删除管理。参与。You could use some of ideas shown in the ActiveState Python recipe titled Caching and aliasing with descriptors. Here's a concise version of the code shown there which provides the functionality you seek.
Edit: A class containing
Alias
attributes could be made to automatically delete any associated target attributes when youdel
one (and vice-versa). The code for my answer now illustrates one easy way this could be done using a convenient class decorator which adds a custom__delattr__()
to do the specialized deletion management when attributeAlias's
could be involved.此函数将属性名称作为参数,并返回作为用于获取和设置的别名的属性。
例子:
This function takes a attribute name as a param and return a property that work as an alias for getting and setting.
Example:
覆盖
__ getAttr __()
方法并返回适当的值。Override the
__getattr__()
method and return the appropriate value.