Python进阶与拾遗5:Python中的新式类
在常用的Python面向对象编程中,几乎都是使用新式类。本篇博文向大家介绍Python中的新式类,下面开始干货。
新式类相关概念
- 对Python 3.0及之后的版本来说,所有的类都是“新式类”,不管是不是显式地继承自object。所有的类都继承自object,不管显式隐式,所有对象都是object的实例,包括内置类型。
- 对Python 2.6及其之前的版本来说,类必须继承自的类看作是“新式”object,并具有新式类的特性。任何从object或其他内置类型派生的类,会被自动视为新式类,只要一个内置类型位于超类树中的某个位置,就是一个新式类。
新式类的变化
- 类和类型合并。type(I)内置函数返回一个实例所创建的类,而不是一个通用的实例类型,通常和I.__class__相同。
class C: pass
class D: pass
def main():
c = C()
d = D()
print(type(c))
print(c.__class__)
print(type(C))
print(C.__class__)
print(type(d))
print(d.__class__)
print(type(D))
print(D.__class__)
print(type(c) == type(d))
l = [1, 2, 3]
print(type(l))
print(isinstance(c, object))
print(isinstance(C, object))
print(isinstance(l, object))
if __name__ == "__main__":
main()
'''
输出:
<class '__main__.C'>
<class '__main__.C'>
<class 'type'>
<class 'type'>
<class '__main__.D'>
<class '__main__.D'>
<class 'type'>
<class 'type'>
False
<class 'list'>
True
True
True
'''
- 多继承的钻石模式继承搜索顺序变更。先宽度搜索,再深度搜索。
class A:
attr = 1
class B(A):
pass
class C(A):
attr = 2
class D(B, C):
pass
def main():
x = D()
print(x.attr)
if __name__ == "__main__":
main()
'''
输出:
2
'''
- 针对内置函数的属性获取。__getattr__和__getattribute__方法不再针对内置运算的隐式属性获取并运行。名称搜索从类开始,而不是从实例开始。
- 新增高级工具如slot,特性,描述符和__getattribute__方法。
新式类的扩展
__slots__的用法
- 在class语句顶层将字符串名称顺序赋值给变量__slots__,只有__slots__列表内这些变量值可以赋值为实例属性,并且不能在类的顶层空间中赋值。
- 在__slots__中,一般会包含__dict__,这样可以收纳__slots__中不包含的属性,也使得例如getattr和setattr这样的通用方法能够运行。
class C:
__slots__ = ['a', 'b', '__dict__']
# a = 1 # ValueError: 'a' in __slots__ conflicts with class variable
def main():
X = C()
X.a = 1
X.b = 2
X.c = 3
setattr(X, 'd', 4)
print(X.__dict__)
print(dir(X))
print(getattr(X, 'd'))
if __name__ == "__main__":
main()
'''
输出:
{'c': 3, 'd': 4}
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'a', 'b', 'c', 'd']
4
'''
- 继承中的__slots__:
子类继承一个没有__slots__的超类,超类的__dict__属性总是可以访问的,并且子类的__slots__无意义。如果一个类定义了与超类相同的slots名称,那么超类中的slots变量只有通过直接从超类获取描述符才能访问。如果子类中的slots包含了__dict__,那么就可以直接访问。也就是说,子类最好加上__dict__。
class C:
a = 1
b = 2
class D(C):
__slots__ = ['c', 'd']
def main():
X = D()
X.a = 1
X.b = 2
X.c = 3
X.e = 5
setattr(X, 'd', 4)
print(X.__dict__)
print(dir(X))
print(getattr(X, 'd'))
if __name__ == "__main__":
main()
'''
输出:
{'a': 1, 'b': 2, 'e': 5}
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'c', 'd', 'e']
4
'''
class C:
__slots__ = ['c', 'd']
a = 1
b = 2
class D(C):
__slots__ = ['c', 'd', '__dict__']
def main():
X = D()
X.c = 3
X.d = 4
X.f = 5
C.c = 10
print(X.a)
print(C.c)
print(X.c)
print(X.__dict__)
print(dir(X))
if __name__ == "__main__":
main()
'''
输出:
1
10
3
{'f': 5}
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'a', 'b', 'c', 'd', 'f']
'''
类特性
内置函数property让新式类定义自动调用的方法,来读取或者赋值实例属性。一般都是在class顶层赋值。对属性本身的读取,会传递给property一个读取方法。
class newprops():
def getage(self):
return self._age
def setage(self,value):
self._age = value
age = property(getage, setage, None)
def main():
X = newprops()
X.age = 100
print(X.age)
print(X._age)
if __name__ == "__main__":
main()
'''
输出:
100
100
'''
以上,欢迎各位读者朋友提出意见或建议。
欢迎阅读笔者后续博客,各位读者朋友的支持与鼓励是我最大的动力!
written by jiong
夫人之相与,俯仰一世。
或取诸怀抱,悟言一室之内;
或因寄所托,放浪形骸之外。