在类定义中定义类“别名”

时间:2013-10-29 06:08:41

标签: python class oop

我希望能够为类名指定别名,并以某种方式定义类体中的别名。所以,例如,而不是这样做:

class C(object):
    pass
C1 = C

我希望能够做到这一点:

class C(object):
    __aliases__ = ['C1']

或类似的东西。

我的目标是在类定义中包含有关别名的信息,以便自动完成在正确的环境中工作,任何类型的内省都会显示类的别名(例如,可以对文档进行说明包括这些别名。)

我猜我可以通过跳到包含框架或其他任何东西来玩游戏,但我只是想避免任何丑陋的诡计,如果可能的话。

问题是,这可能吗?

4 个答案:

答案 0 :(得分:1)

这是使用类装饰器执行类似操作的另一种方法 - 但是在类体中没有像您想要的那样指定别名。它的非常类似于@BrenBarn的answer,除了别名是装饰器参数 - 我认为它可能更适合某些类型的使用(并且它似乎更明确,因为它使它们更显眼那样)。

import sys

def aliases(*pseudonyms):
    def aliaser(cls):
        namespace = sys._getframe(1).f_globals  # Caller's globals.
        namespace.update({alias: cls for alias in pseudonyms})
        cls.aliases = pseudonyms
        return cls
    return aliaser

if __name__ == '__main__':
    @aliases('SN', 'FUBAR')
    class LongName(object):
        pass

    print(SN)                # <class '__main__.LongName'>
    print(LongName.aliases)  # ('SN', 'FUBar')


答案 1 :(得分:0)

这是一个坏主意,但可以通过滥用类装饰器来完成:

def aliaser(cls):
    for alias in cls.aliases:
        globals()[alias] = cls
    return cls

@aliaser
class LongName(object):
    aliases = ['LN', 'Ugh']

>>> LN
<class '__main__.LongName'>

这是滥用,因为装饰器的意思是修改它们装饰的对象,但是这个只用于在全局命名空间中指向同一类的其他名称的全局副作用。

使用风险自负! ; - )

答案 2 :(得分:0)

看起来像这样处理元类是一件好事:

class AKA(type):
    """ 'Also Known As' metaclass to create aliases for a class. """
    def __new__(cls, classname, bases, attrs):
        print('in AKA.__new__')
        class_ = type(classname, bases, attrs)
        globals().update({alias: class_ for alias in attrs.get('aliases', [])})
        return class_

class C(object):
    __metaclass__ = AKA
    aliases = 'C1', 'C2'

print(C)          # <class '__main__.C'>
print(C.aliases)  # ('C1', 'C2')
print(C1)         # <class '__main__.C'>
print(C2)         # <class '__main__.C'>

注意:在Python 3.x中,指定元类的语法是不同的,需要是:

class C(object, metaclass=AKA):
    aliases = 'C1', 'C2'

答案 3 :(得分:0)

  

在类定义中定义python类“别名”

我只是在回应上述问题陈述。 Martineau的不可接受的答案与我提供一个简单别名的方式很接近。但是也许我们真的不想要别名,也许我们真的只是想采取步骤摆脱一个坏名字。

命名很难。有时我们会想更改名称。

我正在查看一些库代码,这些库代码带有需要弃用的不幸命名的类。例如:

class BadC: # Bad name, but changing it could break others!
    """Great implementation!"""

但是,多个别名没有帮助。指向同一对象的多个名称意味着要学习的内容更多,并使您的代码变得比实际需要的更为复杂。坏名声最终需要消失。

我建议您进行以下更改,以作为警告并避免破坏用户的解决方案:

class GoodC:
    """Great implementation!"""


class BadC(GoodC):
    """deprecated, use GoodC instead!"""
    def __init__(self, *args, **kwargs):
        import warnings
        warnings.warn(
          "BadC is deprecated, import and use GoodC instead!",
          DeprecationWarning)
        return super().__init__(*args, **kwargs)

自动完成功能将自动知道这些名称,自省(help(BadC))将立即显示您应该停止使用BadC

现在,您可以在其余的代码中开始用GoodC替换BadC。

>>> GoodC()
<__main__.GoodC object at 0x7f0d0c521c88>

当您或您的用户使用BadC时,他们会收到警告:

>>> BadC()
__main__:4: UserWarning: The BadC name is deprecated, import and use GoodC instead!
<__main__.BadC object at 0x7f0d0c521cc0>

并且仍然能够继续使用它:

>>> BadC()
<__main__.BadC object at 0x7f0d0c521c88>

测试通常会显示这些警告,或者用户可以启用它们,from the docs

  

在理想情况下,代码将具有合适的测试套件,并且测试运行器将在运行测试时隐式启用所有警告(由unittest模块提供的测试运行器执行此操作)。

     

在不太理想的情况下,可以通过将-Wd传递给Python解释器(这是-W default的简写)或在环境中设置PYTHONWARNINGS=default来检查应用程序是否已弃用。这将启用所有警告的默认处理,包括默认情况下被忽略的警告。要更改对遇到的警告采取的措施,您可以更改传递给-W的参数(例如-W error)。请参阅-W标志,以了解更多可能的信息。