我是靠谱客的博主 酷炫大地,这篇文章主要介绍Python3.5从0开始学读书笔记——第八章 面向对象编程,现在分享给大家,希望可以做个参考。

面向对象术语介绍

  • 类:用来描述具有相同属性和方法的对象的集合。类定义中集合了每个对象共有的属性和方法。对象是类的示例。
  • 类变量(属性):类属性在整个实例化的对象中是公用的。类变量定义在类中,且在方法之外。类常亮通常不作为适量变量使用。类变量也称作属性。
  • 数据成员:类变量或实例变量用于处理类及其实例变量的相关数据。
  • 方法重写:如果从父类继承的方法,不能满足子类的需求,就可以对其重写,这个过程叫做方法的覆盖,也称为方法的重写。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 多态:对不同类的对象使用同样的操作。
  • 封装:对外部对象隐藏对象的工作细节。
  • 继承:即一个派生类继承基类的字段和方法。继承允许把一个派生类的对象作为一个基类对象对待,以普通类为基础建立专门的类对象。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

类的定义

示例:

复制代码
1
2
3
4
5
6
7
#! /usr/bin/python3 # -*- coding:UTF-8 -*- class MyClass(object): i = '小明' def f(self): return 'hello world %s' % self.i

类定义的写法:

  • 使用class关键字,class关键字后面紧跟类名,类名通常首字母大写
  • 类名后紧跟的是(object),表明该类是从哪个类中继承而来的,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
  • 类通常包含属性和方法。在类中定义方法时,第一个参数必须是self。除第一个参数外,类的方法和普通函数没有什么区别。

类的使用

复制代码
1
2
3
4
5
6
7
8
9
10
11
#! /usr/bin/python3 # -*- coding:UTF-8 -*- class MyClass(object): i = '小明' def f(self): return 'hello world %s' % self.i my_class = MyClass() print('类中的属性是:',my_class.i) print('类中方法的返回是:',my_class.f())

输出:

复制代码
1
2
3
类中的属性是: 小明 类中方法的返回是: hello world 小明

类的使用比函数调用多了几个操作:

  • my_class = MyClass() 这步叫做类的实例化,即创建一个类的实例。由此得到的my_class变量称为类的具体对象。
  • 调用类中定义的方法,除了self不用传递外,其他参数正常传入。
  • 类属性引用的语法为:obj.name,obj为类对象,name代表属性。

类的构造方法

在Python中,_init_()方法是一个特殊方法,在对象实例化时会被调用。这个方法的写法是:先输入两个下划线,后面接着输入init,再接着两个下划线。这个方法也叫构造方法。在定义类时,如果不显示的定义_init_()方法,则程序默认会调用一个无参的构造方法。示例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass2(object): i = 123 def __init__(self,name1,age1): self.name = name1 self.age = age1 def f(self): return 'hello %s,you are %s years old!' % (self.name,self.age) my_class2 = MyClass2('小明','23') print('类中的属性是:',my_class2.name) print('类中的属性是:',my_class2.age) print('类中方法的返回是:',my_class2.f())

输出:

复制代码
1
2
3
4
类中的属性是: 小明 类中的属性是: 23 类中方法的返回是: hello 小明,you are 23 years old!

一个类中可以定义多个构造方法,但实例化类时只实例化最后的构造方法,即后面的构造方法会覆盖前面的构造方法,并且需要根据最后一个构造方法的形参进行实例化。建议一个类中,只定义一个构造方法。

类的访问权限

直接访问公有属性和方法

在类的内部有属性和方法,外部代码可以直接调用属性和方法。示例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /user/bin/python3 # -*- coding:UTF-8 -*- class Student(object): def __init__(self,name,age): self.name = name self.age = age def info(self): print('hello %s,you are %s years old!' % (self.name,self.age)) stu = Student('小明','23') stu.info() stu.name = '小张' stu.age = '24' stu.info()

输出:

复制代码
1
2
3
hello 小明,you are 23 years old! hello 小张,you are 24 years old!
如何定义和访问私有属性

要让类的内部属性不被外部访问,可以在属性名称前加两个下划线__。在Python中,实例的变量名如果以两个下划线开头,就会变成私有变量,只有内部可以访问,外部不能访问。此时,如果直接访问就会出错。示例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /user/bin/python3 # -*- coding:UTF-8 -*- class Student(object): def __init__(self,name,age): self.__name = name self.__age = age def info(self): print('hello %s,you are %s years old!' % (self.__name, self.__age)) stu = Student('小明','23') stu.info() stu.__name = '小张' stu.__age = '24 stu.info()

输出:

复制代码
1
2
3
4
5
6
7
Traceback (most recent call last): File "D:/pyspace/hellopython/Chapter8.py", line 60, in <module> stu.info() File "D:/pyspace/hellopython/Chapter8.py", line 57, in info print('hello %s,you are %s years old!' % (self.name,self.age)) AttributeError: 'Student' object has no attribute 'name'

这时,可以通过为类增加get_attrs()方法,获取类中的私有变量。可以为类添加set_attrs()方法,修改类中的私有变量。示例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Student(object): def __init__(self,name,age): self.__name = name self.__age = age def info(self): print('hello %s,you are %s years old!' % (self.__name,self.__age)) def get_name(self): return self.__name def set_name(self,name): self.__name = name def get_age(self): return self.__age def set_age(self,age): self.__age = age stu = Student('小明','23') stu.info() stu.set_name('小张') print('修改后的姓名是:',stu.get_name()) stu.set_age('24') print('修改后的年龄是',stu.get_age())

输出:

复制代码
1
2
3
4
hello 小明,you are 23 years old! 修改后的姓名是: 小张 修改后的年龄是 24
如何定义和访问私有方法

通过在方法名前加两个下划线,可以把方法定义为私有方法。私有方法不能通过外部代码直接访问,只能在类中通过公共方法调用。实例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /user/bin/python3 # -*- coding:UTF-8 -*- class Student(object): def __init__(self,name,age): self.name = name self.age = age def __info(self): print('hello %s,you are %s years old!' % (self.name,self.age)) def foo(self): self.__info() stu = Student('小明','23') stu.foo()

输出:

复制代码
1
2
hello 小明,you are 23 years old!

继承

当我们定义一个class时,可以从某个现有的class继承,定义的新class称为子类(SubClass),而被继承的class称为基类、父类或者超类(BaseClass、Super Class)。继承的格式如下:

复制代码
1
2
3
4
5
class DerivedClassName(BaseClassName): statemnt-1 ... statement-n

继承语法class子类名(基类名)时,基类名写在括号内,在元组中指明。特点如下:

  1. 在继承中,基类的构造方法不会被自动调用,需要在子类的构造方法中专门调用。
  2. 在调用基类的方法时,需要加上基类的类名前缀,并带上self参数变量。区别于在类中调用普通方法时,不需要带self参数。
  3. 在Python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal(object): def run(self): print('animal is running....') class Dog(Animal): pass class Cat(Animal): pass dog = Dog() dog.run() cat = Cat() cat.run()

输出:

复制代码
1
2
3
animal is running.... animal is running....

子类不能继承父类的私有方法,也不能调用父类的私有方法。

多态

当子类和父类有相同的方法时,子类的方法会覆盖父类的方法,在方法调用时,总是会首先调用子类的方法,这种情况就是多态。示例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#! /user/bin/python3 # -*- coding:UTF-8 -*- class Animal(object): def run(self): print('animal is running....') class Dog(Animal): def run(self): print('dog is running....') class Cat(Animal): def run(self): print('cat is running...') dog = Dog() dog.run() cat = Cat() cat.run() print('dog是否是animal类型',isinstance(dog,Animal)) print('dog是否是dog类型',isinstance(dog,Animal))

输出:

复制代码
1
2
3
4
5
dog is running.... cat is running... dog是否是animal类型 True dog是否是dog类型 True

例如上面的示例中,dog和cat分别继承了animal,并且分别定义了自己的run方法,最后调用的是各自的run方法。

使用多态的好处是:当我们需要传入Dog,Cat等子类对象时,只需要接收父类Animal对象就可以了,因为Dog,Cat等都是Animal类型,按照Animal类型传入参数即可。由于Animal类型都有run()方法,因此传入的类型只要是Animal类或者是Animal的子类,都会自动调用实例类型的方法。

多重继承

上一节讲述的是单继承,Python还支持多重继承。多重继承的类定义如下:

复制代码
1
2
3
4
5
class DerivedClassName(Base1,Base2,Base3): statment-1 ... statement-n

可以看到,多重继承就是有多个基类(父类或者超类)。

需要注意圆括号中父类的顺序,若父类中有相同的方法名,在子类使用时未指定,Python会从左到右搜索。若方法在子类中未找到,则从左到右查找父类中是否包含此方法。

获取对象信息

使用type()函数

判断基本类型可以用type()函数判断。如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
print('-----------type()函数-----------') print(type('abc')) print(type(123)) print(type(None)) print(type(abs)) print(type('abc')==str) print(type(123)==int) print('-----------判断一个对象是否是函数-----------') import types def func(): pass print(type(func)==types.FunctionType) print(type(abs)==types.BuiltinFunctionType) print(type(lambda x,y,z:x+y+z)==types.LambdaType) print(type(x for x in range(1,10))==types.GeneratorType)

输出:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
-----------type()函数----------- <class 'str'> <class 'int'> <class 'NoneType'> <class 'builtin_function_or_method'> True True -----------判断一个对象是否是函数----------- True True True True
使用isinstance()函数

使用isinstance()函数可以告诉我们一个对象是否是某种类型。

复制代码
1
2
3
print('dog是否是animal类型',isinstance(dog,Animal)) print('dog是否是dog类型',isinstance(dog,Animal))

输出

复制代码
1
2
3
dog是否是animal类型 True dog是否是dog类型 True
使用dir()函数

如果要获得一个对象的所有属性和方法,就可以使用dir()函数。dir()函数返回一个字符串的list。如:

复制代码
1
2
print(dir('abc'))

输出:

复制代码
1
2
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

类的专有方法

_str_

相当于java中的to_string()方法。如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
class Student(object): def __init__(self,name,age): self.__name = name self.__age = age def __str__(self): return '学生名称是:%s,学生的年龄是:%s' % (self.__name,self.__age) print(Student('小明','23')) stu_abc = Student('小宇','24') print(stu_abc)

输出:

复制代码
1
2
3
学生名称是:小明,学生的年龄是:23 学生名称是:小宇,学生的年龄是:24

注意:__str__方法必须返回一个字符串

_iter_

如果要将一个类用于for…in循环,类似list或者tuple一样,就必须实现一个_iter_()方法。该方法返回一个迭代对象,Python的for循环会不断调用迭代对象的__next()方法,获得循环的下一个值,直到遇到StopIteration错误时退出循环。如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a、b 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)

输出:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025
_getitem()_

要像list一样按照下标取出元素,需要实现__getitem()__方法,示例如下:

复制代码
1
2
3
4
5
6
7
8
9
class Fib(object): def __getitem__(self, n): a, b = 1, 1 for x in range(n): a, b = b, a + b return a print(Fib()[3])

输出:

复制代码
1
2
3
_getattr_

使用__getattr__方法动态返回一个属性。如:

复制代码
1
2
3
4
5
6
7
8
9
10
class Student1(object): def __getattr__(self, attr): if attr == 'score': return 95 stu1 = Student1() print(stu1.score)

输出:

复制代码
1
2
95
_call_

通过给一个类定义__call__方法,可以直接对实例进行调用并得到结果。__call__还可以定义参数。对实例进行直接调用就像对一个函数调用一样,完全可以把对象看成函数,把函数看成对象。因为这两者本来就没有根本区别。如果把对象看成函数,函数本身就可以在运行期间动态创建出来,因为类的实例都是运行期间创建出来的。这样一来,就模糊了对象和函数的界限。实例如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
#! /usr/bin/python3 # -*- coding:UTF-8 -*- class Student(object): def __init__(self,name): self.name = name def __call__(self, *args, **kwargs): print('姓名是:%s' % self.name) stu2 = Student('小明') stu2()

输出:

复制代码
1
2
姓名是:小明

可以使用Callable()函数,判断一个对象是否可以被调用。实例如下:

复制代码
1
2
3
4
5
print(callable(Student('小明'))) print(callable(Student1())) print(callable(max)) print(callable([1,2,3]))

输出:

复制代码
1
2
3
4
5
True False True False

牛刀小试——出行建议

小智今天想出去,但不清楚今天的天气是否适合出行,需要一个给他提供建议的程序,程序建议要求输入daytime和night,根据可见度和温度给出出行建议和使用的交通工具,需要考虑需求变更的可能。

需求分析:使用本章所学的封装、继承、多态比较容易实现,由父类封装查看可见度和温度的方法,子类继承父类。如果有需要,子类可以覆盖父类的方法,做自己的实现。子类也可以自定义方法。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class WeatherSeach(object): def __init__(self,input_daytime): self.input_daytime = input_daytime def search_visible(self): visible = 0 if self.input_daytime == 'daytime': visible = 6 elif self.input_daytime == 'night': visible = 2 return visible def search_temperature(self): temperature = 0 if self.input_daytime == 'night': temperature = 16 elif self.input_daytime == 'daytiem': temperature = 26 return temperature class OutAdvice(WeatherSeach): def __init__(self,input_daytime): WeatherSeach.__init__(self,input_daytime) def search_temperature(self): we_use = 'none' if self.input_daytime == 'daytime': we_use = '骑自行车' elif self.input_daytime == 'night': we_use = '开车' return we_use def take_advice(self): we_use = self.search_temperature() visible = self.search_visible() if visible >= 6: print('今天天气不错,可以%s出行' % we_use) elif 0 < visible <= 2: print('今天天气不好,只能%s出行' % we_use) else: print('输入的内容有误,无法给出相应的建议!') oa = OutAdvice('night') oa.take_advice()

输出

复制代码
1
2
今天天气不好,只能开车出行

问题解答

双下划线开头的实例变量一定不能从外部访问吗?

答:不是,不能直接访问的原因是Python解释器对外把__score变量变成了_Student__score,所以,仍然可以通过Student__score访问变量__score。如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student(object): def __init__(self,name,score): self.__name = name self.__socre = score def info(self): print('学生的姓名是:%s,成绩是:%s' % (self.__name,self.__socre)) def get_score(self): return self.__socre stu3 = Student('小宇','94') stu3.info() #print('分数是:',stu3._Student__score) #报错 print('分数是:',stu3.get_score())

输出:

复制代码
1
2
3
学生的姓名是:小宇,成绩是:94 分数是: 94
方法和函数的区别

答:在Python中,函数并不依附于类,在不在类中定义。而方法依附于类,定义在类中,本质上还是一个函数。为便于区分,我们把类中的函数叫做方法,不依赖于类的函数仍然称为函数。

为什么要使用类

答:在Python中,借助继承、封装、多态三大特性,使用类可以更好的对一类实物进行管理,可以将具有相同功能和行为的事物封装为一个类,其他具有相同特性的事物直接继承类,即可获得父类封装好的方法。同时,子类可以覆盖父类的方法,以满足特定的功能需求,子类也可以扩展自己的功能。使用类可以更好的实现代码的复用和扩展。

最后

以上就是酷炫大地最近收集整理的关于Python3.5从0开始学读书笔记——第八章 面向对象编程的全部内容,更多相关Python3.5从0开始学读书笔记——第八章内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部