面向对象编程

对象(object):表示客观世界问题空间中的某个具体事物,又表示软件系统解空间的中的基本元素
面向对象程序设计(Object-oriented programing, OP):是一种程序设计范型,也是一种程序开发的方法。

1、类

类(clas)是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法

1.理解创建类的基本方法

2.初步理解对象和面向对象

python面向接口编程 python面向对象的编程_python面向接口编程

class SuperMan:
    '''
    A class of superman
    '''

    def __init__(self,name):
        self.name = name
        self.gender = 1
        self.single = False
        self.illness = False

    def nine_negative_kungfu(self):
        return "Ya!You have to die."

guojing = SuperMan('guojing')
print(guojing.name)
print(guojing.gender)
kongfu = guojing.nine_negative_kungfu()
print(kongfu)
'''
编写一个程序,用于判断学生是否已经完成作业。如果完成,教
师会给出表扬,否则要进行批评。
'''

class Student:
    def __init__(self, name, grade, subject):
        self.name = name
        self.grade = grade
        self.subject = subject
    def do_work(self, time):
        if self.grade > 3 and time > 2:
            return True
        elif self.grade < 3 and time > 0.5:
            return True
        else:
            return False

class Teacher:
    def __init__(self, name, subject):
        self.name = name
        self.subject = subject
    def evaluate(self, result=True):
        if result:
            return "You are great."
        else:
            return "You should work hard"

stu_zhang = Student('zhang', 5, 'math')   
tea_wang = Teacher('wang', 'math')    
teacher_said = tea_wang.evaluate(stu_zhang.do_work(1))    
print("Teacher {0} said: {1}, {2}".format(tea_wang.name, stu_zhang.name, teacher_said))

stu_newton = Student('Newton', 6, 'physics')
teacher_newton = tea_wang.evaluate(stu_newton.do_work(4))
print("Teacher {0} said: {1}, {2}".format(tea_wang.name, stu_newton.name, teacher_newton))

1.1、属性

属性:描述对象是什么

• 类属性

又称静态属性

只有通过类才能修改

实例也拥有类属性,但不能修改类属性

>>> class Foo:
	lang = 'python'

>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'lang']
>>> Foo.lang
'python'
>>> f = Foo()
>>> type(f)
<class '__main__.Foo'>
>>> dir(f)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'lang']
>>> f.lang
'python'
>>> Foo.group = 'winner classroom'
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang']
>>> dir(f)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang']
>>> f.name = 'winner'
>>> dir(f)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang', 'name']
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang']
• 实例属性

实例属性,又称动态属性

通过实例创建

不同实例的实例属性不同

实例的__dict__显示当前实例的所有属性

>>> class Bar:
	def __init__(self,name):
		self.name = name

>>> b = Bar('winner')
>>> c = Bar('xiaochun')
>>> b.name
'winner'
>>> c.name
'xiaochun'python
>>> b.__dict__
{'name': 'winner'}
>>> class Foo:
	lang = 'python'
	def __init__(self,name):
		self.name = name

>>> f = Foo('winner')
>>> dir(f)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'lang', 'name']
>>> f.__dict__
{'name': 'winner'}
>>> f.lang  #lang是类属性,而不是实例属性,不能在__dict__中列出,但是它可以被实例访问
'python'
• self的作用

类中的方法,如无特别规定,都是以self作为第一参数

self引用当前实例

>>> class Bar:
	def __init__(self):
		print(self)
		
>>> b = Bar()
<__main__.Bar object at 0x00000181FD3E1580>
>>> b
<__main__.Bar object at 0x00000181FD3E1580>
>>>
'''
创建类,能够计算任意两个日期之间的天数、周数。
'''
import datetime
from dateutil import rrule

class BetDate:
    def __init__(self, start_date, stop_date):
        self.start = datetime.datetime.strptime(start_date, "%Y, %m, %d")    
        self.stop = datetime.datetime.strptime(stop_date, "%Y, %m, %d")

    def days(self):
        d = self.stop - self.start
        return d.days if d.days > 0 else False 
    
    def weeks(self):
        weeks = rrule.rrule(rrule.WEEKLY, dtstart=self.start, until=self.stop)
        return weeks.count()    

fir_twe = BetDate("2019, 5, 1", "2019, 11, 25") 
d = fir_twe.days()
w = fir_twe.weeks()
print("Between 2019-5-1, 2019-11-25:")
print("Days is:", d)
print("Weeks is:", w)

1.2、方法

方法:描述对象能做什么

• 比较方法和函数

名称的命名、代码块的编写方式都一样

(实例)方法不能单独调用,只能通过实例/类调用,而函数可以单独使用

方法的第一个参数必须是self

>>> class Foo:
	def method(self,x):
		return x * 2

	
>>> f = Foo()
>>> f.method(2)
4
>>> Foo.method(2)
Traceback (most recent call last):
  File "<pyshell#320>", line 1, in <module>
    Foo.method(2)
TypeError: method() missing 1 required positional argument: 'x'
>>> Foo.method(f,2)
4
>>> f.method  #类是对象,方法也是对象
<bound method Foo.method of <__main__.Foo object at 0x00000181FD3E1820>>
• 类方法

使用装饰器:@classmethod装饰符

类方法的第一个参数:cls,表示类本身,和写成什么没关系,习惯于使用cls

>>> class Bar:
	@classmethod
	def method(cls,x):
		print(cls)
		
>>> b = Bar()
>>> b.method(2)
<class '__main__.Bar'>
>>> Bar
<class '__main__.Bar'>
• 静态方法

使用装饰器:@staticmethod装饰符

静态方法不与实例绑定

>>> class Bar2:
	@staticmethod
	def add():
		return 'add'

>>> b2 = Bar2()
>>> b2.add()
'add'
>>> Bar2.add()
'add'
>>> add()
Traceback (most recent call last):
  File "<pyshell#343>", line 1, in <module>
    add()
TypeError: add() missing 2 required positional arguments: 'x' and 'y'

练习

'''
创建类,能够通过“年-月-日”字符串创建实例,并检验年、月、日是否合法
'''

class Date(object):
    def __init__(self,year=0,month=0,day=0):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def from_string(cls,date_as_string):
        year,month,day = map(int,date_as_string.split('-'))
        datel = cls(year,month,day)
        return datel

    @staticmethod
    def is_date_valid(date_as_string):
        year, month, day = map(int, date_as_string.split('-'))
        return day <= 31 and month<=12 and year <= 2038

d = Date.from_string('2019-11-11')
is_date = Date.is_date_valid('2019-11-11')
print(is_date)

2、继承

继承是对象的特性之一

继承是面向对象编程的一个重要概念

• 父类和子类

对父类方法的重写:如果在子类中写了一个与父类同名的方法,会覆盖父类中的方法

>>> class P:
	def __init__(self,name):
		self.name = name
	def eat(self):
		return "fish"

>>> class C(P):
	pass

>>> c = C()
Traceback (most recent call last):
  File "<pyshell#356>", line 1, in <module>
    c = C()
TypeError: __init__() missing 1 required positional argument: 'name'
>>> c = C('google')
>>> dir(c)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eat', 'name']
>>> class D(P):pass

>>> dir(D)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eat']
>>> class E(P):
	def __init__(self,age):
		self.age = age

		
>>> e = E('winner',18)
Traceback (most recent call last):
  File "<pyshell#367>", line 1, in <module>
    e = E('winner',18)
TypeError: __init__() takes 2 positional arguments but 3 were given
>>> e = E('winner')
>>> dir(e)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'eat']
>>> e.age
'winner'
>>> e.name
Traceback (most recent call last):
  File "<pyshell#371>", line 1, in <module>
    e.name
AttributeError: 'E' object has no attribute 'name'

在单继承中,如果遇到子类覆盖了父类中的同名方法,又想在子类中使用父类的方法,子类中调用父类中的方法

>>> class E(P):
	def __init__(self,name,age):
		self.age = age
		P.__init__(self,name)	
>>> e = E('winner',18)
>>> e.age
18
>>> e.name
'winner'

>>> class E(P):
	def __init__(self,name,age):
		self.age = age
		super().__init__(name)
		
>>> e = E('winner',18)
>>> e.age
18
>>> e.name
'winner'
• 单继承
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def get_name(self):
        return self.name

    def get_age(self):
        return self.age

class Student(Person):
    def __init__(self,school,name,age):
        self.school = school
        super().__init__(name,age)
    def grade(self,n):
        print("{0}'s grade is {1}".format(self.name,str(n)))

stu1 = Student('Soochow','winner','18')
stu1.grade(99)
print(stu1.get_name())
print(stu1.get_age())
• 多继承
class K1:
    def foo(self):
        print("K1-foo")

class K2:
    def foo(self):
        print("K2-foo")
    def bar(self):
        print("K2-bar")

class J1(K1,K2):
    pass

class J2(K1,K2):
    def bar(self):
        print("J2-bar")

class C(J1,J2):
    pass

print(C.__mro__)
m = C()
m.foo()
m.bar()

运行结果
(<class '__main__.C'>, <class '__main__.J1'>, <class '__main__.J2'>, <class '__main__.K1'>, <class '__main__.K2'>, <class 'object'>)
K1-foo
J2-bar
'''
请编写“物理学家”的类,并将其作为“理论物理学家”
和“实验物理学家”两个类的父类
'''

class Physicist:
    def __init__(self,name,iq=120,looks='handsom',subject='physics'):
        self.name = name
        self.iq = iq
        self.looks = looks
        self.subject = subject

    def research(self,field):
        print("{0} research {1}".format(self.name,field))

    def speak(self):
        print("My name is",self.name)
        print("I am",self.looks)
        print("Intelligence is",self.iq)
        print("I like",self.subject)

class ExperimentalPhysicist(Physicist):
    def __init__(self,main_study,name,iq=120,looks='handsom',subject='physics'):
        self.main_study = main_study
        super().__init__(name,iq,looks,subject)

    def experiment(self):
        print("{0} is in Physics Lab".format(self.name))

class TheoreticalPhysicist(Physicist):
    def __init__(self,theory,name,iq=120,looks='handsom',subject='physics'):
        self.theory = theory
        super().__init__(name,iq,looks,subject)

    def research(self,field,base):
        super().research(field)
        print("My theory is {0}, it is based on {1}".format(self.theory,base))

3、多态

  • 多态是对象的特性之一
  • Python语言天然具有多态性
>>> def add(x,y):
	return x + y

>>> add(3,4)
7
>>> add('winner','python')
'winnerpython'

4、封装

  • 封装是对象的特性之一
  • Python中通过私有化的方式实现封装,在对象前面加上两个下划线__
>>> class Foo:
	__name = 'winner'
	book = 'python'
	
>>> Foo.book
'python'
>>> Foo.__name
Traceback (most recent call last):
  File "<pyshell#407>", line 1, in <module>
    Foo.__name
AttributeError: type object 'Foo' has no attribute '__name'
>>> Foo.name
Traceback (most recent call last):
  File "<pyshell#408>", line 1, in <module>
    Foo.name
AttributeError: type object 'Foo' has no attribute 'name'
>>> f = Foo()
>>> f.book
'python'
>>> f.name
Traceback (most recent call last):
  File "<pyshell#411>", line 1, in <module>
    f.name
AttributeError: 'Foo' object has no attribute 'name'
>>> f.__name
Traceback (most recent call last):
  File "<pyshell#412>", line 1, in <module>
    f.__name
AttributeError: 'Foo' object has no attribute '__name'

被封装的对象只能在该类中被调用

>>> class Foo:
	def __init__(self):
		self.name = 'winner'
		self.__group = 'winner classroom'
	def code(self):
		return self.__group
	def __author(self):
		return self.name
	
>>> f = Foo()
>>> f.code()
'winner classroom'
>>> f.__group
Traceback (most recent call last):
  File "<pyshell#426>", line 1, in <module>
    f.__group
AttributeError: 'Foo' object has no attribute '__group'
>>> f.__author()
Traceback (most recent call last):
  File "<pyshell#427>", line 1, in <module>
    f.__author()
AttributeError: 'Foo' object has no attribute '__author'

5、定制类

  1. 理解类和类型
  2. 掌握自定义对象类型的方法
class RoundFloat:
    def __init__(self, val):
        self.value = round(val, 2)
    
    def __str__(self):    # str:用户友好;repr: 解释器友好
        return "{0:.2f}".format(self.value)
    
    __repr__ = __str__

r = RoundFloat(3.1415926)
print(r)
print(type(r))
>>> class Foo:
	def __repr__(self):
		return "I am in repr"
	def __str__(self):
		return "I am in str"

	
>>> f = Foo()
>>> s
['one', 'two', 'three', 'four']
>>> f
I am in repr
>>> print(f)
I am in str
>>>
class Fraction:
    def __init__(self, number, denom=1):
        self.number = number
        self.denom = denom

    def __str__(self):
        return str(self.number) + "/" + str(self.denom)

    __repr__ = __str__

f = Fraction(2, 3)
print(f)
>>> from fractions import Fraction  #分数
>>> m,n = Fraction(1,6),Fraction(3,6)
>>> m
Fraction(1, 6)
>>> n
Fraction(1, 2)
>>> m+n
Fraction(2, 3)

6、控制属性访问

6.1优化内存:slots

>>> a = Foo()
>>> a.__dict__
{}
>>> a.age = 25
>>> a.__dict__
{'age': 25}
>>> a.year = 28
>>> a.__dict__
{'age': 25, 'year': 28}

对类的属性进行控制,不允许随便增减,只允许指定属性,而且不允许修改(只读)

>>> class Bar:
	__slots__ = ('name','age')

>>> Bar.name='winner'
>>> Bar.age=28
>>> b=Bar()
>>> b.name
'winner'
>>> b.age
28
>>> b.city = "soochow"
Traceback (most recent call last):
  File "<pyshell#476>", line 1, in <module>
    b.city = "soochow"
AttributeError: 'Bar' object has no attribute 'city'
>>> b.age = 38
Traceback (most recent call last):
  File "<pyshell#477>", line 1, in <module>
    b.age = 38
AttributeError: 'Bar' object attribute 'age' is read-only

6.2掌握与属性相关的特殊方法__getattr__和__setattr__

访问类中不存在的属性时

>>> class A:
	def __getattr__(self,name):
		print("you use getattr")
	def __setattr__(self,name,value):
		print("you use setattr")
		self.__dict__[name] = value
		
>>> a = A()
>>> a.x
you use getattr
>>> a.x = "haha"
you use setattr
>>> a.x
'haha'

7、迭代器和生成器

判断一个对象是否时可迭代对象

>>> hasattr(list,"__iter__")
True

7.1、迭代器

列表时可迭代的(非迭代器对象),但__next__是迭代器对象特有的

>>> hasattr(iter_lst,"__next__")
True
>>> hasattr(list,"__next__")
False

将迭代器中的元素读到内存中

>>> lst = [1,2,3,4]
>>> iter_lst = iter(lst)
>>> iter_lst
<list_iterator object at 0x00000181FD3F7790>
>>> lst
[1, 2, 3, 4]
>>> hasattr(iter_list,"__iter__")
Traceback (most recent call last):
  File "<pyshell#501>", line 1, in <module>
    hasattr(iter_list,"__iter__")
NameError: name 'iter_list' is not defined
>>> hasattr(iter_lst,"__iter__")
True
>>> hasattr(iter_lst,"__next__")
True

>>> iter_lst.__next__()
1
>>> iter_lst.__next__()
2
>>> iter_lst.__next__()
3
>>> iter_lst.__next__()
4
>>> iter_lst.__next__()
Traceback (most recent call last):
  File "<pyshell#509>", line 1, in <module>
    iter_lst.__next__()
StopIteration

>>> for i in iter_lst:
	print(i)
	
>>> iter_lst =iter(lst)
>>> for i in iter_lst:print(i)
1
2
3
4
class MyRange:
    def __init__(self, n):
        self.i = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.i <= self.n:
            i = self.i
            self.i += 1
            return i
        else:
            raise StopIteration()

print("range(7):", list(range(7)))
print("MyRange(7):", [i for i in MyRange(7)])
class Fibs:
    def __init__(self, max):
        self.max = max
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

fibs = Fibs(1000000)
lst = [fibs.__next__() for i in range(10)]
print(lst)
>>> import itertools
>>> counter = itertools.count(start=7)
>>> next(counter)
7
>>> next(counter)
8
>>> next(counter)
9

7.2、生成器

>>> def g():
	yield 0
	yield 1
	yield 2
	
>>> ge = g()
>>> ge
<generator object g at 0x00000181FD3EDCF0>
>>> type(ge)
<class 'generator'>
>>> dir(ge)
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
>>>

yield和return

执行到yield时,函数被挂起,等待下一次执行next

执行到return时,函数终止

>>> def r_return(n):
	print("start")
	while n > 0:
		print("before return")
		return n
		n -= 1
		print('after return')	
>>> rre = r_return(3)
start
before return
>>> print(rre)
3

>>> def y_yield(n):
	print("start")
	while n > 0:
		print("before yield")
		yield n
		n -= 1
		print('after yield')		
>>> yy = y_yield(3)
>>> yy.__next__()
start
before yield
3
>>> yy.__next__()
after yield
before yield
2
>>> yy.__next__()
after yield
before yield
1
>>> yy.__next__()
after yield
Traceback (most recent call last):
  File "<pyshell#561>", line 1, in <module>
    yy.__next__()
StopIteration
def fibs():
    prev, curr = 0, 1
    while True:
        yield prev
        prev, curr = curr, prev + curr

import itertools
print(list(itertools.islice(fibs(), 10)))

生成器解析

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> gt = (x**2 for x in range(10))
>>> gt
<generator object <genexpr> at 0x00000181FD3EDE40>
>>> gt.__next__()
0
>>> gt.__next__()
1
>>> gt.__next__()
4
>>> gt.__next__()
9