pythdon day 10

2019/10/13

学习资料来自老男孩与尚学堂

目录

1. 反射补充

反射模拟网络浏览器登录

  1. # 初级版
  2. '''
  3. from lib import account
  4. url = input('please input the website address:>>> ')
  5. if url.endswith('login'):
  6. r = account.login()
  7. print(r)
  8. elif url.endswith('logout'):
  9. r = account.logout()
  10. print(r)
  11. else:
  12. print('404')
  13. '''
  14. # 中级版
  15. '''
  16. url = input('please input the website address:>>> ')
  17. inp = url.split('/')[1] # ['www.baidu.com','login'][1] == 'login'
  18. if hasattr(account, inp): # 判断某个模块中是否有指定对象
  19. target_func = getattr(account, inp, None) # 找到模块中的指定对象
  20. r = target_func()
  21. print(r)
  22. else:
  23. print('404')
  24. '''
  25. # 高级版
  26. # from lib import account as lat # 从lib包里面导入account模块
  27. # print(lat.__name__)
  28. # m = __import__('lib.account', fromlist=True) # 本质上是调用了__import__方法
  29. # print(m.__name__)
  30. inp = input('module/function: ').strip()
  31. module_name, func_name = inp.split('/') # 将列表中的索引值为0与1分别赋值给前面的两个变量
  32. m = __import__('lib.'+module_name, fromlist=True) # 因为__import__接收字符串作为参数,
  33. if hasattr(m, func_name):
  34. target_func = getattr(m, func_name)
  35. r = target_func()
  36. print(r)
  37. else:
  38. print('404')

16. 面向对象

16.1 面向对象初步介绍

面对对象(object oriented programming,OOP)编程的思想主要是针对大型软件设计而来的。面向对象编程命名程序的扩展性更强/可读性更好,使得编程可以像搭积木一样简单。

面向对象编程将数据和操作数据相关的方法封装到对象中,组织代码和数据的方式更加接近人的思维,从而大大提高了编程的效率。

python完全采用了面向对象的思想,是真正面向对象的编程语言,完全支持面向对象的基本功能,例如:继承/多态/封装等。

python中,一切对象。前面学习的数据类型,函数等,都是对象。

python支持面向过程/面向对象/函数式编程等多种编程范式

16.2 面向对象和面向过程区别

  • 面向过程(procedure oriented)思维

    面向过程编程更加关注的是程序的逻辑流程,是一种“执行者”思维,适合编写小规模的程序。

    面向过程思想思考问题时,我们首先思考“怎么按步骤实现?”,并将步骤对应成方法,一步一步,最终完成。这个适合简单任务,不需要过多协作的情况下。

  • 面向对象(object oriented)思维

    面向对象更加关注的是“软件中对象之间的关系”,是一种“设计者”思维,适合编写大规模的程序。(

    面向对象思想更契合人的思维模式。我们首先思考的是“怎么设计这个事物?” 。比如,思考造车,就会先思考,“车怎么设计?”,而不是“怎么按步骤造车的问题”。这就是思维方式的转变。

    面向对象方式思考造车,发现车由如下对象组成

    1. 轮胎
    2. 发动机
    3. 车壳
    4. 座椅
    5. 挡风玻璃

      为了便于协作,我们找轮胎厂完成制造轮胎的步骤,发动机厂完成制造发动机的步骤,这样,发现大家可以同时进行车的制造,最终进行组装,大大提高了效率。但是,具体到轮胎厂的一个流水线操作,仍然是有步骤的,不是离不开面向过程思想。

      因此,面向对象可以帮助我们从宏观上把握/从整体上分析整个系统。但是,具体到实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理

      面向对象和面向过程是相辅相成的,面向对象离不开面向过程。
  • 面向对象思考方式

    遇到复杂问题,先从问题中找名词(面向过程更多的是找动词),然后确立这些名词哪些可以作为类,再根据问题需求确定类的属性和方法,确定类之间的关系。

  • 面向对象和面向过程的总结:

  • [x] 都是解决问题的思维方式,都是代码组织的方式。

  • [x] 解决简单问题可以使用面向过程。

  • [x] 解决复杂问题:宏观上使用面向对象把握,微观处理上仍然是面向过程。

16.3 对象的进化

随着编程面临的问题越来越复杂,编程语言本身也在进化,从主要处理简单数据开始,随着数据变多进化“数组”;数据类型变复杂,进化出了“结构体”;处理数据的方式和逻辑变复杂,进化出了“对象”。

  1. 简单数据:像30,40,50.2等这些数字,就是简单的数据。最初的计算机编程,都是像这样的数字。
  2. 数组:将同类型的数据放到一起。比如,整数数组[20,30,40],字符串数组['aa','bb','cc']等
  3. 结构体:将不同类型的数据放到一起,是C语言中的数据结构。比如:struct resume{int age;char name[10],double salary;};
  4. 对象:将不同类型的数据/方法(即函数)放到一起,就是对象。比如:
  1. class Student:#旧式类写法
  2. company = 'SXT' #类属性
  3. conut = 0 #类属性
  4. def __init__(self,name,score):
  5. self.name = name #实例属性
  6. self.score = score
  7. Student.count = Student.count + 1
  8. def say_score(self): #实例方法
  9. print('我的公司是:', Student.company)
  10. print(self.name,'我的分数是:',self.score)

17. 类class

17.1 类的定义

可以将对象比作一个“饼干”,类就是制造这个饼干的“模具”。

通过类定义数据类型的属性(数据)和方法(行为),也就是说,“类将行为和状态打包在一起”。

对象是类的具体实体,一般称为“类的实例”。类看做饼干模具,对象就是根据这个模具制造出的饼干。

从一个类创建对象时,每个对象都会共享这个类的行为(即类中定义的方法),但会有自己的属性值(不共享状态)。更具体一点:“方法代码是共享的,属性数据不共享”

python中,一切皆对象。类也称为"类对象",类的实例也称为“实例对象”。

定义类的语法格式如下:

  1. class 类名:
  2. 类体

要点如下:

  1. 类名必须符合"标识符"的规则;一般规定,首字母大字,多个单词使用“驼峰原则”,即每个单词首字母大写。
  2. 类体中可以定性属性和方法。
  3. 属性用来描述数据,方法(即函数)用来描述这些数据相关的操作。
  1. # 一个典型的类的定义
  2. class Student(object):#新式类写法
  3. def __init__(self,name,score):#__init__是构造函数
  4. self.name = name #实例属性
  5. self.score = score
  6. def say_score(self): #实例方法
  7. print(self.name,'我的分数是:',self.score)
  8. s1 = Student('张三',80)
  9. #s1是实例对象,实际是Student.__init__(s1,'张三',80)
  10. s1.say_score() #实际是Student.say_score(s1)

17.2 __init__构造方法和__new__方法

类是抽象的,也称为为“对象的模板”。我们需要通过类这个模板,创建类的实例对象,然后才能使用类定义的功能。

一个python对象包含三个部分:id(identity识别码)/type(对象类型)/value(对象的值)

现在,可以更进一步的说,一个python对象包含如下部分:

1. id(identity识别码)

2. type(对象类型)

3. value(对象的值)

(1) 属性(attribute)

(2) 方法(method)

创建对象,我们需要定义构造函数__init__()方法。构造方法用于执行"实例对象的初始化工作",即对象创建后,初始化当前对象的相关属性,无返回值。

init()的要点如下:

  1. 名称固定,必须为:init():
  2. 第一个参数固定,必须为self.self指的就是刚刚创建好的实例对象。
  3. 构造函数通常用来初始化实例对象的实例属性。
  4. 通过“类名(参数列表)”来调用构造函数。调用后,将创建后的对象返回给相应的变量。比如:s1 = Student('张三',80)
  5. init()方法:初始化创建好的对象,初始化指的是:给实例属性赋值
  6. new()方法:用于创建对象,但我们一般无需重定义该方法。
  7. 如果我们不定义__init__()方法,系统会提供一个默认的__init__方法。如果我们定义了带参的__init__方法,系统不创建默认的__init__方法。

注:

1. python中的self相当于C++中的self指针,JAVA和C#中的this关键字。python中,self必须为构造函数的第一个参数,名字可以任意修改。但一般遵守惯例,都叫做self。

17.3 实例属性和实例方法

17.3.1 实例属性(实例变量)

实例属性是从属于实例对象的属性,也称为“实例变量”。他的使用有如下几个要点:

  1. 实例属性一般在__init__()方法中通过如下代码定义:

    self.实例属性名 = 初始值
  2. 在本类的其他实例方法中,也是通过self 进行访问:

    self.实例属性名
  3. 创建实例对象后,通过实例对象访问:

    obj01 = 类名() #创建对象,调用__init__()初始化属性

    obj01.实例属性名 = 值 #可以给已有属性赋值,也可以新加属性

17.3.2 实例方法

实例方法是从属于实例对象的方法。实例方法的定义格式如下:

def 方法名(self [, 形参列表]):

函数体

方法的调用格式如下:

对象.方法名([实参列表])

要点:

  1. 定义实例方法时,第一个参数必须为self。和前面一样,self 指当前的实例对象。 2. 调用实例方法时,不需要也不能给self 传参。self 由解释器自动传参。
  • 函数和方法的区别
  1. 都是用来完成一个功能的语句块,本质一样。
  2. 方法调用时,通过对象来调用。方法从属于特定实例对象,普通函数没有这个特点。
  3. 直观上看,方法定义时需要传递self,函数不需要。
  1. class Student(object):#类名一般首字母大写,多个单词每个单词首字母大写
  2. '''定义类的测试'''
  3. def __init__(self,name,score):#构造函数的第一个参数必须是self
  4. self.name = name
  5. self.score = score
  6. def say_score(self):#对象的方法,第一个参数也必须是self
  7. print('{0}的分数是{1}'.format(self.name,self.score))
  8. s1 = Student('小蓝',90) ## Student.__init(s1,'小蓝',90)
  9. s1.say_score() ## Student.say_score(s1)
  10. s1.age = 28
  11. s1.salary = 3800
  12. print(s1.salary)
  13. print(s1.say_score)
  14. s2 = Student('小张',20) #s2并不会有salary,age属性。
  15. print(dir(s1)) #获得对象的的所有属性和方法
  16. print(s1.__dict__) #对象的属性,将属性以字典形式返回
  17. print(isinstance(s1,list)) #判断“对象”是不是“指定类型”
  18. 小蓝的分数是90
  19. 3800
  20. <bound method Student.say_score of <__main__.Student object at 0x000001CBEBADF9B0>>
  21. ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
  22. '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__re
  23. duce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'ag
  24. e', 'name', 'salary', 'say_score', 'score']
  25. {'name': '小蓝', 'score': 90, 'age': 28, 'salary': 3800}
  26. False

17.4 类对象/类属性/类方法/静态方法

17.4.1 类对象

当解释器执行class语句时,就会创建一个类对象。

  1. class Student(object):
  2. '''测试类之二'''
  3. pass #空语句,占位符
  4. print(type(Student),'\r\n*******\r\n',id(Student))
  5. Stu2 = Student #实际就是生成了一个变量名就是类名“Student”的对象。也可以赋值给新变量Stu2.
  6. s1 = Stu2()
  7. print(s1)

17.4.2 类属性(类变量)

类属性是从属于"类对象"的属性,也称为"类变量"。由于类属性从属于类对象,可以被所有实例对象共享。

类属性的定义方式:

class 类名:

类变量名 = 初始值

在类中或者类的外面,我们可以通过:"类名.类变量名"来读写

  1. class Student(object):
  2. '''类属性的使用测试'''
  3. company = 'SXT' #类属性
  4. count = 0 #类属性
  5. def __init__(self,name,score):
  6. self.name = name #实例属性
  7. self.score = score
  8. Student.count += 1
  9. def say_score(self): #实例方法
  10. print('我的公司是:',Student.company)
  11. print(self.name,'的分数是:',self.score)
  12. s1 = Student('张三',80) #s1是实例对象,自动调用__init__() 方法
  13. s1.say_score()
  14. print('一共创建{0}个Student对象'.format(Student.count))

17.4.3 类方法

类方法是从属于"类对象"的方法。类方法通过装饰器@classmethod来定义,格式如下:

@classmethod

def 类方法名(cls [,开参列表]):

函数体

要点如下:

  1. @classmethod必须位于方法上面一行。
  2. 第一个cls必须有;cls指的就是"类对象"本身。
  3. 调用类方法格式:"类名.类方法名(参数列表)"。参数列表中,不需要也不能给cls传递值。
  4. 类方法中访问实例属性和实例方法导致错误。
  5. 子类继承父类方法时,传入cls是子类对象,而非父类对象
  1. class Student(object):
  2. '''类属性/类方法的使用测试'''
  3. company = 'SXT' #类属性
  4. count = 0 #类属性
  5. @classmethod
  6. def printCompany(cls):
  7. print(cls.company)
  8. def __init__(self,name,score):
  9. self.name = name #实例属性
  10. self.score = score
  11. Student.count += 1
  12. def say_score(self): #实例方法
  13. print('我的公司是:',Student.company)
  14. print(self.name,'的分数是:',self.score)
  15. # s1 = Student('张三',80) #s1是实例对象,自动调用__init__() 方法
  16. # s1.say_score()
  17. # print('一共创建{0}个Student对象'.format(Student.count))
  18. Student.printCompany()

17.4.4 静态方法

python中允许定义与"类对象"无关的方法,称为"静态方法".

“静态方法”和在模块中定义普通函数没有区别,只不过“静态方法”放到了“类的名字空间里面”,需要通过“类调用”。

静态方法通过装饰器@staticmethod来定义,格式如下:

  1. @staticmethod
  2. def 静态方法名([形参列表])
  3. 函数体

要点如下:

  1. @staticmethod必须位于方法上面一行
  2. 调用静态方法格式:“类名.静态方法名(参数列表)”。
  3. 静态方法中访问实例属性和实例方法会导致错误
  1. class Student(object):
  2. '''类属性的使用测试'''
  3. company = 'SXT' #类属性
  4. count = 0 #类属性
  5. def __init__(self,name,score):
  6. self.name = name #实例属性
  7. self.score = score
  8. Student.count += 1
  9. def say_score(self): #实例方法
  10. print('我的公司是:',Student.company)
  11. print(self.name,'的分数是:',self.score)
  12. @staticmethod
  13. def add(a, b): # 静态方法
  14. print('{0}+{1}={2}'.format(a, b, a + b))
  15. return a + b
  16. @classmethod
  17. def printCompany(cls):#类方法
  18. print(cls.company)
  19. s1 = Student('张三',80) #s1是实例对象,自动调用__init__() 方法
  20. # s1.say_score()
  21. # print('一共创建{0}个Student对象'.format(Student.count))
  22. # Student.printCompany()
  23. print(Student.add(1.4,7))
  24. s1.add(1,2)
  25. 1.4+7=8.4
  26. 8.4
  27. 1+2=3

17.5 del()方法(析构函数)和垃圾回收机制

__del__方法称为“析构方法”,用于实现对象被销毁时所需的操作。比如:释放对象 占用的资源,例如:打开的文件资源、网络连接等。

Python实现自动的垃圾回收,当对象没有被引用时(引用计数为 0),由垃圾回收器调用__del__方法。

我们也可以通过del 语句删除对象,从而保证调用__del__方法。

系统会自动提供__del__方法,一般不需要自定义析构方法。

  1. class Person(object):
  2. def __del__(self):
  3. print('销毁对象{0}'.format(self))
  4. p1 = Person()
  5. p2 = Person()
  6. del p2
  7. print('程序结束 ')

17.6 call()方法和可调用对象

定义了__call__方法的对象,称为“可调用对象”,即该对象可以像函数一样被调用

  1. class SalaryAccount(object):
  2. def __call__(self, salary,*args, **kwargs):
  3. print('算工资啦')
  4. # return 3000
  5. yearsalary = salary*12
  6. daysalary = salary//22.5
  7. hoursalary = daysalary//8
  8. return dict(yearsalary= yearsalary,daysalary=daysalary,hoursalary=hoursalary)
  9. s = SalaryAccount()
  10. print(s(30000))

17.7 方法没有重载/方法的动态性

17.7.1 方法没有重载

在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可。方法签名包含 3 个部分:方法名、参数数量、参数类型

Python中,方法的的参数没有声明类型(调用时确定参数的类型),参数的数量也可以由 可变参数控制。因此,Python中是没有方法的重载的。定义一个方法即可有多种调用方式, 相当于实现了其他语言中的方法的重载。

如果我们在类体中定义了多个重名的方法,只有最后一个方法有效。

建议:不要使用重名的方法!Python中方法没有重载。只有最后一个有效。

17.7.2 方法的动态性

  1. class Person(object):
  2. # def __del__(self):
  3. # print('销毁对象{0}'.format(self))
  4. def work(self):
  5. print('努力上班!')
  6. def play_game(self):
  7. print('{0}玩游戏'.format(self))
  8. def work2(s):
  9. print('好好工作,努力上班')
  10. Person.play_game = play_game
  11. p1 = Person()
  12. p2 = Person()
  13. p1.work()
  14. p1.play_game()
  15. Person.work = work2
  16. p1.work()
  17. 努力上班!
  18. <__main__.Person object at 0x000001D55025F9B0>玩游戏
  19. 好好工作,努力上班

17.8 私有属性和私有方法(实现封装)

Python对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别。关于私有 属性和私有方法,有如下要点:

  1. 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public)
  2. 类内部可以访问私有属性(方法)
  3. 类外部不能直接访问私有属性(方法)
  4. 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)

【注】方法本质上也是属性!只不过是可以通过()执行而已。所以,此处讲的私有属性和公 有属性,也同时讲解了私有方法和公有方法的用法。如下测试中,同时也包含了私有方法和 公有方法的例子。

  1. #测试私有属性
  2. class Employee(object):
  3. __company = '蓝星科技' #类的私有属性
  4. def __init__(self,name,age):
  5. self.name = name
  6. self.__age = age #实例的私有属性,加了两个下划线
  7. def __work(self):#私有方法,加了两个下划线
  8. print('好好工作,赚钱养老婆')
  9. print('年龄:{0}'.format(self.__age))#类内部调用私有属性是完全没有问题的。
  10. print(Employee.__company)
  11. e = Employee('小蓝',18)
  12. print(e.name)
  13. # print(e.__age)
  14. print(e._Employee__age)
  15. print(dir(e))
  16. e._Employee__work()
  17. print(Employee._Employee__company)
  18. 小蓝
  19. 18
  20. ['_Employee__age', '_Employee__company', '_Employee__work', '__class__', '__delattr__', '__dict__', '__dir__', '__do
  21. c__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '
  22. __le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__s
  23. izeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
  24. 好好工作,赚钱养老婆
  25. 年龄:18
  26. 蓝星科技
  27. 蓝星科技

从打印的 Person 对象所有属性我们可以看出。私有属性“__age”在实际存储时是按照 “_Person__age”这个属性来存储的。这也就是为什么我们不能直接使用“__age”而可以 使用“_Person__age”的根本原因。

17.9 @property装饰器

@property可以将一个方法的调用方式变成"属性调用"。一般用来给对应的属性增加get和set方法。

@property 主要用于帮助我们处理属性的读操作、写操作。对于某一个属性,我们可以直 接通过:

emp1.salary = 30000

如上的操作:读操作、写操作。但是,这种做法不安全。比如,我需要限制薪水必须为1-10000 的数字。这时候,我们就需要通过getter、setter方法来处理。

  1. class Employee(object):
  2. def __init__(self,name,salary):
  3. self.__name = name
  4. self.__salary = salary
  5. @property #定义下面的方法变成了一个属性
  6. def salary(self):
  7. print('计算工资')
  8. return self.__salary
  9. @salary.getter
  10. def get_salary(self,salary):
  11. return self.__salary
  12. @salary.setter #针对salary属性的一个设置
  13. def salary(self,salary):
  14. if 1000<salary<50000:
  15. self.__salary = salary
  16. else:
  17. print('录入错误,薪水在1000--50000这个范围')
  18. '''
  19. def get_salary(self):
  20. return self.__salary
  21. def set_salary(self,salary):
  22. if 1000<salary<50000:
  23. self.__salary = salary
  24. else:
  25. print('录入错误,薪水在1000--50000这个范围')
  26. '''
  27. # emp1 = Employee('蓝星',30000)
  28. # print(emp1.get_salary())
  29. # emp1.set_salary(20000)
  30. # print(emp1.get_salary())
  31. # emp1.salary = 20000 #不能设置
  32. # emp1.salary() #也可像方法一样调用了,因为salary已经是一个属性了。
  33. emp2 = Employee('lanxing',20000)
  34. print(emp2.salary)
  35. emp2.salary = -29990
  36. emp2.salary = 2000

17.10 属性和方法命名总结/类编程风格

17.10.1 属性和方法命名总结

· _xxx:保护成员,不能用“frommodule import * ”导入,只有类对象和子类对象能访 问这些成员。

· __xxx__:系统定义的特殊成员

· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外部可以通过“对象名._类名__xxx”这种特殊方式访问。 Python 不存在严格意义的私有成员)

注:再次强调,方法和属性都遵循上面的规则。

17.10.2 类编码风格

  1. 类名首字母大写,多个单词之间采用驼峰原则。
  2. 实例名、模块名采用小写,多个单词之间采用下划线隔开。
  3. 每个类,应紧跟“文档字符串”,说明这个类的作用
  4. 可以用空行组织代码,但不能滥用。在类中,使用一个空行隔开方法;模块中,使用两个空行隔开多个类

17.11 继承(inheritance)

继承是面向对象程序设计的重要特征,也是实现“代码复用”的重要手段。

如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作难度。已有的类,我们称为“父类或者基类”,新的类,我们称为“子类或者派生类”

17.11.1 继承的语法格式

python支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:

class 子类类名(父类1[,父类2,...]):

类体

如果在类定义中没有指定父类,则默认父类是object类。也就是说,object是所有类的父类,里面定义了一些所有类共有的默认实现,比如__new__().

定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下:

父类名.init(self,参数列表):

  1. class Person(object):
  2. def __init__(self,name,age):
  3. self.name = name
  4. self.__age = age #私有属性
  5. def say_age(self):
  6. print('年龄,年龄,我也不知道')
  7. class Student(Person):
  8. def __init__(self,name,age,score):
  9. #调用父类的构造函数方法一
  10. Person.__init__(self,name,age)#语法级别上不调用也没错,但是作为子类,必须要去调用,不然这个子类就没有name属性了。
  11. self.score = score
  12. #Student--->Person--->object类
  13. print(Student.mro())#打印继承顺序
  14. s = Student('lanxing',22,78)
  15. s.say_age()
  16. print(s.name)
  17. # print(s.age)
  18. print(s._Person__age)

17.11.2 类成员的继承和重写

  1. 成员继承:子类继承了父类除构造方法之外的所有成员。
  2. 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为重写
  1. #类成员继承和方法重写的案例
  2. class Person(object):
  3. def __init__(self,name,age):
  4. self.name = name
  5. self.__age = age
  6. def say_age(self):
  7. print('我的年龄是',self.__age)
  8. def say_intro(self):
  9. print('我的名字是{0}'.format(self.name))
  10. class Student(Person):
  11. def __init__(self,name,age,score):
  12. Person.__init__(self,name,age) #必须显式的调用父类初始化方法,不然解释器不会去调用。
  13. self.score = score
  14. def say_score(self):
  15. print(self.name,'的分数是:',self.score )
  16. def say_name(self): #重写父类的方法
  17. print('报告老师,我是',self.name)
  18. s1 = Student('张三',15,85)
  19. s1.say_score()
  20. s1.say_name()
  21. s1.say_age()

17.11.3 查看类的继承层次结构

通过类的方法mro()或者类的属性__mro__可以输出这个类的继承层次结构。

  1. class A:
  2. pass
  3. class B(A):
  4. pass
  5. class C(B):
  6. pass
  7. #print(C.mro())
  8. print(C.__mro__)#与上方代码是一样的效果
  9. [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

17.12 object根类

17.12.1 object根类的属性

object类是所有类的父类,因此所有的类都有object类的属性和方法。显然有必要深入研究下object类的结构。

  • dir()查看对象属性

    内置函数dir()可以查看指定对象所有的属性。
  1. class Person(object):
  2. def __init__(self,name,age):
  3. self.name = name
  4. self.__age = age #私有属性
  5. def say_age(self):
  6. print(self.name,'的年龄是:',self.age)
  7. obj = object() #obj是object这个基类实例化的对象
  8. print(dir(obj)) #输出obj这个对象的所有属性
  9. print('----------')
  10. s2 = Person('lanxing',19)
  11. print(dir(s2))
  12. ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format
  13. __', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '
  14. __init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce
  15. __', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str_
  16. _', '__subclasshook__']
  17. -------------------
  18. ['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '_
  19. _doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__
  20. ', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '_
  21. _module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__rep
  22. r__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__w
  23. eakref__', 'name', 'say_age']

从上面我们可以发现这样几个要点:

  1. Person对象增加了六个属性: dict, module, weakref ,age, name, say_age
  2. object的所有属性,Person 类作为object 的子类,显然包含了所有的属性。
  3. 我们打印age、name、say_age,发现say_age 虽然是方法,实际上也是属性。只不过, 这个属性的类型是“method”而已。
  1. age <class 'int'>
  2. name <class 'str'>
  3. say_age <class 'method'>

17.12.2 重写__str__方法

  1. class Person(object):
  2. def __init__(self,name,age):
  3. self.name = name
  4. self.__age = age #私有属性
  5. p = Person('LANXING',22)
  6. print(p)
  7. <__main__.Person object at 0x000001EC5F1CF940>
  8. class Person(object):
  9. def __init__(self,name,age):
  10. self.name = name
  11. self.__age = age #私有属性
  12. def __str__(self):
  13. '''将对象转化成一个字符串,一般用于print方法'''
  14. return '名字是:{0},年龄是{1}'.format(self.name,self.__age)
  15. p = Person('LANXING',22)
  16. print(p)
  17. 名字是:LANXING,年龄是22

17.13 多重继承

python支持多重继承,一个子类可以有多个"直接父类"。这样,就具备了多个父类的特点。但是,由于这样会被类的整体层次搞的异常复杂,尽量避免使用

在python3中,不管是新式类写法还是经典类写法,都是按照广度优先进行查询。

python2中,新式类写法是按照广度优先,经典类写法是按照深度优先。

  1. class A: #经典类写法
  2. pass
  3. class B(A): #新式类写法
  4. pass
  5. class C(B,A): #多重继承
  6. pass
  7. class D(C,B)
  8. #广度优先就是D先从C查询,C没有,就找B,B再没有就找A。
  9. #深度优先就是D先从C查询,如果C没有,就再找A。

17.14 super()方法获得父类定义

在子类中,如果想要获得父类的方法时,可以通过super()来获得。

super()代表父类的定义,不是父类的对象。

  1. class A:
  2. def say(self):
  3. print('A:',self)
  4. class B(A):
  5. def say(self):
  6. # A.say(self)
  7. super().say() #super()=A
  8. print('B:',self)
  9. B().say()

17.15 多态(polymorphism)

多态(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为。

关于多态要注意以下2点:

  1. 多态是方法的多态,属性没有多态。
  2. 多态的存在有2个必要条件:继承和方法重写。
  1. class Man(object):
  2. def eat(self):
  3. print('饿了,吃饭了!')
  4. class Chinese(Man):
  5. def eat(self): #方法重写
  6. print('中国人用筷子吃饭')
  7. class English(Man):
  8. def eat(self):
  9. print('英国人用叉子吃饭')
  10. class Indian(Man):
  11. def eat(self):
  12. print('印度人用右手吃饭')
  13. def manEat(m):
  14. if isinstance(m,Man):
  15. m.eat() #多态
  16. else:
  17. print('不能吃饭')
  18. manEat(Chinese())
  19. manEat(English())

17.16 特殊方法和特性属性

17.17 对象的浅拷贝和深拷贝

  • 变量的赋值操作

    只是形成两个变量,实际还是指向同一个对象。
  • 浅拷贝

    Python拷贝一般都是浅拷贝。拷贝时,对象包含的子对象内容不拷贝。因此,源对象 和拷贝对象会引用同一个子对象。
  • 深拷贝

    使用copy模块的 deepcopy 函数,递归拷贝对象中包含的子对象。源对象和拷贝对象所有的子对象也不同。
  1. import copy
  2. class MobilePhone(object):
  3. def __init__(self,cpu,screen):
  4. self.cpu = cpu
  5. self.screen = screen
  6. class Cpu:
  7. def calculate(self):
  8. print('计算,算个12345')
  9. print('cpu的对象',self)
  10. class Screen:
  11. def show(self):
  12. print('显示一个好看的画面')
  13. print('屏幕对象:',self)
  14. #测试变量赋值
  15. c1 = Cpu()
  16. c2 = c1
  17. # print(c1)
  18. # print(c2)
  19. #测试浅复制
  20. s1 = Screen()
  21. m1 = MobilePhone(c1,s1)
  22. m2 = copy.copy(m1)
  23. # print(m1,m1.cpu,m1.screen)
  24. # print(m2,m2.cpu,m2.screen)
  25. #测试深复制
  26. m3 = copy.deepcopy(m1)
  27. print(m1,m1.cpu,m1.screen)
  28. print(m3,m3.cpu,m3.screen)

17.18 组合

"is-a"关系,我们可以使用“继承”。从而实现子类拥有父类的方法和属性。“is-a” 关系指的是类似这样的关系:狗是动物,dog is animal。狗类就应该继承动物类。

"has -a"关系,我们可以使用“组合”,也能实现一个类拥有另一个类的方法和属性。has-a”关系指的是这样的关系:手机拥有 CPU。 MobilePhone has a CPU.

  1. #使用继承实现代码的复用
  2. class A1:
  3. def say_a1(self):
  4. print('a1,a1,a1')
  5. class B1(A1):
  6. pass
  7. b1 = B1()
  8. b1.say_a1()
  9. #同样的效果,使用组合来实现代码的复用
  10. class A2:
  11. def say_a2(self):
  12. print('a2,a2,a2')
  13. class B2:
  14. def __init__(self,a):
  15. self.a =a
  16. a2 = A2()
  17. b2 = B2(a2)
  18. b2.a.say_a2()

18. 面向对象三大特征

python是面向对象的语言,也支持面向对象编程的三大特性:继承/封装(隐藏)/多态

18.1 封装(隐藏)

隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只对外暴露“相关调用的方法”。

通过前面学习的“私有属性/私有方法”的方式,实现“封装”。python追求简洁的语法,没有严格的语法级别的访问控制符,更多的是依靠程序员自觉实现。

18.2 继承

继承可以让子类具有父类的特性,提高了代码的重用性

从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法。

18.3 多态

多态是指同一个方法调用由于对象不同会产生不同的行为。生活中这样的例子比比皆是:同样是休息方法,人不同休息方法不同。张三休息是睡觉,李四休息是玩游戏,程序员休息是"敲几行代码"。即“一个接口,多种实现”。

19. 设计模式:工厂模式与单例模式

设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候固定的做法,设计模式有很多种,比较流行的是:GOF,23种设计模式。

对于初学者,学习两个最常用的模式:工厂模式与单例模式。

19.1 工厂模式

工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类/创建对象进行了统一的管理和控制。越是大型的软件,越是需要工厂模式。

  1. #工厂模式
  2. class CarFactory(object):
  3. def createCar(self,brand):
  4. if brand =="benz":
  5. return Benz()
  6. elif brand =="baoma":
  7. return Baoma()
  8. elif brand == "biyadi":
  9. return Biyadi()
  10. else:
  11. return '未知品牌,不能代工'
  12. class Benz:
  13. pass
  14. class Baoma:
  15. pass
  16. class Biyadi:
  17. pass
  18. factory = CarFactory()
  19. c1 = factory.createCar('benz')
  20. c2 = factory.createCar('baoma')
  21. print(c1)
  22. print(c2)
  23. <__main__.Benz object at 0x0000022FD5D604A8>
  24. <__main__.Baoma object at 0x0000022FD5D604E0>

19.2 单例模式

单例模式(singleton pattern)的核心作用是确保一个类只有一个实例对象,并且提供一个访问该实例的全局访问点

单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件/产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大的降低开销。

单例模式有多种实现的方法,这里推荐重写__new__()的方法。

  1. class MySingleton(object):
  2. __obj = None #类属性
  3. __init_flag = True
  4. def __new__(cls, *args, **kwargs):
  5. if cls.__obj == None:
  6. cls.__obj =object.__new__(cls)
  7. return cls.__obj
  8. def __init__(self,name):
  9. if MySingleton.__init_flag:
  10. self.name = name
  11. print('init.....')
  12. MySingleton.__init_flag = False
  13. a = MySingleton('aa')
  14. b = MySingleton('bb')
  15. print(a)
  16. print(b)

python day10: 反射补充,面向对象的更多相关文章

  1. python学习-第四天补充-面向对象

    python学习-第四天补充-面向对象 python 私有 --name mangling(名字修改.名字) 在命名时,通过使用两个下划线作为开头,可以使得这个变量或者函数编程私有的,但是这个其实的p ...

  2. python对象反射和函数反射

    python的对象反射功能,经常在编程时使用.相比较其它的编程语言使用非常方便.反射就是用字符串来操作对象或者类,模块中的成员. 一.对象的反射 反射功能的实现,由这4个内置函数来实现(hasattr ...

  3. Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究

    Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究 一丶反射 什么是反射: ​ 反射的概念是由Smith在1982年首次提出的 ...

  4. day34 反射、面向对象内置方法:如__str__、面向对象的软件开发

    Python之路,Day21 = 反射.面向对象内置方法:如__str__.面向对象的软件开发 几个内置查看的方法使用 .__base__ 查看类的继承结构.mro() 对象找属性的顺序存在里面 -- ...

  5. python的反射机制

    转载自:http://www.cnblogs.com/feixuelove1009/p/5576206.html 对编程语言比较熟悉的朋友,应该知道"反射"这个机制.Python作 ...

  6. python的反射

    目前大多数网站都是通过路由的方法来,处理url请求,如果有很多个url的话,不停的include或者用if判断匹配,似乎不太符合情理,因此这里讲讲python的反射机制, 自动装在模块.请看下面的实例 ...

  7. Python数据结构与算法--面向对象

    前面已经讲过,Python是一种面向对象的编程语言. 面向对象编程语言中最重要的特征是允许程序员创建类建立数据模型来解决问题. 我们之前利用抽象数据类型提供的逻辑来描述数据对象 (它的状态) 和功能 ...

  8. python笔记 - day7-1 之面向对象编程

    python笔记 - day7-1 之面向对象编程 什么时候用面向对象: 多个函数的参数相同: 当某一些函数具有相同参数时,可以使用面向对象的方式,将参数值一次性的封装到对象,以后去对象中取值即可: ...

  9. 简单谈谈python的反射机制

    转:http://www.jb51.net/article/87479.htm 本文主要介绍python中的反射,以及该机制的简单应用,熟悉JAVA的程序员,一定经常和Class.forName打交道 ...

随机推荐

  1. MySql 三大知识点——索引、锁、事

    作者:莫那鲁道原文:http://thinkinjava.cn/2019/03/16/2019-03-16-mysql/ 1. 索引 索引,类似书籍的目录,可以根据目录的某个页码立即找到对应的内容. ...

  2. pandas filter数据筛选

    https://study.163.com/course/courseMain.htm?courseId=1006383008&share=2&shareId=400000000398 ...

  3. swoole流程图

    程图,便于以后回忆下 总结几点如下: 首先主进程监听pipe_master事件, 子进程监听pipe_worker事件 通过主进程派生的线程 swReactorThread *thread = swS ...

  4. Linux配置crontab

    1. 添加任务(每分钟执行一次)crontab -e* * * * * /home/lings/logRotate.sh 2. 查看日志Jun 5 20:25:01 localhost CROND[8 ...

  5. linux环境中,openssl升级及openresty中nginx基于新版本openssl重新编译

    需求说明: 最近在对系统进行安全扫描的时候,出现了openssl版本的问题,建议对openssl版本进行升级,在此记录下升级过程. 环境说明: 操作系统:RHEL 6.6 升级操作过程: 1.下载最新 ...

  6. Linux MySQL 5.6.43 安装

    [注意] 1.首先安装在默认目录 /usr/local/mysql,如需更改数据存储目录,进行2.3两步 2.如果需要修改数据目录,将my.nf 中的 datadir=/usr/local/mysql ...

  7. Tengine的说明

    什么是Tengine 官方帮助文档:http://tengine.taobao.org/changelog_cn.html

  8. k8s添加凭证

    请参照:https://www.cnblogs.com/effortsing/p/10013441.html

  9. 用ArcMap在PostgreSQL中创建要素类需要执行”create enterprise geodatabase”吗

    问:用Acmap在PostgreSQL中创建要素类需要执行"create enterprise geodatabase"吗? 关于这个问题,是在为新员工做postgresql培训后 ...

  10. 小程序重置index,重置item

    重置index,重置item <block wx:for="{{index_data.banner_list}}" wx:for-index="idx" ...