【问题标题】:Python: defining properties in constructor from a list of itemsPython:从项目列表中定义构造函数中的属性
【发布时间】:2013-01-04 22:42:49
【问题描述】:

我想在我的类的构造函数中声明属性。

MaterialOne 类展示了我目前拥有它的方式。每个属性都必须单独定义。但是,我将有一组相似的属性,我想给出相同的 fset/fget/fdel。

由于需要大量代码来显式编写所有属性,因此我想以更简洁的方式定义属性。因此,我想到让构造函数处理这个问题。 MateralTwo 类展示了我的想法。

不幸的是,它不起作用,因为我收到 TypeErrors:

TypeError: get_property() takes exactly 1 argument (2 given)

我可以理解它为什么会抱怨,但我想不出任何解决方案。我不一定要从构造函数的列表中定义属性。我正在寻找的是一种更简洁明了的定义它们的方法。

class MaterialOne(object):
    def __init__(self):
        pass;

    def del_property(attr):
        """Abstract deller"""
        def del_attr(self):
            setattr(self, attr, None);
        return del_attr

    def set_property(attr):
        """Abstract setter."""
        def set_attr(self, x):
            setattr(self, attr, x);            
        return set_attr

    def get_property(attr):
        """Abstract getter"""
        def get_attr(self):
            if getattr(self, attr) is not None:
                return getattr(self, attr); 
            else:
                return 'Some calculated value..'
        return get_attr

    _young = None;
    _shear = None;
    _poisson = None;

    young = property(fget=get_property('_young'), fset=set_property('_young'), fdel=del_property('_young'));
    shear = property(fget=get_property('_shear'), fset=set_property('_shear'), fdel=del_property('_shear'));
    poisson = property(fget=get_property('_poisson'), fset=set_property('_poisson'), fdel=del_property('_poisson'));


class MaterialTwo(object):
    def __init__(self):
        properties = ['young', 'shear', 'poisson'];
        self.create_properties(properties)

    def del_property(attr):
        """Abstract deller"""
        def del_attr(self):
            setattr(self, attr, None);
        return del_attr

    def set_property(attr):
        """Abstract setter."""
        def set_attr(self, x):
            setattr(self, attr, x);            
        return set_attr

    def get_property(attr):
        """Abstract getter"""
        def get_attr(self):
            if getattr(self, attr) is not None:
                return getattr(self, attr); 
            else:
                return 'Some calculated value..'
        return get_attr        

    def create_properties(self, items):
        for item in items:
            storage = '_'+item;
            setattr(self, storage, None);
            setattr(self, item, property(fget=self.get_property(storage), fset=self.set_property(storage), fdel=self.del_property(storage)));


steel = MaterialOne(); 
steel.young = 2e11;
steel.poisson = 0.3;
print steel.poisson
print steel.shear

carbon = MaterialTwo();
carbon.young = 2e11;
carbon.poisson = 0.3;
print carbon.poisson
print carbon.shear

澄清更多关于代码的内容。我想写的是材料类,固体、液体、气体,它们每个都是材料的子类。许多材料属性将被分配。有些可以根据已经定义的来计算。例如,给定两个弹性模量,可以计算出第三个。

我现在使用与 MaterialOne 非常相似的东西实现了这一点。然而,随着我获得更多的材料属性,并且还将包括更多此类计算,我想让它更清洁、更有条理。像我在 MaterialTwo 中那样编写它对我来说是可能的。

【问题讨论】:

  • 样式点与你的问题无关:你在 python 中不需要分号
  • 您最终想要完成什么? (看起来您可能走错了路。)您是否尝试在首次访问属性时“按需”计算每个值,然后缓存该值?

标签: python class properties


【解决方案1】:
setattr(self, item, property(...

这最终是你的问题。由于属性是描述符,它们必须绑定到类,而不是实例。你需要override __getattr__(), __setattr__(), and __delattr__() 并在那里实现它。

【讨论】:

  • 没错,它归结为那一行。就像你说的,描述符绑定到类而不是实例。因此,它不适用于构造函数。我现在知道了。我会看看覆盖将涉及什么,但可能我必须恢复到我在 MaterialOne 中的做法。
【解决方案2】:

所有定义都应将self 作为第一个参数。

这些函数应该是这样的:

def del_property(self, attr):
def sel_property(self, attr):
def get_property(self, attr):

【讨论】:

    【解决方案3】:

    当在 Python 中对对象调用方法时,该对象会作为第一个参数静默传递,这就是为什么您会收到错误消息,指出您传递了太多参数。正如其他人所说,您需要将 self 作为函数的第一个参数。

    【讨论】:

      猜你喜欢
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 2022-12-07
      • 1970-01-01
      相关资源
      最近更新 更多