Python中父类和子类间类属性(非实例属性)的设置获取的传递

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python中父类和子类间类属性(非实例属性)的设置获取的传递相关的知识,希望对你有一定的参考价值。

前几天做一个项目,遇见类似这样一个问题。父类是个公用类,很多子项目中都运用到了,而子类也要作为一个基本类在该项目中的很多地方都要用到,但是的原始父类里面有些类属性(注意这里是类属性,不是实力属性)。在程序运行时候要进行重新设置。


背景:Python中父类的类属性,类方法,实力属性都能够被子类继承,实力属性的再设置很简单,当然为了控制类属性的访问权限(Python中不能完全实现控制),也可以用@preproty装饰符优化和控制实力属性的设置,父类的类属性被子类继承,可以很容易的获得父类属性的内容,但是如果想设置父类的类属性,就要用 父类名.类属性名 称来实现,那么能不能用 子类名.类属性名 来实现类属性的同步设置呢。


来看一个例子:

class Grandfather(object):
    mylist = []

    def __init__(self):
        pass

class Father(Grandfather):


    def __init__(self):
        pass

Grandfather.mylist = [1, 2, 3, 4]
print Grandfather.mylist
print Father.mylist
Father.mylist = [‘a‘]
print Grandfather.mylist
print Father.mylist


打印结果:

[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[‘a‘]

发现,如果使用

Father.mylist = [‘a‘]

来实现类属性的设置,想象中,应该父类的类属性也能被重新设置,但是结果显示出,想象的和现实还是有差距的。


我也尝试了用@preproty和@xxx.setter等修饰符,单独以及配合@classmethod修饰符来实现用Father.mylist的实现类属性的同步设置,但结果都失败了。其实可以继续使用Grandfather的类名加类属性及Grandfather来实现父类属性的设置但是,就感觉明明有了新父类,模块中交替使用这两个类名来设置类属性,确实有点不是太完美。

后来经过尝试找到了一个新的方法,就是使用类元metaclass,至于metaclass的内容,大家可以在网上找到相应的文章,这里介绍两种使用方法。

第一种:

class MetaMyList(type):
    
    def _get_dummy(self):
        return Grandfather.mylist
    
    def _set_dummy(self, value):
        Grandfather.mylist = value

    mylist = property(_get_dummy, _set_dummy)

class Grandfather(object):
    mylist = []

    def __init__(self):
        pass

class Father(Grandfather):

    __metaclass__ = MetaMyList

    def __init__(self):
        pass

Grandfather.mylist = [1, 2, 3, 4]
print Grandfather.mylist
print Father.mylist
Father.mylist = [‘a‘]
print Grandfather.mylist
print Father.mylist

打印结果令人很满意:

[1, 2, 3, 4]
[1, 2, 3, 4]
[‘a‘]
[‘a‘]

因为我们创建类的时候使用了__metaclass__, 那么类被创建的时候就会添加mylist作为自己的类属性,但是当我们使用Father.mylist来设置类属性的时候,我们其实是在将这个值传递给了Grandfather。因为Grandfather该类已经被创建,所以override该类属性的property是不现实(也许可以,但是我读书少)。那么只有在创建Father的时候来override此类属性的property,而如果想实现,那就必须用到类元,及metaclass,这东西简单,但是确实是所有类的始祖。


第二中方法,当然,也是在理解第一种方法之后,后来在读别的文章的时候发现了第二种方法。这里写出来方便大家理解。

class Grandfather(object):
    mylist = []
    def __init__(self):
        pass
class Father(Grandfather):
    class __metaclass__(type):
        @property
        def mylist(cls):
            return Grandfather.mylist
        @mylist.setter
        def mylist(cls, value):  # @NoSelf
            Grandfather.mylist = value
    def __init__(self):
        pass

Grandfather.mylist = [1, 2, 3, 4]
print Grandfather.mylist
print Father.mylist
Father.mylist = [‘a‘]
print Grandfather.mylist
print Father.mylist


这里就很容易发现在python中类是可以动态在任意合法位置使用合法缩进创建的。其实两者方法的原理一样。但是我个人还是更喜欢第一种,代码更加简洁明快。


才疏学浅,欢迎交流提意见彼此提高。


本文出自 “EIT流浪汉” 博客,请务必保留此出处http://zicowarn.blog.51cto.com/3815716/1792735

以上是关于Python中父类和子类间类属性(非实例属性)的设置获取的传递的主要内容,如果未能解决你的问题,请参考以下文章

java多态中父类和子类一定要有一样的方法名吗

c#如何在父类(或是接口)当中定义一个子类必须要重写的字段(属性)?

delphi中父类和子类之间的转换

NHibernate 中父类和子类的 ID

java中父类和子类初始化顺序

Java 如何实现父类转换为子类的效果?