面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。
面向对象的程序设计把计算机程序视为一组对象的集合,每个对象可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
# 面向过程 <<< std1 = {'name': 'Michael', 'score': 98} <<< std2 = {'name': 'Bob', 'score': 81} <<< def print_score(std): print('%s: %s' % (std['name'], std['score'])) # 面向对象 class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_socre(self): print('%s %s' % (self.name, self.score)) <<< bart = Student('Bart Simpson', 59) <<< lisa = Student('Lisa Simpson', 87) <<< bart.print_score() <<< bart.print_score()判断对象类型,使用type()函数,可判断基本类型、函数、类,type()函数返回对应的Class类型。
判断一个对象是否是函数。
<<< import types <<< def fn(): pass <<< type(fn) == types.FunctionType True <<< type(abs) == types.BuiltinFunctionType True <<< type(lambda x: x) == types.LambdaType True <<< type((x fir x in range(10))) == types.GeneratorType判断class的类型,可以使用isinstance()函数。
# 继承关系是 object -> Animal -> Dog -> Husky <<< a = Animal() <<< d = Dog() <<< h = Husky() <<< isinstance(h, Husky) <<< isinstance(h, Dog) <<< isinstance(h, Animal) True <<< isinstance(d, Husky) False <<< isinstance([1, 2, 3], (list, tuple)) Truedir()函数,获得一个对象的所有属性和方法,它返回一个包含字符串的list。
getattr()、setattr()、hasattr(),直接操作一个对象的状态。
给实例绑定属性和方法,给类绑定实例和方法。
class Student(object): pass <<< s = Student() <<< s.name = 'Michael' # 动态给实例绑定一个属性 <<< print(s.name) Michael # 给实例绑定一个方法 <<< def set_age(self, age): # 定义一个函数作为实例方法 self.age = age <<< from types import MethodType <<< s.set_age = MethodType(set_age, s) # 给实例绑定一个方法 <<< s.set_age(25) 25 <<< s2 = Student() # 创建新的实例 <<< s2.age(25) # 尝试调用方法 AttributeError:…… # 给class绑定方法 <<< def set_score(self, score) self.score = score <<< Student.set_score = set_score <<< s.set_score(100) <<< s.score 100 <<< s2.set_score(99) <<< s2.score 99使用__slots__限制实例的属性,__slots__定义的属性仅对当前类起作用,对继承的子类不起作用。除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。
class Student(object): __slots__ = ('name', 'age') <<< s = Student() # 创建新的实例 <<< s.name = 'Michael' # 绑定属性'name' <<< s.age = 25 # 绑定属性'age' <<< s.score = 99 # 绑定属性'score' AttributeError:……@property,只定义getter方法,不定义setter方法就是一个只读属性。
@property def score(self): return self._score @score.setter def score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0~100!') self._score = value @property def birth(self): return self._birth @birth.setter def birth(self, value): self._birth = value @property def age(self): return 2015 - self._birth <<< s = Student() <<< s.score = 60 # OK, 实际转化为s.set_score(60) <<< s.score # OK, 实际转化为s.get_score__str__,__str__返回用户看到的字符串,__repr__返回程序开发者看到的字符串。
class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object(name = %s)' % self.name __repr__ = __srt____iter__,使一个类可以被作用于for ... in循环返回一个迭代对象,Python的for循环会不断调用该迭代对象的__next__方法拿到循环的下一个值。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器 def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def __next__(self): self.a self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000 # 退出循环的条件 raise StopIteration() return self.a # 返回下一个值 for n in Fib(): print(n)__getitem,使一个类可以像list那样按照下标取出元素。__setitem、__delitem__。
class Fib(object): def __getitem__(self, n): a, b = 1, 1 for x in range(n): a, b = b, a+b return a <<< f = Fib() <<< f[0] 1 # 切片 class Fib(object): def __getitem__(self, n): if isinstance(n, int): # n是索引 a, b =1, 1 for x in range(n): a, b = b, a+b return a if isinstance(n, slice): # n是切片 start = n.start stop = n.stop if start is None: start = 0 a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a+b return L <<< f = Fib() <<< f[0:5] [1, 1, 2, 3, 5]__getattr__,动态获取属性和方法。在没有找到属性的情况下,才调用__getattr__。任意调用s.abc都会返回None,因为我们定义的__getattr__默认返回就是None。要让class只响应特定的几个属性,我们要按照约定,抛出AttributeError的错误。
class Student(object): def __init__(self): self.name = 'Michael' def __getattr(self, attr): if attr == 'score': return 99 if attr == 'age': return lambda: 25 raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr) <<< s = Student() <<< s.name 'Michael' <<< s.score 99 <<< s.age() 25__call__,实现调用实例方法直接在实例本身上调用。_call_也可以定义参数,对实例调用好比对一个函数调用,可以把对象看成函数,把函数看成对象。因为类的实例是运行期创建出来的,如果你把对象看成函数,那么函数本身也可以在运行期动态创建出来。判断一个对象是否能被调用,能被调用的对象就是一个callable对象。
class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name) <<< s = Student('Michael') <<< s() My name is Michael. <<< callable(Student()) True <<< callabke(max) True <<< callable([1, 2, 3]) False <<< callable(None) False <<< callable('str') FalseEnum
<<< from enum import Enum <<< Week = Enum('Week',('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')) <<< from name, member in Week.__members__.items(): print(name, '=>', member, ',', member.value) from enum import Enum, unique @unique # @unique装饰器帮助检查没有重复值 class Weekday(Enum): Sun = 0 Mon = 1 Tue = 2 Wed = 3 Thu = 4 Fri = 5 Sat = 6 <<< day1 = Weekday <<< print(day1) Weekday.Monday <<< print(Weekday.Tue) Weekday.Tue <<< print(Weekday['Tue']) Weekday.Tue <<< print(Weekday.Tue.value) 2 <<< print(day1 == Weekday.Mon) True <<< print(day1 == Weekday.Tue) False <<< print(Weekday(1)) Weekday.Mon <<< print(day1 == Weekday(1)) True <<< Weekday(7) ValueError <<< for name, member inWeekday.__members__.items(): print(name, '=>' member) Sun => Weekday.Sun Mon => Weekday.Mon Tue => Weekday.Tue Wed => Weekday.Wed Thu => Weekday.Thu Fri => Weekday.Fri Sat => Weekday.Sattype()
# hello.py class Hello(object): def hello(self, name='world'): print('Hello, %s.' % name) <<< form helllo import Hello <<< h = Hello() <<< h.hello() Hello, world. <<< print(type(Hello)) <class 'type'> <<< print(type(h)) <class 'hello.Hello'> # type()函数创建新的类型 <<< def fn(self, name='world'): print('Hello, %s.' % name)