我想问一下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
为什么要打印2次?对不起,这个问题,我只是想要了解python OOP的noob ......
答案 0 :(得分:3)
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]:
答案 1 :(得分:2)
这是ipython中的%autocall错误。 launchpad和github上的相关票证。它显然在当前版本的ipython中得到了解决。
属性的目的是隐藏看似普通属性赋值/访问的奇特逻辑。只有当你有一个必要的设计理由时才应该这样做,python不是java所以不需要编写样板getter和setter。
伊格纳西奥试图告诉你的是,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
,因为它有一个下划线,但请注意,这只不过是一个惯例。
答案 2 :(得分:2)
当你想直接访问对象的属性并且在某些情况下需要在getter / setter周围有一些额外的代码时,属性特别有用。
想象一下你有一个汽车对象。
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!')
挑战在于直接设置属性是非常干净和光滑的,但是没有为我们提供进行任何数据验证的机会(例如,我想确保make在已知品牌列表中)或数据类型转换(在年份示例中)。
属性通过允许我们围绕属性赋值和/或检索设置包装器代码而不是要求我们为所有属性执行此操作,甚至要求我们提前知道我们想要进行一些额外验证来解决问题。事实上,我可以按照以下方式修改我的Car对象,它仍将以完全相同的方式使用。
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
设置它,但现在它会在必要时将值转换为int,如果用户提供的值不是,则会引发异常正确转换为int。
答案 3 :(得分:0)