速撸《python学习手册》--第25-21章-类

第25章-OOP:宏伟蓝图

为何使用类

与其他程序组成单元相比,类有三个独到之处:

  • 多重实例:类基本上就是生产对象的工厂,每次调用一个类,都有独立命名空间的新对象。
  • 通过继承进行定制:类也支持OPP的继承的概念。
  • 运算符重载:通过提供特定的协议方法,类可以重载运算符。

第26章-类代码编写基础

类产生多个实例

  • 类对象和实例对象各自有独立的命名空间。
  • 说白了类就是实例的工厂函数

类对象提供默认行为

  • class语句创建类对象并将其复制给变量名
  • class语句内的赋值语句会创建类的属性
  • 类属性提供对象的状态和行为

实例是具体的元素

  • 像函数那样调用类对象会创建新的实例对象
  • 每个实例对象继承类的属性并获得了自己的命名空间
  • 在方法内怼self属性做赋值运算会产生每个实例自己的属性

注意:

  • 可以对实例的直接赋值

类可以截获python运算符

  • 以双下划线命名的方法都是特殊钩子,可以用来拦截运算
  • 当实例出现在内置运算时,这类方法会自动调用(指上述双下划线的方法)
  • 类可以覆盖多数内置类型运算
  • 运算符覆盖方法没有默认值,而且也不需要
  • 运算符可让类与python的对象模型相继承
In [294]: class rec:pass

In [295]: rec.name='damao'

In [296]: rec.age=18

In [297]: rec.name
Out[297]: 'damao'

In [298]: x=rec()

In [299]: x.age
Out[299]: 18

In [300]: x.name
Out[300]: 'damao'
    
In [301]: rec.__dict__
Out[301]:
mappingproxy({'__module__': '__main__',
              '__dict__': ,
              '__weakref__': ,
              '__doc__': None,
              'name': 'damao',
              'age': 18})

In [302]: x.__dict__
Out[302]: {}

第27章 更多实例

第28章 类代码编写细节

  • class是创建并且隐式赋值,并不是声明
  • 注意。类可以通过直接赋值来改变属性值的。
In [303]: class ShareData:
     ...:     spam=42
     ...:

In [304]: x=ShareData()

In [305]: y=ShareData()

In [306]: x.spam
Out[306]: 42

In [307]: y.spam
Out[307]: 42

In [308]: ShareData.spam=24

In [309]: x.spam
Out[309]: 24

In [310]: y.spam
Out[310]: 24
   
In [311]: x.spam=100

In [312]: x.spam
Out[312]: 100

In [313]: y.spam
Out[313]: 24

In [314]: ShareData.spam
Out[314]: 24
  • 注意,在构造时,python只会找出并且调用一个__init__

  • 类的方法上如果使用了@abstractmethod,那么这个类不能被实例话,它的子类如果没有实现fun方法,也不能被实例化。

# 其中11是模块属性,22是函数内本地变量,33是类属性,44是方法中本地变量,55是实例属性
In [320]: X=11
     ...:
     ...: def f():
     ...:     print(X)
     ...:
     ...: def g():
     ...:     X=22
     ...:     print(X)
     ...:
     ...: class C:
     ...:     X=33
     ...:     def m(self):
     ...:         X=44
     ...:         self.X=55
     ...:

In [321]:

In [321]: print(X)
11

In [322]: f()
11

In [323]: g()
22

In [324]: print(X)
11

In [325]: obj=C()

In [326]: obj.X
Out[326]: 33

In [327]: obj.m()

In [328]: obj.x
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 obj.x

AttributeError: 'C' object has no attribute 'x'

In [329]: obj.X
Out[329]: 55

In [330]: C.X
Out[330]: 33

In [331]: C.m.X
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 C.m.X

AttributeError: 'function' object has no attribute 'X'

In [332]: g.X
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 g.X

AttributeError: 'function' object has no attribute 'X'

In [333]: obj.m.__dict__
Out[333]: {}
# 打印继承树
def classtree(cls, indent):
    print('.' * indent, cls.__name__)
    for supercls in cls.__bases__:
        classtree(supercls, indent + 3)


def instancetree(inst):
    print('Tree of %s' % inst)
    classtree(inst.__class__, 3)


def selftest():
    class A: pass

    class B(A): pass

    class C(A): pass

    class D(B, C): pass

    class E: pass

    class F(D, E): pass

    instancetree(B())
    instancetree(F())

第29章 运算符重载

运算符的重载其实就是一种拦截。

# 定义__getitem__之后立马就支持了for循环
In [381]: class stepper:
     ...:     def __getitem__(self, item):
     ...:         return self.data[item]
     ...:
     ...: X=stepper()
     ...:
     ...: X.data='Spam'
     ...:
     ...:

In [382]: X[1]
Out[382]: 'p'

In [383]: for item in X:
     ...:     print(item)
     ...:
S
p
a
m

python中所有的迭代环境都会先尝试__iter__方法,再尝试__getiterm__方法。iter方法是返回一个迭代器,而getiterm方法是获取偏移量重复索引。

In [384]: class Squares:
     ...:     def __init__(self, start, stop):
     ...:         self.value = start - 1
     ...:         self.stop = stop
     ...:     # 返回本身,所以这种方法只支持一个迭代器
     ...:     def __iter__(self):
     ...:         return self
     ...:
     ...:     def __next__(self):
     ...:         if self.value == self.stop:
     ...:             raise StopIteration
     ...:         self.value += 1
     ...:         return self.value ** 2
     ...:

In [385]:

In [385]: for i in Squares(1,5)
  File "", line 1
    for i in Squares(1,5)
                         ^
SyntaxError: invalid syntax


In [386]: for i in Squares(1,5):
     ...:     print(i)
     ...:
1
4
9
16
25

In [387]: list(Squares)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in ()
----> 1 list(Squares)

TypeError: 'type' object is not iterable

In [388]: list(Squares(1,6))
Out[388]: [1, 4, 9, 16, 25, 36]

In [389]: X=Squares(1,5)

In [390]: I=iter(X)

In [391]: next(I)
Out[391]: 1

In [392]: next(I)
Out[392]: 4

In [393]: next(I)
Out[393]: 9

In [394]: next(I)
Out[394]: 16

In [395]: next(I)
Out[395]: 25

In [396]: next(I)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
 in ()
----> 1 next(I)

 in __next__(self)
      9     def __next__(self):
     10         if self.value == self.stop:
---> 11             raise StopIteration
     12         self.value += 1
     13         return self.value ** 2

StopIteration:
  • 双下划线开头的变量名会自动扩张,比如__spam,将扩展成_x__spam
In [400]: class C1:
     ...:     def meth1(self):self.__X=88
     ...:     def meth2(self):print(self.__X)
     ...:
     ...: class C2:
     ...:     def metha(self):self.__X=99
     ...:     def methb(self):print(self.__X)
     ...:
     ...: class C3(C1,C2):pass
     ...:
     ...:

In [401]: I=C3()

In [402]:

In [402]: I.meth1()

In [403]: I.metha()

   
# 注意这个地方 值没有被覆盖了,跟下面做对比
In [404]: I.__dict__
Out[404]: {'_C1__X': 88, '_C2__X': 99}

In [405]: I.meth2()
88

In [406]: I.methb()
99

In [407]: class C1:
     ...:     def meth1(self):self.X=88
     ...:     def meth2(self):print(self.X)
     ...:
     ...: class C2:
     ...:     def metha(self):self.X=99
     ...:     def methb(self):print(self.X)
     ...:
     ...: class C3(C1,C2):pass
     ...:
     ...: I=C3()
     ...:
     ...:

In [408]: I.meth1()

In [409]: I.metha()

   
# 注意这个地方 值被覆盖了
In [410]: I.__dict__
Out[410]: {'X': 99}

In [411]: I.meth2()
99

In [412]: I.methb()
99

你可能感兴趣的:(速撸《python学习手册》--第25-21章-类)