Skip to content

Latest commit

 

History

History
289 lines (232 loc) · 7.78 KB

9.Classes.md

File metadata and controls

289 lines (232 loc) · 7.78 KB

python完全具备面向对象的特质:类的实例化、类元素调用、继承、多层继承、覆盖,并且还有自己独特的语法定义。

1、类的初印象

1.1、首先看一下类的简单实例:

class ClassName:
	<statement-1>
	.
	.
	.
	<statement-N>

一旦完成一个类的编写,同时一个名称为ClassName的命名空间被定义,可以提供给其它类引用,里面的成员有属性成员于方法成员。

1.2、类对象

类对象支持:属性引用与实例化

class MyClass:
	"""A simple example class"""
	i = 12345
	def f(self):
		return 'hello world'

其中 MyClass.i、MyClass.f都是合法的属性引用,可以给MyClass.i赋值,其中__doc__是类中的注释信息。
当一个类建立起来后,可以通过初始化函数进行初始化一些数据,python用的就是 **init()**方法:

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

1.3、实例对象

实例对象唯一能理解的操作就是属性引用. 有两种合法的属性, 数据属性和方法

class classdemo:
field='meimei:'
def __init__(self,key,value):
    self.r=key
    self.y=value
def PrintString(self,values):
    print self.field,values
u=classdemo(4,5)
print u.r,u.y
u.PrintString('is a female!')
u.field='peter:'
u.PrintString('is a male!')

>4 5  
>meimei: is a female!  
>peter: is a male!  

1.4、方法对象

方法对象绑定后就可以调用了。

class MyClass:
	"""A simple example class"""
	i = 12345
	def f(self):
		return 'hello world'
x = MyClass()
x.f()
xf = x.f
while True:
	print xf()

**x.f() 针对方法的调用,可以保存起来,xf 到后面进行调用。

2、一些说明

作为类属性的任何函数对象, 定义了一个方法用于那个类的实例. 函数是否在一个类体中其实并不重要: 指定一个函数对象给类中的局部变量也是可以的:

# 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

我们知道了方法的第一个参数默认是self,所以我们可以在同一个类中的方法可以通过self互相调用:

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)
x=Bag()
x.add(1)
x.addtwice(2)
print x.data

[1, 2, 2]

3、继承

派生类定义如下:

class DerivedClassName(BaseClassName):
	<statement-1>
	.
	.
	.
	<statement-N>

BaseClassName 的定义对于派生类而言必须是可见的. 在基类的地方, 任意的表达式都是允许的. 这就会非常有用, 比如基类定义在另一个模块:

class DerivedClassName(modname.BaseClassName):

Python 支持多重继承. 一个多重继承的类定义看起来像这样:

class DerivedClassName(Base1, Base2, Base3):
	<statement-1>
	.
	.
	.
	<statement-N>

4、私有属性

在方法成员中定义一个私有的属性,供类中的其它方法调用:

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)

5、零碎的知识点

像写个抽象函数一样我们可以定义一个空的类,然后给这个类附加一些数据属性,具体怎么用,需要在实战中体现:

class Employee:
	pass

john = Employee() # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

6、异常也是个类

用户定义的异常其实也是类. 使用这个机制, 就可以创建可扩展的异常继承体系.
有两种合法的形式用于 raise 语句:

raise Class

raise Instance

一个在 except 中的类, 可以与一个异常相容, 如果该异常是同样的类, 或是它的基类 (但是并不是另一种 – 一个 except 语句列出的派生类与其基类并不相容). 如下面的代码, 以那种顺序打印出 B, C, D:

class B(Exception):
	pass
class C(B):
	pass
class D(C):
	pass

for c in [B, C, D]:
	try:
		raise c()
	except D:
		print("D")
	except C:
		print("C")
	except B:
		print("B")

7、迭代器

大多数的容器对象都可以使用 for 来迭代:

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)

这种形式简洁, 明了并且方便. 迭代器的使用遍布于 Python 之中. 在这个外表之下,
for 语句对容器对象调用了 iter(). 这个函数返回一个迭代器对象, 它定义了 next() 方法,
用以在每次访问时得到一个元素. 当没有任何元素时, next() 将产生 StopIteration 异常,
它告诉 for 停止迭代. 你可以使用内置函数 next() 来调用 next() 方法; 这个例子展示了它如何工作:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
	next(it)
StopIteration

在看到迭代器的机制之后, 就可以很简单的将迭代行为增加到你的类中. 定义一个 iter() 方法用以返回一个具有 next() 的对象.
如果这个类定义了 next() , 那么 iter() 仅需要返回 self:

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]

>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

8、发生器

Generator (生成器) 是一个用于创建迭代器简单而且强大的工具. 它们和普通的函数很像, 但是当它们需要返回值时, 则使用 yield 语句.
每次 next() 被调用时, 生成器会从它上次离开的地方继续执行 ( 它会记住所有的数据值和最后一次执行的语句).
一个例子用以展示如何创建生成器:

def reverse(data):
	for index in range(len(data)-1, -1, -1):
		yield data[index]

>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g

9、生成器表达式

有些简单的生成器可以简洁的写出来, 而且和列表推导很类似, 仅仅是将方括号换成了圆括号.
这些表达式设计用于在一个函数中正好可以用生成器的情况. 生成器表达式更加紧密,
但是功能相对来说也少点, 并且与同样的列表推导式来说更节约内存.

>>> 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

>>> from math import pi, sin
>>> sine_table = {x: sin(x*pi/180) for x in range(0, 91)}

>>> 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']