理解Python中的属性
我想问一下关于Python中的属性(Property),我正在写下面的代码……
有没有人能解释一下我代码的输出,并简单说明一下属性是什么,什么时候应该使用它?
class C(object):
def __init__(self):
self.x = 'sulthan'
self.y = 'ahnaf'
@property
def name(self):
print self.x
print self.y
现在当我运行这段代码时:
>>> c = C()
>>> c.name
sulthan
ahnaf
sulthan
ahnaf
为什么它打印了两次?抱歉问这个问题,我只是个新手,想理解Python的面向对象编程……
4 个回答
这是ipython中的一个%autocall错误。相关的讨论可以在launchpad和github上找到。这个问题在当前版本的ipython中似乎已经解决。
属性的目的是为了把复杂的逻辑隐藏在看起来像普通属性赋值或访问的后面。你只有在有设计上的理由时才应该这样做,Python和Java不一样,不需要对每个属性都写一堆重复的获取和设置方法。
Ignacio想告诉你的是,在name()
的定义中,似乎没有必要加那些打印语句。
这里是你例子的一个更常见的实现,使用了属性。
class Person(object):
def __init__(self):
self._name = 'sulthan ahnaf'
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
现在你有了一个属性_name
,你可以通过“属性”name
来控制对它的访问。愿意遵守规则的人会不去碰你的_name
,因为它前面有个下划线,但要注意这只是一个约定。
属性在你想直接访问一个对象的特性时特别有用,有时候还需要在获取和设置这些特性时加一些额外的代码。
想象一下你有一个汽车对象。
class Car(object):
def __init__(self, make, model, year, vin):
self.make = make
self.model = model
self.year = year
self.vin = vin
my_car = Car('Ford', 'Taurus', 2005, '123ABCVINSARELONG999')
现在假设我需要更改汽车的年份。我可能会用几种不同的方法来做到这一点。
my_car.year = 2006
my_car.year = '2007'
第二种方法如果我想假设年份是一个数字,那就会出现一些严重的问题。看看下面的例子:
if(my_car.year > 2010):
print('Shiney new!')
问题在于,直接设置属性看起来很简单,但这并没有给我们机会去验证数据(比如我可能想确保汽车品牌在一个已知品牌的列表中)或者进行数据类型转换(就像年份的例子)。
属性的好处在于,它们允许我们在设置或获取属性时加上一些额外的代码,但并不要求我们对所有属性都这样做,或者提前知道我们想要进行额外的验证。我可以在之后修改我的汽车对象,如下所示,仍然可以以完全相同的方式使用它。
class Car(object):
def __init__(self, make, model, year, vin):
self.make = make
self.model = model
self._year = year
self.vin = vin
def get_year(self):
return self._year
def set_year(self, val):
self._year = int(val)
year = property(get_year, set_year)
你仍然可以通过 my_car.year
来访问年份,仍然可以用 my_car.year = 2006
来设置它,但现在它会在必要时将值转换为整数,并且如果用户提供的值不能正确转换为整数,就会抛出一个异常。
这似乎是ipython的问题,如果你使用python命令行,它会正确显示输出(只显示一次)
[avasal@avasal]$ python
Python 2.7 (r27:82500, Sep 16 2010, 18:02:00)
[GCC 4.5.1 20100907 (Red Hat 4.5.1-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class C(object):
... def __init__(self):
... self.x = 'sulthan'
... self.y = 'ahnaf'
... @property
... def name(self):
... print self.x
... print self.y
...
>>> c1 = C()
>>> c1.name
sulthan
ahnaf
>>>
[avasal@avasal]$ ipython
Python 2.7 (r27:82500, Sep 16 2010, 18:02:00)
Type "copyright", "credits" or "license" for more information.
IPython 0.10.2 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.
In [1]: class C(object):
...: def __init__(self):
...: self.x = 'sulthan'
...: self.y = 'ahnaf'
...: @property
...: def name(self):
...: print self.x
...: print self.y
...:
In [2]: c1 = C()
In [3]: c1.name
sulthan
ahnaf
sulthan
ahnaf
In [4]: