1.作用域和命名空间
示例: 如何引用不同作用域和命名空间
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
输出:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
2.初识类
2.1.类定义语法
类定义最简单的形式:
class ClassName:
<statement-1>
.
.
.
<statement-N>
2.2.类对象
类对象支持两种操作: 属性引用和实例化
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
可以使用MyClass.i
和MyClass.f
返回一个整数和一个方法对象.
也可以对类属性赋值, MyClass.i = 123
.__doc__
也是一个有效的属性.
类的实例化使用函数符号, 创建一个新的类实例并赋值给局部变量x
:
x = MyClass()
构造方法:
def __init__(self):
self.data = []
如果类定义了__init__
方法的话, 类的实例化操作会自动为新的实例调用__init__()
方法
__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)
2.3.实例对象
数据属性相当于实例变量..
不需要声明, 第一次使用的时候就会生成.
x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2
print(x.counter)
del x.counter
方法是属于一个对象的函数.
2.4.方法对象
通常使用这种方式调用方法:
x.f()
x.f
是一个方法对象, 可以复制给一个局部变量:
xf = x.f
while True:
print(xf())
2.5.类和实例变量
实例变量对每一个实例来说, 都有自己唯一的数据.
class Dog:
kind = 'canine'
def __init__(self, name):
self.name = name
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind
'canine'
>>> e.kind
'canine'
>>> d.name
'Fido'
>>> e.name
'Buddy'
若类的属性为可变对象, 如列表和字典, 可能会带来意外的效果:
class Dog:
tricks = []
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over', 'play dead']
这个类设计时应该使用一个实例变量:
class Dog:
def __init__(self, name):
self.name = name
self.tricks = []
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
3.一些说明
数据属性会覆盖同名的方法属性…
所以为了避免这种情况, 有一些约定:
-
大写方法名称的首字母
-
使用一个唯一的小字符串座位数据属性名称的前缀
-
方法使用动词, 属性使用名称..
函数定义代码不一定非得定义在类中:
也可以将一个函数对象复制给类中的一个局部变量:
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g
通过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)
获取对象的类(class):
object.__class__
4.继承
继承示例:
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
基类在另一个模块中时:
class DerivedClassName(modname.BaseClassName):
两个用于继承的函数:
-
isinstance()
用于检查实例类型:isinstance(obj, int)
只有在obj.class
是 int 或其他从 int 继承的类型时返回 true. -
issubclass()
用于检查类继承:issubclass(bool, int)
为 true, 因为 bool 是 int 的子类.issubclass(float, int)
为 False, 因为 float 不是 int 的子类.
4.1.多继承
多继承的类定义示例:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
5.私有变量
python 不存在只能从内部访问的私有变量.
当以一个下划线开头的命名将会被处理为Api的非公开部分.
当以至少两个下划线开头命名(并且后面至多一个下划线), 例如: __spam
将被替换成_classname__spam
.
示例:
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
class MappingSubclass(Mapping):
def update(self, keys, values):
for item in zip(keys, values):
self.items_list.append(item)
6.补充
用一个空的类定义可以实现类似 C 中的结构(struct):
class Employee:
pass
john = Employee()
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
7.异常也是类
异常抛出形式:
raise Class
raise Instance
raise Class()
异常类继承示例:
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
将按顺序打印 B, C, D.
若将异常子句的顺序颠倒过来, 将打印 B, B, B.
8.迭代器
大多数容器对象都可以用 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, end='')
for 遍历的工作原理:
>>> 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
给自己的类添加迭代器行为:
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
9.生成器
使用 Generator 来创建迭代器:
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
生成器将自动创建__iter__()
和__next__()
方法, 显得比较简洁.
10.生成器表达式
示例:
>>> sum(i*i for i in range(10))
285
>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec))
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']
网友评论