Python的类与对象

程序员自定义类型

举个例子:创建一个叫做Point的内置类型,代表二维空间中 的一个点。
程序员自定义类型也被称作类(class)。

class Point:
   """Represents a point in 2-D space"""

头部语句表明新类的名称是Point。主体部分是文档字符串,用来解释这个类的用途。
定义一个叫做Point的类将创建了一个类对象(class object)。

>>> Point
<class '__main__.Point'>

由于Point是定义在顶层的,所以它的“全名”是__main__.Point

类对象就像是一个用来创建对象的工厂。要创建一个点,可以像调用函数那样调用Point

>>> blank = Point()
>>> blank
<__main__.Point object at 0xb7e9d2ac>

返回值是一个Point对象的引用,我们将它赋值给blank

创建一个新对象的过程叫做实例化(instantiation),这个新对象叫做这个类的一个实例(instance)。

每一个对象都是某种类的实例,所以对象和实例可以互换。

属性

可以使用点标记向一个实例进行赋值操作:

>>> blank.x = 3.0
>>> blank.y = 4.0

这个语法类似于从一个模块中使用变量的语法,比如math.pistring.whitespace。这个例子中,我们是给一个类中已命名的元素赋值。这类元素叫做属性(attributes)。

说明一个对象及其属性的状态图叫做对象图(object diagram)。

变量blank引用了一个Point类,这个类拥有了两个属性。每个属性都引用了一个浮点数。

可以使用相同的语法读取一个属性的值:

>>> blank.y
4.0
>>> x = blank.x
>>> x
3.0

表达式blank.x的意思是,“前往blank所引用的对象并且获取x的值”。在这个例子中,我们将获取到的值赋值给了一个叫做x的变量。变量x和属性x并不会冲突。

你可以在任何表达式中使用点标记法。例如:

>>> '(%g, %g)' % (blank.x, blank.y)
'(3.0, 4.0)'
>>> distance = math.sqrt(blank.x**2 + blank.y**2)
>>> distance
5.0

你可以将一个实例作为参数传递。例如:

def print_point(p):
    print('(%g, %g)' % (p.x, py))

print_point接受一个点作为参数,打印出其在数学中的表示方法。调用它的时候,你可以将blank作为参数传递:

>>> print_point(blank)
(3.0, 4.0)

在这个函数内部,pblank的别名,所以函数修改了pblank也会随之改变。

矩形

  • 指定矩形的一个角(或中心)、宽度以及长度
class Rectangle:
    """Represents a rectangle.
    attributes:width, height, cornet.
    """

文档字符串中列出了属性:widthheight是数字;corner是一个Point对象,代表左下角的那个点。

为了描述一个矩形,需要实例化一个Rectangle对象,并且为它的属性赋值:

box = Rectangle(0
box.width = 100.0
box.height = 200.0
box.corner = Point()
box.corner.x = 0.0
box.corner.y = 0.0

表达式box.corner.x的意思是,“前往box所引用的对象,找到叫做corner的属性;然后前往corner所引用的对象,找到叫做x的属性。”

实例作为返回值

函数可以返回实例。例如find_center接受一个Rectangle作为参数,返回一个Point,代表了这个Rectangle的中心坐标:

def find_center(rect):
	p = Point()
	p.x = rect.corner.x + rect.width/2
	p.y = rect.corner.y + rect.height/2
	return p

下面这个例子将box作为参数传递,然后将返回的Point赋值给center

>>> center = find_center(box)
>>> print_point(center)
(50, 100)

对象是可变的

可以通过给一个对象的属性赋值来改变这个对象的状态。例如,要改变一个举行的大小而不改变它的位置,可以修改widthheight的值:

box.width = box.width + 50
box.height = box.height + 100

可以编写函数来修改对象,例如grow_rectangle接受一个Rectangle对象和两个数字,dwidthdheight,并将其加到举行的宽度和高度上:

def grow_rectangle(rect, dwidth, dheight):
	rect.width += dwidth
	rect.height += dheight

效果:

>>> box.width, box.height
(150.0, 300.0)
>>> grow_rectangle(box, 50, 100)
>>> box.width, box.height
(200.0, 400.0)

复制

别名会降低程序的可读性,因为一个地方的变动可能对另一个地方造成预料之外的影响。跟踪所有引用同一个对象的变量是非常困难的。

通常用复制对象的方法取代为对象起别名。copy模块拥有一个叫做copy的函数,可以复制任何对象:

>>> p1 = Point()
>>> p1.x = 3.0
>>> p1.y = 4.0

>>> import copy
>>> p2 = copy.copy(p1)

p1p2拥有相同的数据,但是它们并不是同一个Point对象。

>>> print_point(p1)
(3, 4)
>>> print_point(p2)
(3, 4)
>>> p1 is p2
False
>>> p1 == p2
False

is运算符显示了p1p2并非同一个对象。

如果使用copy.copy来复制一个Rectangle,你会发现它仅仅复制了Rectangle对象,但没有复制嵌套的Point对象。

>>> box2 = copy.copy(box)
>>> box2 is box
False
>>> box2.corner is box.corner
True

这个操作叫做浅复制(shallow copy),因为它仅复制了对象以及其包含的引用,但未复制嵌套的对象。

copy模块拥有一个叫做deepcopy的方法,它不仅可以复制一个对象,还可以复制这个对象所引用的对象,设置可以复制这个对象所引用的对象所引用的对象。这个操作叫做深复制(deep copy)。

>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False

box3box是完全互不相干的对象。

你可能感兴趣的:(Python基础知识)