Python自动化开发课堂笔记【Day07】 - Python进阶(类)- 02

类与对象

对象是特征(变量)与技能(函数)的结合体,类是一系列对象共有的特征与技能的结合体
  现实生活中:先有对象,再总结归纳出类
  程序中:一定是先定义类,再实例化出对象
定义类的语法:
class 类名:
  '''注释'''
  类体(可以是任意代码)

1 class Chinese:
2     country = 'China'
3     def __init__(self,name,age):
4         self.name = name
5         self.age = age
6         print('--->',self.name,self.age)
7     def talk(self):
8         print('say Chinese')

1. 类的第一种用法,实例化

1 p1 = Chinese('Albert',18)
2 p2 = Chinese('Baker',33)

2. 类的第二种用法,属性引用

1 print(Chinese.country)#类的数据属性
2 print(Chinese.__init__)#类的函数属性
3 p1.__init__('Talbert',81)

  3. 其他知识点补充

 1 print(Chinese.__dict__)#查看类的属性字典,或者说是名称空间
 2 #{'__module__': '__main__', '__doc__': None, 'talk': <function Chinese.talk at 0x00675D68>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, 'country': 'China', '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__init__': <function Chinese.__init__ at 0x00675228>}
 3 print(Chinese.country)
 4 print(Chinese.__dict__['country'])#效果同上,本质上是如何取到的country这个变量
 5 print(p1.name,p1.age)
 6 print(p1.__dict__['name'],p1.__dict__['age'])
 7 
 8 #类型和类是统一的
 9 print(type(p1)) #<class '__main__.Chinese'>
10 
11 #类中定义的变量对象是公用的,不会产生新的内存空间
12 print(id(p1.country)) #5593664
13 print(id(p2.country)) #5593664
14 print(id(Chinese.country)) #5593664

类绑定方法(类实例化后绑定到对象身上)
绑定方法:绑定到谁身上就是给谁用的,谁来调用就会自动把自己当作第一个参数传入

1 print(Chinese.talk) #<function Chinese.talk at 0x006F5D68>
2 print(p1.talk) #<bound method Chinese.talk of <__main__.Chinese object at 0x002759F0>>
3 print(p2.talk) #<bound method Chinese.talk of <__main__.Chinese object at 0x0070EB50>>

总结:定义在类内部的变量是所有对象共有的,id全一样。定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.func()会把obj本身当作第一个参数传入
  print(p1.x) # p1.__dict__ ---> Chinese.__dict__ ---> 报错
如果要查找一个属性,先从对象名称空间中查找,找不到之后再到类名称空间查找,如果还找不到不会再去全局找,直接报错

练习:

 1 1.统计类实例化对象的次数
 2 class Chinese:
 3     country = 'China'
 4     count = 0
 5     def __init__(self,name,age):
 6         self.name = name
 7         self.age = age
 8         Chinese.count += 1 #类变量的概念
 9         print('--->',self.name,self.age)
10         print('%d obj create' % Chinese.count)
11 p1=Chinese('A',1)
12 p2=Chinese('B',2)
13 
14 2.定义一个学生类
15 class Stu:
16     def __init__(self,stuid,name,age):
17         self.stuid = stuid
18         self.name = name
19         self.age = age
20         print('Student--->',self.stuid,self.name,self.age)
21 s1 = Stu(1,'A',18)
22 s2 = Stu(2,'B',18)
23 
24 3.类对象交互
25 class A:
26     camp = 'AAA'
27     def __init__(self,nickname,damage=100, HP=200):
28         self.nickname = nickname
29         self.damage = damage
30         self.HP = HP
31     def attack(self,enemy):
32         enemy.HP -= self.damage
33         print('造成%d点伤害' % self.damage)
34 class B:
35     camp = 'BBB'
36     def __init__(self,nickname,damage=200, HP=100):
37         self.nickname = nickname
38         self.damage = damage
39         self.HP = HP
40     def attack(self,enemy):
41         enemy.HP -= self.damage
42         print('造成%d点伤害' % self.damage)
43 a1 = A('a1')
44 b1 = B('b1')
45 print(a1.camp)
46 print(b1.camp)
47 a1.attack(b1)
48 b1.attack(a1)

继承

  继承是一种创建新类的方式,新建的类可以继承一个或多个父类,父类又可以称为基类或超类,新建的类称为派生类或子类

1 class ParentClass1:
2     pass
3 class ParentClass2:
4     pass
5 class SubClass1(ParentClass1):
6     pass
7 class SubClass2(ParentClass1,ParentClass2):
8     pass

如何查看继承的父类

1 print(SubClass1.__bases__) #(<class '__main__.ParentClass1'>,)
2 print(SubClass2.__bases__) #(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

  类的种类

 1 #Python2中分为新式类和经典类
 2 #新式类(有括号的,有继承关系的) 
 3 class Foo(object):
 4     pass
 5 #经典类(没括号的,谁都不继承)
 6 class Bar:
 7     pass
 8 #Python3中全部都是经典类(即使没有括号也是新式类)
 9 class Foo:
10     pass
11 print(Foo.__bases__) #(<class 'object'>,)

继承的好处:
  1.减少冗余代码
  2.在子类定义新的属性,覆盖掉父类的属性,称为派生

 1 class Animal:
 2     def __init__(self,name,age,sex):
 3         self.name = name
 4         self.age = age
 5         self.sex =sex
 6     def eat(self):
 7         print('eating...')
 8     def talk(self):
 9         print('%s saying...' % self.name)
10 class People(Animal):
11     def __init__(self,name,age,sex,edu):
12         Animal.__init__(self,name,age,sex)
13         self.edu = edu
14     def talk(self):
15         Animal.talk(self)
16         print('%s say hello' % self.name)
17 class Pig(Animal):
18     pass
19 class Dog(Animal):
20     pass
21 p1 = People('p1',18,'male','college')
22 g1 = Pig('g1',11,'female')
23 d1 = Dog('d1',22,'male')
24 print(p1.edu)
25 p1.talk()
26 g1.talk()
27 d1.talk()
28 print(isinstance(p1,People))
29 print(isinstance(g1,Pig))
30 print(isinstance(d1,Dog))

  对象如果要调用方法,先从对象自己的命名空间找,然后是自己的类,最后是父类,依次往上找

 1 class Parent:
 2     def foo(self):
 3         print('Parent.foo')
 4         self.bar()
 5     def bar(self):
 6         print('Parent.bar')
 7 class Sub(Parent):
 8     def bar(self):
 9         print('Sub.bar')
10 s=Sub()
11 s.foo() # Parent.foo
12         # Sub.bar

继承反应的是一种什么是什么的关系
组合也可以解决代码冗余的问题,但是组合反应的是一种什么有什么的关系

 1 class People:
 2     def __init__(self,name,age,sex):
 3         self.name=name
 4         self.age=age
 5         self.sex=sex
 6 class Date:
 7     def __init__(self,y,m,d):
 8         self.y = y
 9         self.m = m
10         self.d = d
11     def tell(self):
12         print('%s-%s-%s' % (self.y,self.m,self.d))
13 class Teacher(People):
14     def __init__(self,name,age,sex,salary,y,m,d):
15         People.__init__(self,name,age,sex)
16         self.salary = salary
17         self.birth = Date(y,m,d)
18 
19 class Student(People):
20     def __init__(self,name,age,sex,y,m,d):
21         People.__init__(self,name,age,sex)
22         self.birth = Date(y,m,d)
23 
24 t1 = Teacher('A',18,'male',3000,2000,1,1)
25 t1.birth.tell()

抽象类

 1 import abc
 2 class File(metaclass=abc.ABCMeta):
 3     @abc.abstractmethod
 4     def read(self):
 5         pass
 6     @abc.abstractmethod
 7     def write(self):
 8         pass
 9 class Txt(File):
10     def read(self):
11         pass
12     def write(self):
13         pass
14 p=Txt()

继承搜索顺序:
Python2中,分为
广度优先(新式类)F->D->B->A->E->C->H
深度优先(经典类)F->D->B->E->C->H->A
Python3中,只有广度优先(python3中只有新式类)

 1 class A:
 2     def test(self): print('from A')
 3     pass
 4 class B(A):
 5     def test(self): print('from B')
 6     pass
 7 class C(A):
 8     def test(self): print('from C')
 9     pass
10 class D(B):
11     def test(self): print('from D')
12     pass
13 class E(C):
14     def test(self): print('from E')
15     pass
16 class H(A):
17     def test(self): print('from H')
18     pass
19 class F(D,E,H):
20     def test(self): print('from F')
21     pass
22 f=F()
23 f.test()
24 print(F.mro())
25 #[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>,
26 # <class '__main__.C'>, <class '__main__.H'>, <class '__main__.A'>, <class 'object'>]

子类中重用父类的方法(super)

 1 class Foo:
 2     def test(self):
 3         print('from foo.test')
 4 class Bar(Foo):
 5     def test(self):
 6         super().test()
 7         print('from bar.test')
 8 b = Bar()
 9 b.test()
10 
11 class Foo1:
12     def test(self):
13         print('from foo1.test')
14 class Foo2:
15     def test(self):
16         print('from foo2.test')
17 class Bar(Foo1,Foo2):
18     def test(self):
19         super().test()
20         print('from bar.test')
21 b = Bar()
22 b.test() #from foo1.test
23          #from bar.test

多态与多态性

没有多态就没有多态性
多态:同一种事物的多种形态
多态性:指的是具有不同功能的函数可以使用相同的函数名

 1 class Animal:
 2     def eat(self):
 3         print('eating...')
 4 class People(Animal):
 5     def eat(self):
 6         print('eating...')
 7 class Pig(Animal):
 8     def eat(self):
 9         print('eating...')
10 class Dog(Animal):
11     def eat(self):
12         print('eating...')
13 p1=People()
14 g1=Pig()
15 d1=Dog()
16 def func(obj):
17     obj.eat()
18 func(p1)
19 func(g1)
20 func(d1)

封装

为什么要封装:保护隐私,隔离复杂度
Python没有真正的隐藏,只是从语法级别做了些改变

 1 class Foo:
 2     __x = 1 # '_Foo__x': 1
 3     def __test(self): # '_Foo__test': <function Foo.__test at 0x00665D68>
 4         print('from test')
 5 print(Foo.__dict__)
 6 print(Foo._Foo__x)
 7 print(Foo._Foo__test)
 8 
 9 class People:
10     __country = 'Chinese'
11     def __init__(self,name,age,sex):
12         self.__name=name #只在定义阶段才会发生变形,实例产生后新加入的变量就不会变形了
13         self.__age=age
14         self.__sex=age
15     def tell_info(self):
16         print('%s:%s:%s' % (self.__name,self.__age,self.__sex))
17 p=People('alex',18,'male')
18 print(p.__dict__) #{'_People__age': 18, '_People__sex': 18, '_People__name': 'alex'}
19 p.tell_info()
20 p.__salary = 3000
21 print(p.__dict__) #{'_People__name': 'alex', '_People__sex': 18, '_People__age': 18, '__salary': 3000}
22 
23 class People:
24     __country = 'Chinese'
25     def __init__(self,name,age):
26         self.__name=name
27         self.__age=age
28     def tell_info(self):
29         print('Name:%s,Age:%d' % (self.__name,self.__age))
30     def set_info(self,x,y):
31         if not isinstance(x,str):
32             raise TypeError('must be str!!!')
33         if not isinstance(y,int):
34             raise TypeError('must be int!!!')
35         self.__name = x
36         self.__age = y
37 p1 = People('Albert',18)
38 p1.tell_info() # Name:Albert,Age:18
39 p1.set_info('Baker',22)
40 p1.tell_info() # Name:Baker,Age:22

关于property的应用

 1 应用1:
 2 class Foo:
 3     @property
 4     def test(self):
 5         print('from foo')
 6     # test = property(test)
 7 f=Foo()
 8 # f.test() #from foo
 9 f.test #from foo
10 
11 应用2:
12 class People:
13     def __init__(self,name,weight,height):
14         self.name = name
15         self.weight = weight
16         self.height = height
17     @property
18     def bmi(self):
19         return self.weight / (self.height ** 2)
20 p = People('Albert',75,1.80)
21 p.height=1.82
22 print(p.bmi)
23 
24 应用3:
25 import math
26 class Circle:
27     def __init__(self,radius):
28         self.raduis = radius
29     @property
30     def zc(self):
31         return 2 * math.pi * self.raduis
32 c = Circle(5)
33 print(c.zc)
34 
35 应用4:
36 class Person:
37     def __init__(self,name,permission=False):
38         self.__name = name
39         self.permission = permission
40     @property
41     def name(self):
42         return self.__name
43     @name.setter
44     def name(self,value):
45         if not isinstance(value,str):
46             raise TypeError('must be str')
47         self.__name = value
48     @name.deleter
49     def name(self):
50         if not self.permission:
51             raise PermissionError('not allowed')
52         del self.__name
53 p=Person('Albert')
54 print(p.name)
55 p.name='Baker'
56 print(p.name)
57 p.permission = True
58 del p.name

绑定

类中定义的函数分成两大类:
1.绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入)
  1.绑定到类的方法:用classmethod装饰器装饰的方法。
    为类量身定制
    类.bound_method(),自动将类当作第一个参数传入(其实对象也可调用,但仍将类当作第一个参数传入)
  2.绑定到对象的方法:没有被任何装饰器装饰的方法。
    为对象量身定制
    对象.bound_method(),自动将对象当作第一个参数传入(属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值的说法)

2.非绑定方法:用staticmethod装饰器装饰的方法
  不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说,就是一个普通工具而已

 1 #绑定到类的方法
 2 class Foo:
 3     @classmethod
 4     def test(cls):
 5         print(cls)
 6 Foo.test() #<class '__main__.Foo'>
 7 #跟谁都不绑定的方法
 8 class Foo:
 9     @staticmethod
10     def test(x,y):
11         print('test',x,y)
12 Foo.test(1,3)
13 f=Foo()
14 f.test(2,4)

示例

 1 #setting文件配置
 2 # HOST = '127.0.0.1'
 3 # PORT = 3306
 4 import setting
 5 import hashlib
 6 import time
 7 class MySQL:
 8     def __init__(self,host,port):
 9         self.sql_id = self.sql_id()
10         self.host = host
11         self.port = port
12         print('connecting...')
13     @classmethod
14     def from_conf(cls):
15         return cls(setting.HOST,setting.PORT) #相当于MySQL(host,port)
16     @staticmethod
17     def sql_id():
18         m = hashlib.md5(str(time.clock()).encode('utf-8'))
19         return m.hexdigest()
20     def select(self):
21         print(self) #<__main__.MySQL object at 0x0060E2D0>
22         print('select func',self.host,self.port)
23 
24 conn1 = MySQL('192.168.1.1',3306)
25 conn1.select()
26 print(conn1.sql_id)
27 conn2 = MySQL.from_conf()
28 print(conn2.sql_id)

staticmeth与classmethod的区别

 1 class Person:
 2     def __init__(self,name,age):
 3         self.name = name
 4         self.age = age
 5     def __str__(self):
 6         print('run __str__')
 7         return 'name:%s age:%s' % (self.name, self.age)
 8 p = Person('Albert',19)
 9 print(p)
10 
11 #setting文件配置
12 # HOST = '127.0.0.1'
13 # PORT = 3306
14 import setting
15 class MySQL:
16     def __init__(self,host,port):
17         self.host = host
18         self.port = port
19         print('connecting...')
20     @classmethod
21     def from_conf(cls):
22         return cls(setting.HOST, setting.PORT)
23     def __str__(self):
24         return 'from MySQL'
25 class Mariadb(MySQL):
26     def __str__(self):
27         print(self.host,self.port)
28         return 'from Maria'
29 conn1 = Mariadb.from_conf()
30 print(conn1)

反射(自省)

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问,检测和修改它本身状态或行为的一种能力。
Python面向对象中的反射:通过字符串的形式操作对象相关的属性。Python中的一切皆对象(都可以使用反射)

 1 class People:
 2     country = 'China'
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6 print(People.country)
 7 p = People('Albert',18)
 8 print(p)
 9 print(hasattr(p,'name')) # True
10 print(hasattr(People,'country')) #True
11 setattr(p,'sex','male')
12 print(p.__dict__) # {'age': 18, 'name': 'Albert', 'sex': 'male'}
13 print(getattr(p,'nam','not exist')) # not exist
14 print(getattr(p,'name'))
15 # setattr(p,'x',1)
16 if hasattr(p,'x'):
17     res = getattr(p,'x')
18     print(res)
19 delattr(p,'sex')
20 print(p.__dict__)

练习

 1 import sys
 2 res = sys.modules[__name__] #获取当前模块 <module '__main__' from 'C:/Users/ajiax/PycharmProjects/Python17/Day07/ALesson07.py'>
 3 print(res)
 4 if hasattr(res,'People'):
 5     get = getattr(res,'People')
 6     print(get)
 7     obj=get('Baker',22)
 8 print(obj.name)
 9 
10 
11 class FTPClient:
12     def __init__(self,host):
13         self.host=host
14         print('connecting...%s' % self.host)
15     def interactive(self):
16         while True:
17             cmd_line = input('>>>:').strip()
18             cmd_list = cmd_line.split()
19             if hasattr(self,cmd_list[0]):
20                 func = getattr(self,cmd_list[0])
21                 func(cmd_list)
22     def get(self,args):
23         print('downloading...%s' % args[1])
24 p = FTPClient('127.0.0.1')
25 p.interactive()
posted @ 2017-06-17 07:10  秋名山藤原豆腐哥  阅读(170)  评论(0编辑  收藏  举报