如何覆盖类属性的setattr

时间:2018-03-27 10:43:58

标签: python override metaclass getattr setattr

我正在尝试创建一个类,其中返回类属性以及类名

// create a copy of the current array
var selected = this.state.selected.slice();
// push the new element to the copy
selected.push(id);
// replace the current array with the modified copy
this.setState({ selected: selected });

即。我想要以下

class TestClass:
    obj1 = 'hi'

我知道使用Python中的“Enum”包可以获得这种效果,但是如果我使用“Enum”包,我就无法创建标准的__init__函数。

如果我使用Enum,我会得到:

>>> TestClass.obj1
Out: ('TestClass', 'hi')

我已经尝试在元类中重写__getattribute__ magic方法,如下所示:How can I override class attribute access in python?

然而,这打破了__dir__魔术方法,然后不会返回任何东西。因此,我试图覆盖__setattr__魔术方法,但这似乎只影响在类实例上设置的属性,而不影响类属性本身。

2 个答案:

答案 0 :(得分:0)

方式1

您可以使用classmethod装饰器来定义在整个班级中可调用的方法:

<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Name="FlagColumn" Width="Auto" MinWidth="{Binding ActualWidth, ElementName=NumberColumn}"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Name="NumberColumn" Width="Auto" MinWidth="{Binding ActualWidth, ElementName=FlagColumn}"/>
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="0" Text="AAAA" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    <TextBlock Grid.Column="1" Text="BBBBBBBBBBBBB" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    <TextBlock Grid.Column="2" Text="CCCCCCCCCCCCCCCCC" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

方式2

也许你应该使用property装饰器,这样可以通过某个类的实例而不是类本身来访问病毒输出:

class TestClass:
    _obj1 = 'hi'

    @classmethod
    def obj1(cls):
        return cls.__name__, cls._obj1


class TestSubClass(TestClass):
    pass


print(TestClass.obj1())
# ('TestClass', 'hi')
print(TestSubClass.obj1())
# ('TestSubClass', 'hi')

答案 1 :(得分:0)

感谢akarilimano的建议,确实是解决问题的好方法。在此期间,我得到了同事帮助定义元类的帮助,并提出了以下解决方案(P2.7和P3兼容)

from future.utils import with_metaclass
class EnvirMeta(type):
    def __new__(mcs, name, bases, dct):
        c = super(EnvirMeta, mcs).__new__(mcs, name, bases, dct)
        c._member_names = []
        for key, value in c.__dict__.items():
            if type(value) is str and not key.startswith("__"):
                c._member_names.append(key)
                setattr(c, key, (c.__name__, value))
        return c

    def __dir__(cls):
        return cls._member_names

class MyKlass(with_metaclass(EnvirMeta, object)):
    a = 'hi'
    b = 'hi again'

print(MyKlass.a)
# ('MyKlass', 'hi')
print(MyKlass.b)
# ('MyKlass', 'hi again')
print(dir(MyKlass))
# ['a', 'b']