doc: 阅读python面向对象文档
This commit is contained in:
344
python/py.md
344
python/py.md
@@ -103,6 +103,23 @@
|
|||||||
- [global](#global)
|
- [global](#global)
|
||||||
- [nonlocal](#nonlocal)
|
- [nonlocal](#nonlocal)
|
||||||
- [global namespace](#global-namespace)
|
- [global namespace](#global-namespace)
|
||||||
|
- [Class Objects](#class-objects)
|
||||||
|
- [__init__](#init)
|
||||||
|
- [data attributes](#data-attributes)
|
||||||
|
- [method object](#method-object)
|
||||||
|
- [class and instance variables](#class-and-instance-variables)
|
||||||
|
- [function object](#function-object)
|
||||||
|
- [Inheritance](#inheritance)
|
||||||
|
- [attribute resolving](#attribute-resolving)
|
||||||
|
- [method resolving](#method-resolving)
|
||||||
|
- [built-in functions](#built-in-functions)
|
||||||
|
- [private variables](#private-variables)
|
||||||
|
- [name mangling](#name-mangling)
|
||||||
|
- [odds and ends](#odds-and-ends)
|
||||||
|
- [`__self__, __func__`](#__self__--__func__)
|
||||||
|
- [iterators](#iterators)
|
||||||
|
- [generators](#generators)
|
||||||
|
- [generator expression](#generator-expression)
|
||||||
|
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
@@ -1691,3 +1708,330 @@ After nonlocal assignment: nonlocal spam
|
|||||||
After global assignment: nonlocal spam
|
After global assignment: nonlocal spam
|
||||||
In global scope: global spam
|
In global scope: global spam
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Class Objects
|
||||||
|
class对象支持两种类型的操作,`attribute reference`和`instantiation`。
|
||||||
|
|
||||||
|
attribute reference使用`obj.name`的语法。class定义如下:
|
||||||
|
```py
|
||||||
|
class MyClass:
|
||||||
|
"""A simple example class"""
|
||||||
|
i = 12345
|
||||||
|
|
||||||
|
def f(self):
|
||||||
|
return 'hello world'
|
||||||
|
```
|
||||||
|
`MyClass.i`和`MyClass.f`是有效的attribute reference,会返回一个integer和一个function。
|
||||||
|
|
||||||
|
`__doc__`也是一个有效的attribute,返回对该class的简单文档描述。
|
||||||
|
|
||||||
|
类实例化类似于函数的调用,其语法如下:
|
||||||
|
```py
|
||||||
|
x = MyClass()
|
||||||
|
```
|
||||||
|
上述示例会创建一个MyClass类型的对象,并且将其赋值给本地变量x。
|
||||||
|
|
||||||
|
#### __init__
|
||||||
|
python中支持在初始化时为对象指定状态,故而可以自定义构造器,示例如下:
|
||||||
|
```py
|
||||||
|
class Complex:
|
||||||
|
def __init__(self, realpart, imagpart):
|
||||||
|
self.r = realpart
|
||||||
|
self.i = imagpart
|
||||||
|
|
||||||
|
c = Complex(3.0, -4.5)
|
||||||
|
```
|
||||||
|
#### data attributes
|
||||||
|
python中的data attributes类似于c++中的data members,但是,`data attributes`并不需要被声明,其类似于local variables,其在第一次赋值时就存在了。
|
||||||
|
|
||||||
|
例如,`变量x是MyClass类的实例`,那么如下代码将会输出`16`.
|
||||||
|
|
||||||
|
#### method object
|
||||||
|
除了通过data attribute外,另一种attribute reference的方式是method。
|
||||||
|
|
||||||
|
在python中,class中的function定义了object中的method。但是,`x.f`和`MyClass.f`并不等价,前者是method object,后者是function object。
|
||||||
|
|
||||||
|
通常,method在其所绑定的对象后调用:
|
||||||
|
```py
|
||||||
|
x.f()
|
||||||
|
```
|
||||||
|
|
||||||
|
python中,`x.f`为一个method object,支持被存储在变量中,并可以在后续通过变量调用,示例如下:
|
||||||
|
```py
|
||||||
|
xf = x.f
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print(xf())
|
||||||
|
```
|
||||||
|
如上所示,method object `x.f`被存储在local variable `xf`中后,后续可以通过`xf()`来调用method object。
|
||||||
|
|
||||||
|
> 按照`MyClass`的类定义,`x.f`方法将会接收一个`self`参数,但是在调用`xf()`时,并没有传递任何参数。
|
||||||
|
|
||||||
|
实际上,对于method而言,其method所绑定的对象实例将会作为参数被传向function的第一个参数`self`。
|
||||||
|
|
||||||
|
故而,对于method object和function object而言,`x.f()`实际上等价于`MyClass.f(x)`。
|
||||||
|
|
||||||
|
即,对于method object而言,`obj.method(arg1, arg2 ...)`的调用等价于`Class.method(obj, arg1, arg2 ...)`的function调用。
|
||||||
|
|
||||||
|
### class and instance variables
|
||||||
|
简单来说,每个对象的instance variables是相互独立的,但是class variables则是在同一类的所有对象间都是共享的。
|
||||||
|
|
||||||
|
```py
|
||||||
|
class Dog:
|
||||||
|
|
||||||
|
kind = 'canine' # class variable shared by all instances
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name # instance variable unique to each instance
|
||||||
|
|
||||||
|
>>> d = Dog('Fido')
|
||||||
|
>>> e = Dog('Buddy')
|
||||||
|
>>> d.kind # shared by all dogs
|
||||||
|
'canine'
|
||||||
|
>>> e.kind # shared by all dogs
|
||||||
|
'canine'
|
||||||
|
>>> d.name # unique to d
|
||||||
|
'Fido'
|
||||||
|
>>> e.name # unique to e
|
||||||
|
'Buddy'
|
||||||
|
```
|
||||||
|
|
||||||
|
对于class variables而言,其既可以通过`MyClass.name`来进行访问,也可以通过`obj.name`来进行访问。
|
||||||
|
|
||||||
|
但是,在class variable和instance variable同名时,instance variable会优先被访问,示例如下:
|
||||||
|
```py
|
||||||
|
class Warehouse:
|
||||||
|
purpose = 'storage'
|
||||||
|
region = 'west'
|
||||||
|
|
||||||
|
w1 = Warehouse()
|
||||||
|
print(w1.purpose, w1.region)
|
||||||
|
storage west
|
||||||
|
w2 = Warehouse()
|
||||||
|
w2.region = 'east'
|
||||||
|
print(w2.purpose, w2.region)
|
||||||
|
storage east
|
||||||
|
```
|
||||||
|
|
||||||
|
在python中,用户既可以通过method来访问data attributes,也可以通过对象直接访问。并且,python中也没有类似其他语言中`private`这类强制隐藏的机制,`python中都是基于约定`。
|
||||||
|
|
||||||
|
在使用data attributes时,应当小心如下场景:
|
||||||
|
- data attributes可能被method维护和管理,若用户不经过method直接修改attribute的值,可能会造成attribute的状态被破坏(没有经过method中的相关校验直接将attribute改为错误值)
|
||||||
|
- 用户可以在`避免命名冲突`的前提下向data attributes添加自己的值
|
||||||
|
|
||||||
|
在python中,对象中method的第一个参数名为`self`,这只是一个约定,`self`在python中并没有特别的意义。
|
||||||
|
|
||||||
|
#### function object
|
||||||
|
python中,function object为一个class attribute,用于定义method。function object并不一定要定义在class内部,示例如下:
|
||||||
|
```py
|
||||||
|
# Function defined outside the class
|
||||||
|
def f1(self, x, y):
|
||||||
|
return min(x, x+y)
|
||||||
|
|
||||||
|
class C:
|
||||||
|
f = f1
|
||||||
|
|
||||||
|
def g(self):
|
||||||
|
return 'hello world'
|
||||||
|
|
||||||
|
h = g
|
||||||
|
```
|
||||||
|
在上述示例中,类`C`包含`f, g, h`三个attributes,C实例中也包含`f, g, h`三个method。其中,`h`和`g`完全等价。
|
||||||
|
|
||||||
|
在python的class定义中,method可以通过`self.xxx`调用其他method,示例如下:
|
||||||
|
```py
|
||||||
|
class Bag:
|
||||||
|
def __init__(self):
|
||||||
|
self.data = []
|
||||||
|
|
||||||
|
def add(self, x):
|
||||||
|
self.data.append(x)
|
||||||
|
|
||||||
|
def addtwice(self, x):
|
||||||
|
self.add(x)
|
||||||
|
self.add(x)
|
||||||
|
```
|
||||||
|
method中同样可以访问global names,method关联的global scope是method定义所位于的module。
|
||||||
|
|
||||||
|
> 在python中,每个值都是一个对象,其class信息存储在`object.__class__`中。
|
||||||
|
|
||||||
|
### Inheritance
|
||||||
|
在python中,支持类的继承,示例如下:
|
||||||
|
```py
|
||||||
|
class DerivedClassName(BaseClassName):
|
||||||
|
<statement-1>
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
<statement-N>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### attribute resolving
|
||||||
|
若派生类B继承了基类A,那么在对B的对象进行attribute解析时,其首先会查找派生类,如果在派生类中没有找到,则会继续在基类中查找。
|
||||||
|
|
||||||
|
#### method resolving
|
||||||
|
method解析也会从派生类开始,沿着基类逐渐查询,直到找到对应的function object。
|
||||||
|
|
||||||
|
在python中,派生类的方法会覆盖基类的方法,用c++中的概念来理解,即python中所有的method都是virtual的。
|
||||||
|
|
||||||
|
在python中,如果派生类方法中想要调用基类的方法,可以通过`BaseClassName.methodname(self, arguments)`,其类似于其他语言中的`super`。
|
||||||
|
|
||||||
|
#### built-in functions
|
||||||
|
python中包含如下built-in function来判断继承关系:
|
||||||
|
- `isinstance`: 该方法通常用于检查是否实例属于某一个类
|
||||||
|
- `isinstance(obj, int)`
|
||||||
|
- `issubclass`: 该方法通常用于检查是否一个类派生自另一个类
|
||||||
|
- `issubclass(bool, int)`: 该调用返回为True,bool是int的子类
|
||||||
|
|
||||||
|
### private variables
|
||||||
|
python中并不存在只能从类内部访问的`private instance variable`。但是,python编码中存在一个规范约束:
|
||||||
|
- 以`_`开头的名称应当被作为api中的非公开部分(下划线开头的可以是function, method, data member)
|
||||||
|
|
||||||
|
#### name mangling
|
||||||
|
在类定义中,任何以`__spam`定义的name(至少两个前缀下划线,最多一个后缀下划线),都会被替换为`_classname__spam`的形式。
|
||||||
|
|
||||||
|
name magling在不破坏列内部调用的场景下十分有用,示例如下:
|
||||||
|
```py
|
||||||
|
class Mapping:
|
||||||
|
def __init__(self, iterable):
|
||||||
|
self.items_list = []
|
||||||
|
self.__update(iterable)
|
||||||
|
|
||||||
|
def update(self, iterable):
|
||||||
|
for item in iterable:
|
||||||
|
self.items_list.append(item)
|
||||||
|
|
||||||
|
__update = update # private copy of original update() method
|
||||||
|
|
||||||
|
class MappingSubclass(Mapping):
|
||||||
|
|
||||||
|
def update(self, keys, values):
|
||||||
|
# provides new signature for update()
|
||||||
|
# but does not break __init__()
|
||||||
|
for item in zip(keys, values):
|
||||||
|
self.items_list.append(item)
|
||||||
|
```
|
||||||
|
在上述代码中,即使在`MappingSubclass`中引入`__update`,其名称也为`_MappingSubclass__update`,和`_Mapping__update`不同,仍然不会对父类造成影响。
|
||||||
|
|
||||||
|
在类中以`__spam`定义的变量,在类外部可以以`_classname__spam`进行访问。
|
||||||
|
|
||||||
|
### odds and ends
|
||||||
|
有时想使用类似C语言中的struct,惯用方法是使用`dataclasses`,示例如下所示:
|
||||||
|
```py
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Employee:
|
||||||
|
name: str
|
||||||
|
dept: str
|
||||||
|
salary: int
|
||||||
|
```
|
||||||
|
```py
|
||||||
|
>>> john = Employee('john', 'computer lab', 1000)
|
||||||
|
>>> john.dept
|
||||||
|
'computer lab'
|
||||||
|
>>> john.salary
|
||||||
|
1000
|
||||||
|
```
|
||||||
|
|
||||||
|
### `__self__, __func__`
|
||||||
|
instance method object拥有如下属性:
|
||||||
|
- `__self__`: `m.__self__`代表method m关联的实例对象
|
||||||
|
- `__func__`: `m.__func__`代表method关联的function object
|
||||||
|
|
||||||
|
### iterators
|
||||||
|
在python中,大多数容器对象都可以通过for-statements进行迭代:
|
||||||
|
```py
|
||||||
|
for element in [1, 2, 3]:
|
||||||
|
print(element)
|
||||||
|
for element in (1, 2, 3):
|
||||||
|
print(element)
|
||||||
|
for key in {'one':1, 'two':2}:
|
||||||
|
print(key)
|
||||||
|
for char in "123":
|
||||||
|
print(char)
|
||||||
|
for line in open("myfile.txt"):
|
||||||
|
print(line, end='')
|
||||||
|
```
|
||||||
|
在底层,for-statement针对容器对象调用了`iter()`方法,该方法会返回一个`iterator`对象,iterator对象中定义了`__next__()`方法,该方法在终止时会抛出`StopIteration`异常。
|
||||||
|
|
||||||
|
可以通过内置的`next()`方法来调用`__next__()`,示例如下所示:
|
||||||
|
```py
|
||||||
|
>>> s = 'abc'
|
||||||
|
>>> it = iter(s)
|
||||||
|
>>> it
|
||||||
|
<str_iterator object at 0x10c90e650>
|
||||||
|
>>> next(it)
|
||||||
|
'a'
|
||||||
|
>>> next(it)
|
||||||
|
'b'
|
||||||
|
>>> next(it)
|
||||||
|
'c'
|
||||||
|
>>> next(it)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
next(it)
|
||||||
|
StopIteration
|
||||||
|
```
|
||||||
|
如果想要为自定义类添加iterator,可以在类中定义一个`__iter__()`方法,该方法返回一个带`__next__()`方法的对象。`如果一个class中包含了__next__()方法的定义,那么__iter__()方法仅需返回self即可`。
|
||||||
|
|
||||||
|
```py
|
||||||
|
class Reverse:
|
||||||
|
"""Iterator for looping over a sequence backwards."""
|
||||||
|
def __init__(self, data):
|
||||||
|
self.data = data
|
||||||
|
self.index = len(data)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.index == 0:
|
||||||
|
raise StopIteration
|
||||||
|
self.index = self.index - 1
|
||||||
|
return self.data[self.index]
|
||||||
|
```
|
||||||
|
|
||||||
|
### generators
|
||||||
|
`Generators`可以简单的创建iterator,其编写和函数类似,但是当想要返回值时,使用`yield statement`。
|
||||||
|
|
||||||
|
每次调用`next()`时,generator都会从上次中止的地方进行恢复。示例如下所示:
|
||||||
|
```py
|
||||||
|
def reverse(data):
|
||||||
|
for index in range(len(data)-1, -1, -1):
|
||||||
|
yield data[index]
|
||||||
|
```
|
||||||
|
```py
|
||||||
|
>>> for char in reverse('golf'):
|
||||||
|
print(char)
|
||||||
|
|
||||||
|
f
|
||||||
|
l
|
||||||
|
o
|
||||||
|
g
|
||||||
|
```
|
||||||
|
通过generator完成的任何事情都可以通过iterator来完成,但是generator的代码更加紧凑,其`__iter__`和`__next__`方法都是自动生成的。
|
||||||
|
|
||||||
|
在generator的多次next调用之间,local variables的状态和执行状态也是自动保存的。
|
||||||
|
|
||||||
|
generator令iterator的编写更加简单。
|
||||||
|
|
||||||
|
### generator expression
|
||||||
|
一些简单的迭代器可以简化为表达式:
|
||||||
|
```py
|
||||||
|
>>> sum(i*i for i in range(10)) # sum of squares
|
||||||
|
285
|
||||||
|
|
||||||
|
>>> xvec = [10, 20, 30]
|
||||||
|
>>> yvec = [7, 5, 3]
|
||||||
|
>>> sum(x*y for x,y in zip(xvec, yvec)) # dot product
|
||||||
|
260
|
||||||
|
|
||||||
|
>>> unique_words = set(word for line in page >>> for word in line.split())
|
||||||
|
|
||||||
|
>>> valedictorian = max((student.gpa, student.name) for student in graduates)
|
||||||
|
|
||||||
|
>>> data = 'golf'
|
||||||
|
>>> list(data[i] for i in range(len(data)-1, -1, -1))
|
||||||
|
['f', 'l', 'o', 'g']
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user