您的位置:首页 > 编程语言 > Python开发

python 专题十七 类

2013-11-21 12:38 393 查看

字段

字段 (Field) 和 属性 (Property) 是不同的。

• 实例字段存储在 instance.__dict__,代表单个对象实体的状态。

• 静态字段存储在 class.__dict__,为所有同类型实例共享。

• 必须通过类型和实例对象才能访问字段。

• 以双下划线开头的 class 和 instance 成员视为私有,会被重命名。(module 成员不变)

>>> class User(object):
... table = "t_user"
... def __init__(self, name, age):
... self.name = name
... self.age = age
>>> u1 = User("user1", 20)   # 实例字段存储在 instance.__dict__。
>>> u1.__dict__    
{'age': 20, 'name': 'user1'}
>>> u2 = User("user2", 30)   # 每个实例的状态都是相互隔离的。
>>> u2.__dict__
{'age': 30, 'name': 'user2'}
>>> for k, v in User.__dict__.items():  # 静态字段存储在 class.__dict__。
... print "{0:12} = {1}".format(k, v)
__module__ = __main__
__dict__ = <attribute '__dict__' of 'User' objects>
__init__ = <function __init__ at 0x106eb4398>
table = t_user


可以在任何时候添加实例字段,仅影响该实例名字空间,与其他同类型实例⽆无关。
>>> u1.x = 100
>>> u1.__dict__
{'x': 100, 'age': 20, 'name': 'user1'}
>>> u2.__dict__
{'age': 30, 'name': 'user2'}


私有字段以双下划线开头,⽆无论是静态还是实例成员,都会被重命名: _<class>__<name>

>>> class User(object):
... __table = "t_user"
...
... def __init__(self, name, age):
... self.__name = name
... self.__age = age
...
... def __str__(self):
... return "{0}: {1}, {2}".format(
... self.__table,   # 编码时⽆无需关⼼心重命名。
... self.__name,
... self.__age)
>>> u = User("tom", 20)
>>> u.__dict__      # 可以看到私有实例字段被重命名了。
{'_User__name': 'tom', '_User__age': 20}
>>> str(u)
't_user: tom, 20'
>>> User.__dict__.keys()     # 私有静态字段也被重命名。
['_User__table', ...]
某些时候,我们既想使⽤用私有字段,⼜又不想放弃外部访问权限。

• ⽤用重命名后的格式访问。

• 只⽤用⼀一个下划线,仅提醒,不重命名。

不必过于纠结 "权限" 这个词,从底层来看,本就没有私有⼀一说

属性

属性 (Property) 是由 getter、setter、deleter ⼏几个⽅方法构成的逻辑。属性可能直接返回字段值,

也可能是动态逻辑运算的结果。

属性以装饰器或描述符实现,原理以后再说。实现规则很简单,也很好理解

>>> class User(object):
... @property
... def name(self): return self.__name  # 注意⼏几个⽅方法是同名的。
...
... @name.setter
... def name(self, value): self.__name = value
...
... @name.deleter
... def name(self): del self.__name
>>> u = User()
>>> u.name = "Tom"  
>>> u.__dict__   # 从 instance.__dict__ 可以看出属性和字段的差异。
{'_User__name': 'Tom'}
>>> u.name    # instance.__dict__ 中并没有 name,显然是 getter 起作⽤用了。
'Tom'
>>> del u.name   # 好吧,这是 deleter。
>>> u.__dict__
{}
>>> for k, v in User.__dict__.items():
... print "{0:12} = {1}".format(k, v)
...
__module__ = __main__
__dict__ = <attribute '__dict__' of 'User' objects>
name = <property object at 0x106ed6100>
从 class.__dict__ 可以看出,⼏几个属性⽅方法最终变成了 property object。这也解释了⼏几个同名⽅方

法为何没有引发错误。既然如此,我们可以直接⽤用 property() 实现属性。

>>> class User(object):
... def get_name(self): return self.__name
... def set_name(self, value): self.__name = value
... def del_name(self): del self.__name
... name = property(get_name, set_name, del_name, "help...")
>>> for k, v in User.__dict__.items():
... print "{0:12} = {1}".format(k, v)
__module__ = __main__
__dict__ = <attribute '__dict__' of 'User' objects>
set_name = <function set_name at 0x106eb4b18>
del_name = <function del_name at 0x106eb4b90>
get_name = <function get_name at 0x106eb4aa0>
name = <property object at 0x106ec8db8>
>>> u = User()
>>> u.name = "Tom"
>>> u.__dict__
{'_User__name': 'Tom'}
>>> u.name
'Tom'
>>> del u.name
>>> u.__dict__
{}
区别不⼤大,只是 class.__dict__ 中保留了⼏几个⽅方法。
属性⽅方法多半都很简单,⽤用 lambda 实现会更加简洁。鉴于 lambda 函数不能使⽤用赋值语句,故改
⽤用 setattr。还得注意别⽤用会被重命名的私有字段名做参数。
>>> class User(object):
... def __init__(self, uid):
... self._uid = uid
...
... uid = property(lambda o: o._uid)    # 只读属性。
...
... name = property(lambda o: o._name, \    # 可读写属性。
... lambda o, v: setattr(o, "_name", v))
>>> u = User(1)
>>> u.uid
1
>>> u.uid = 100
AttributeError: can't set attribute
>>> u.name = "Tom"
>>> u.name
'Tom'

静态方法

>>> class User(object):
... def a(): pass
...
... @staticmethod
... def b(): pass
...
... @classmethod
... def c(cls): pass
>>> User.a
<unbound method User.a>
>>> User.b
<function b at 0x10c8ef320>
>>> User.c
<bound method type.c of <class '__main__.User'>>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: