python:具有多态性的类属性/变量继承? [英] python:class attribute/variable inheritance with polymorphism?

查看:68
本文介绍了python:具有多态性的类属性/变量继承?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我作为python学徒的努力中,如果我尝试使用类属性,最近我陷入了某种奇怪的行为(从我的角度来看)。我不是在抱怨,但是希望您能提出一些有益的意见来阐明此问题。

In my endeavours as a python-apprentice i got recently stuck at some odd (from my point of view) behaviour if i tried to work with class attributes. I'm not complaining, but would appreciate some helpful comments to shed some light on this issue.

为了将复杂的问题简化为更简洁的问题,我将其表达为这样:

To reduce a complex matter into a more concise question i would formulate it like this:

确保类属性的行为更像继承树中的静态变量的 pythonic方法是什么?

What is the "pythonic" way to ensure that a class-attribute behaves more like a static variable in an inheritance tree?

在我看来,类属性的行为类似于具有多态特征的读取时复制默认值。只要我执行只读操作,它就保持为单例,
,但是一旦我通过派生的类或实例访问带有赋值的类属性,它就会变成一个新的引用丢失与继承的基本引用之间的关系。

It seems to me like a class-attribute behaves like a "copy on read" default value with polymorphic characteristics. As long as i do "read-only" operations it stays a "singleton", but as soon, as i access the class-attribute with an assignment through the derived class or instance it gets morphed into a new reference loosing the relation to the inherited base-reference.

(它肯定具有一些有趣的功能,但是您必须理解它才能让
接受它,因此有些

(It has sure potential for some interessting features, but you have to understand it to embrace it, so some insight is highly appreciated.)

class A(object):
    classvar = 'A'
    def setclassvar(self, value):
        A.classvar = value                   
    def __str__(self):
        return "%s id(%s) " %(A.classvar, hex(id(A.classvar))[2:-1].upper())

class A1(A):
    pass

class B(object):
    classvar = 'B'
    def setclassvar(self, value):
        self.__class__.classvar = value            
    def __str__(self):
        cvar = self.__class__.classvar
        return "%s id(%s) " %(cvar, hex(id(cvar))[2:-1].upper())

class B1(B):
    def setclassvar(self, value):
        self.__class__.classvar = value

a, a1 = A(), A1()
a1.setclassvar('a')
print "new instance A: %s" %a
print "new instance A1: %s" %a

b, b1 = B(), B1()
b1.setclassvar('bb')
print "new instance B: %s" %b
print "new instance B1: %s" %b1

a1.setclassvar('aa')
print "new value a1: %s" %a
print "new value a: %s" %a

a1.classvar = 'aaa'
print "direct access a1: %s id(%s)" %(a1.classvar, hex(id(a1.classvar))[2:-1].upper())
print "method access a1: %s" %a1
print "direct access a: %s" %a

会产生以下内容:


new instance A: a id(B73468A0) 
new instance A1: a id(B73468A0) 
new instance B: B id(B73551C0) 
new instance B1: bb id(AD1BFC) 
new value a1: aa id(AD1BE6) 
new value a: aa id(AD1BE6) 
direct access a1: aaa id(A3A494)
method access a1: aa id(AD1BE6) 
direct access a: aa id(AD1BE6)


因此,直接(分配)访问 object.classvar 或通过<$进行中介c $ c> self .__ class __。classvar 与 BASECLASS.classvar 不同。

So either the direct (assigning) access object.classvar or mediated through self.__class__.classvar are not the same as BASECLASS.classvar.

这是范围问题还是完全不同。

Is this a scope issue or somethin totaly different.

期待您的回答,并感谢您。 :-)

Looking forward to your answers and thanks in forward. :-)

编辑:很短时间内就有一个答案建议使用类描述符,例如:
如何制作类属性?

There was an answer for a very short time suggesting the use of class-descriptors like: How to make a class property?.

不幸的是,这似乎不起作用:

Unfortunatly that doesn't seem to work:

class Hotel(Bar):
    def __init__(self):        
        Hotel.bar += 1

hotel = Hotel()
assert hotel.bar == 51
assert hotel.bar == foo.bar

第二个断言失败! hotel.bar与 foo.bar 引用的对象不同,而 hotel.bar 引用的对象不是Hotel。

The 2nd assertion fails! hotel.bar doesn't reference the same object as foo.bar and hotel.bar references somethin other then Hotel.bar!

第二编辑:我很清楚单例被认为是反模式,我并没有打算(广泛地)使用它们。因此,我没有在问题咨询中提及他们。即使有很多解决方案讨论单例并提供有关单例的解决方案,但我的问题仍然存在:为什么类变量可以如此轻松地脱离其引用? Ruby的行为方式对我来说很自然: http://snippets.dzone.com/posts / show / 6649

2nd I'm quite aware that singletons are considered an "antipattern" and i didn't intend to use them (extensivly). Therefore i didn't mention them in the question-titel. Even so there are many solutions discussing and providing solutions with and about singletons, my question stays: Why can a class-variable detach it's reference so easily? Ruby behaves more the way it feels natural to me: http://snippets.dzone.com/posts/show/6649

推荐答案

如果难以解释实现,则是个坏主意。 / strong>

If the implementation is hard to explain, it's a bad idea.

在这种情况下,为了完整起见,我包括一个实现,这是我喜欢在Python中使用的一种棘手的东西。

In this case, I am including an implementation, for sake of completness, and for this being the kind of tricky thing I like in Python.

因此,该片段的波纹管在某种程度上使用了闭包,以提供一个可以满足OP需求的Class Decorator:一个类变量,对于派生类中的读写,该类变量保持统一

Therefore, the snippet bellow abuse somewhat of closures to come up with a Class Decorator that fills the needs of the O.P. : a class variable that remains "unified" for reading and writing within derived classes.

此外,作为奖励,我将属性包装在一个描述符中,这使得该属性在实例内也不变-因此,无论何时写入该属性,子类或原始类的子类实例,可以正确更新class属性。

Moreover, as a bonus, I wrap the attribute in a descriptor which makes the attribute unchangeable within instances as well - so whenever the attribute is written - in either a subclass or instance of a subclass of the original class, the class attribute is properly updated.

作为Zen Python的作者这样说:如果难以解释实现,那将是个坏主意-我认为我再难做些了-我们在这里谈论范围动态生成的元类。它可以正常工作,但是由于大量使用了类,元类,闭包和描述符机制,因此这是一个非常神秘的代码,从而使它失去了 unpythonic代码。

As the Zen of Python puts it: "If the implementation is hard to explain, it is a bad idea" - I don't think I could come with anything harder -- we are talking of scoped dynamically generated meta-classes here. It will work, but it looses this is "unpythonic" code as it is very cryptic due to the heavy use of the class, metaclass, closures and descriptor mechanisms.

def SingletonAttrs(**names):
    keys = names.keys()
    def class_decorator(cls):
        class Meta(type):
            def __getattribute__(cls, attr):
                if attr in keys:
                    return type.__getattribute__(owner_cls,  attr)
                return type.__getattribute__(cls, attr)
            def __setattr__(cls, attr, value):
                if attr in keys:
                    class Wrapper(object):
                        def __init__(self, value):
                            self.__set__(None, value)
                        __set__ = lambda self, instance, value: setattr(owner_cls,"__" +  attr, value)
                        __get__ = lambda self, instance, owner: type.__getattribute__(owner_cls, "__" + attr)
                    return type.__setattr__(owner_cls,  attr, Wrapper(value))
                return type.__setattr__(cls, attr, value)
        owner_cls = Meta(cls.__name__, cls.__bases__, cls.__dict__.copy())
        for key in keys:
            setattr(owner_cls, key, names[key])
        return owner_cls
    return class_decorator

if __name__ == "__main__":

    @SingletonAttrs(a="value 1", b="value 2")
    class Test(object):
        pass

    class TestB(Test):
        pass

    t = Test()
    print t.a
    print t.b
    tb = TestB()
    tb.a = "value 3"
    print Test.a

这篇关于python:具有多态性的类属性/变量继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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