Python“属性”和“特性”之间有什么区别?

2025-04-15 09:19:00
admin
原创
27
摘要:问题描述:我通常对“属性”和“特性”之间的区别感到困惑,并且我找不到很好的资源来简明扼要地详细说明这些区别。解决方案 1:属性是一种特殊的属性。基本上,当 Python 遇到以下代码时:spam = SomeObject() print(spam.eggs) 它会在1eggs中查找,然后检查它是否具有、或方法...

问题描述:

我通常对“属性”和“特性”之间的区别感到困惑,并且我找不到很好的资源来简明扼要地详细说明这些区别。


解决方案 1:

属性是一种特殊的属性。基本上,当 Python 遇到以下代码时:

spam = SomeObject()
print(spam.eggs)

它会在1eggs中查找,然后检查它是否具有、或方法——如果有,则它是一个属性,Python 会调用该方法(因为我们执行的是查找操作),并返回该方法的返回值。如果它不是属性,则会在 中查找,并返回在那里找到的任何值。SomeObject`eggs__get__set__delete__geteggsspam`

有关Python 的数据模型和描述符的更多信息。


1非常感谢 Robert Seimer 对查找顺序的修正。

解决方案 2:

通过属性 (property),您可以完全控制其 getter、setter 和 deleter 方法,而使用属性 (attribute) 则无法做到这一点(如果不使用警告)。

class A(object):
    _x = 0
    '''A._x is an attribute'''

    @property
    def x(self):
        '''
        A.x is a property
        This is the getter method
        '''
        return self._x

    @x.setter
    def x(self, value):
        """
        This is the setter method
        where I can check it's not assigned a value < 0
        """
        if value < 0:
            raise ValueError("Must be >= 0")
        self._x = value

>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
  File "ex.py", line 15, in <module>
    a.x = -1
  File "ex.py", line 9, in x
    raise ValueError("Must be >= 0")
ValueError: Must be >= 0

解决方案 3:

一般来说,属性 (property) 和特性 (attribute) 是同一回事。不过,Python 中有一个属性装饰器,它提供了对特性 (或其他数据) 的 getter/setter 访问。

class MyObject(object):
    # This is a normal attribute
    foo = 1

    @property
    def bar(self):
        return self.foo

    @bar.setter
    def bar(self, value):
        self.foo = value


obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo

解决方案 4:

属性 (property) 允许您像普通属性 (attribute) 一样获取和设置值,但其底层调用了一个方法,将其转换为 getter 和 setter。这实际上只是为了减少调用 getter 和 setter 的样板代码。

举个例子,你有一个类,里面保存着你需要的 x 和 y 坐标。要设置它们,你可能需要执行以下操作:

myObj.x = 5
myObj.y = 10

这比写作更容易看和思考:

myObj.setX(5)
myObj.setY(10)

问题是,如果有一天你的类发生了变化,需要将 x 和 y 偏移某个值,该怎么办?现在你需要修改类定义以及所有调用它的代码,这非常耗时且容易出错。该属性允许你使用前一种语法,同时赋予你修改后一种语法的灵活性。

在 Python 中,你可以使用 property 函数定义 getter、setter 和 delete 方法。如果你只需要读取属性,也可以在方法上方添加 @property 装饰器。

http://docs.python.org/library/functions.html#property

解决方案 5:

我从 Bernd Klein 的网站上了解到了 2 个不同之处,总结如下:

1. 属性是实现数据封装的更便捷的方式

例如,假设你有一个公共属性length。稍后,你的项目需要你将其封装起来,即将其更改为私有属性,并提供 getter 和 setter => 你必须更改之前编写的代码:

# Old code
obj1.length = obj1.length + obj2.length
# New code (using private attributes and getter and setter)
obj1.set_length(obj1.get_length() + obj2.get_length()) # => this is ugly

如果您使用@propertyand @length.setter=> 则无需更改旧代码。

2. 一个属性可以封装多个特性

class Person:
  def __init__(self, name, physic_health, mental_health):
    self.name = name
    self.__physic_health = physic_health 
    self.__mental_health = mental_health 

  @property
  def condition(self):
    health = self.__physic_health + self.__mental_health
    if(health < 5.0):
      return "I feel bad!"
    elif health < 8.0:
      return "I am ok!"
    else:
      return "Great!"

在这个例子中,__physic_health__mental_health是私有的,不能从外部直接访问。

解决方案 6:

我用来缓存或刷新数据还有一个不太明显的区别,我们经常会用一个函数连接到类属性。例如,我需要读取一次文件,并将内容赋给属性,这样值就被缓存了:

class Misc():
        def __init__(self):
            self.test = self.test_func()

        def test_func(self):
            print 'func running'
            return 'func value'

cl = Misc()
print cl.test
print cl.test

输出:

func running
func value
func value

我们访问了该属性两次,但我们的函数只被触发了一次。将上面的示例更改为使用 property ,将导致每次访问该属性时其值都会刷新:

class Misc():

    @property
    def test(self):
        print 'func running'
        return 'func value'

cl = Misc()
print cl.test
print cl.test

输出:

func running
func value
func running
func value

解决方案 7:

我喜欢这样想,如果您想为属性设置限制,请使用属性。

虽然所有属性都是公共的,但程序员通常用下划线(_)来区分公共属性和私有属性。考虑以下类,

class A:
    def __init__(self):
        self.b = 3    # To show public
        self._c = 4   # To show private

这里,b属性旨在从类 A 外部访问。但是,此类的读者可能会疑惑,b属性可以从类外部设置A吗?

如果我们不想b从外部进行设置,我们可以用 来表明这一意图@property

class A:
    def __init__(self):
        self._c = 4   # To show private
   
    @property
    def b(self):
        return 3

现在,b无法设置。

a = A()
print(a.b)   # prints 3
a.b = 7      # Raises AttributeError

或者,如果您只想设置某些值,

class A:
    @property 
    def b(self):
        return self._b
    
    @b.setter
    def b(self, val):
        if val < 0:
            raise ValueError("b can't be negative")
        self._b = val

a = A()
a.b = 6     # OK
a.b = -5    # Raises ValueError

解决方案 8:

属性实际上存在于对象中。

属性通过代理传递。(其值可能会被动态计算。)


参见

解决方案 9:

对于一个用例,我使用@property按需加载数据和缓存

class Foo:
    def __init__(self):
        self._bar = None

    @property
    def bar(self):
        if _bar is None:
            _bar = self.load_bar_dataset_from_database()
        return _bar

当我的字段包含用于分析的数据框时,它们会在第一次访问时加载,并且我不会通过一次性从数据库加载数据框来初始化整个对象,但也可以缓存以用于进一步的分析。

还可以防止“设置”一致性。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用