如何为 Python 类中的非函数成员属性创建别名?
我正在编写 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
(反之亦然)。
我可以想到很多方法来做到这一点,但没有一个看起来像我想要的那么顺利:
- 编写自定义注释
- 使用
@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...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(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.
您可以提供
__setattr__
和引用别名映射的__getattr__
:You can provide a
__setattr__
and__getattr__
that reference an aliases map:当一半用户决定使用
dx
而另一半用户决定使用d.xValue
时,您会怎么做?当他们尝试共享代码时会发生什么?当然,如果您知道所有别名,它会起作用,但是它会很明显吗?当你把代码搁置一年后,这对你来说是显而易见的吗?最后,我认为这种美好或奢侈是一个邪恶的陷阱,最终会造成更多的混乱而不是好处。
您可以通过这种方式使用属性创建别名:
但由于上述原因,我认为这不是一个好的设计。它
使 Dummy 更难阅读、理解和使用。对于每个用户,您将
用户为了理解 Dummy 必须知道的 API 的大小。
更好的替代方法是使用适配器设计模式。
这使您可以保持 Dummy 美观、紧凑、简洁:
而子域中希望使用不同词汇的用户可以这样做
通过使用 Adapter 类:
对于 Dummy 中的每个方法和属性,您只需连接相似的方法和属性
它将繁重的工作委托给 Dummy 的实例。
它可能需要更多行代码,但它允许您为 Dummy 保留干净的设计,更易于维护、记录和单元测试。人们会编写有意义的代码,因为类将限制可用的 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.
您可以使用标题为 使用描述符进行缓存和别名。这是其中显示的代码的简洁版本,它提供了您寻求的功能。
编辑:包含
Alias
属性的类可以在您删除
一个属性时自动删除任何关联的目标属性(反之亦然)。我的答案的代码现在说明了一种简单的方法,可以使用方便的类装饰器来完成此操作,该装饰器添加自定义的 __delattr__() 来在属性Alias's
可以时进行专门的删除管理参与其中。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.