学习 python 6 - python面向对象编程「半原创」


本文会带来什么

  1. python 中面向对象的特性
  2. 封装继承多态等学习

前言

面向对象编程,简称oop,是一种程序设计思想,万物皆对象,概念和Java 类似,不做过多介绍


正文

1.类和类方法的定义

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
#  --------------类和类方法的定义
# class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),
# 表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,
# 就使用object类,这是所有类最终都会继承的类。
class Student(object):
pass

student = Student()
# 可以给该变量绑定属性
student.name = "jack"
print(student.name)

# 也可以在创建的收把一些属性绑定上去,如下
# 注意到__init__方法的第一个参数永远是self,表示创建的实例本身,
# 因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
class Student2(object):
def __init__(self,name,age):
self.name = name
self.age = age
# 有了__init__方法,在创建实例的时候,就不能传入空的参数了,
# 必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
student2 = Student2("jack",3)
print(student2.name,"age :" ,student2.age)

# 和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,
# 并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,
# 所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。

class Student3(object):
def __init__(self,name,age):
self.name = name
self.age = age

def printNameAndAge(self):
print(self.name , "from def:" ,self.age)
# 有了__init__方法,在创建实例的时候,就不能传入空的参数了,
# 必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
student3 = Student3("jack3",3)
print(student3.name,"age :" ,student3.age)
student3.printNameAndAge()

2.访问限制

1
2
3
4
5
6
7
8
9
10
11
12
#  --------------访问限制
# 如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,是两个下滑,一个是没用的
# 方法也是如此
class Student(object):
def __init__(self,name):
self.__name = name

def __printSelf(self):
print("print")
student = Student("jack")
# 如果想要属性得以访问,可以 加类似于 get set 方法来做
# 有时候会看到 一个下划线开头的那种,也请视为 私有变量

3.继承和多态

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
#  --------------继承和多态
class Student(object):

def printSelf(self):
print("i am from student")

class Student2(Student):
pass

student2 = Student2()
student2.printSelf()

# 继承的好处
# 传入一个 animal 类型的函数,继承 Animal,实现 run 方法
def run_twice(animal):
animal.run()
animal.run()
# 静态语言 vs 动态语言
# 对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

# 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:
class Timer(object):
def run(self):
print('Start...')
# 这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

4.获取对象信息

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#  --------------获取对象信息
# 当我们拿到一个对象的引用时,如何知道这个对象是什么类型、有哪些方法呢?
# 首先,我们来判断对象类型,使用type()函数:

# 基本类型都可以用type()判断
print(type(123))
print(type(""))
print(type('12'))
print(type(None))
# 但是type()函数返回的是什么类型呢?它返回对应的Class类型。
# 如果我们要在if语句中判断,就需要比较两个变量的type类型是否相同:
print(type(123) == type(456))
print(type(123) == str)
print(type(123) == int)

# 判断基本数据类型可以直接写int,str等,但如果要判断一个对象是否是函数怎么办?可以使用types模块中定义的常量

import types


def fn():
pass


print(type(fn) == types.FunctionType)

# 对于class继承的关系来看,用type 就很不方便,可以使用 isinstance

# 能用type()判断的基本类型也可以用isinstance()判断

# 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list
# 比如,获得一个str对象的所有属性和方法

print(dir("abc"))

# 类似__xxx__的属性和方法在Python中都是有特殊用途的,比如__len__方法返回长度。
# 在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,
# 它自动去调用该对象的__len__()方法,所以,下面的代码是等价的:
len("abc")
"abc".__len__()


# 我们自己写的类,如果也想用len(myObj)的话,就自己写一个__len__()方法
class MyDog(object):
def __len__(self):
return 100

# 仅仅把属性和方法列出来是不够的,
# 配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:


class MyObject(object):
def __init__(self):
self.x = 9
def power(self):
return self.x * self.x

obj = MyObject()

hasattr(obj, 'x') # 有属性'x'吗?
# True
obj.x
# 9
hasattr(obj, 'y') # 有属性'y'吗?
# False
setattr(obj, 'y', 19) # 设置一个属性'y'
hasattr(obj, 'y') # 有属性'y'吗?
# True
getattr(obj, 'y') # 获取属性'y'
# 19
obj.y # 获取属性'y'
# 19

# 可以传入一个default参数,如果属性不存在,就返回默认值:
getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
# 404

# 也可以获得对象的方法:
hasattr(obj, 'power') # 有属性'power'吗?
# True
getattr(obj, 'power') # 获取属性'power'
# <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
fn # fn指向obj.power
# <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
fn() # 调用fn()与调用obj.power()是一样的
# 81

5.实例属性和类属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#  --------------实例属性和类属性
# 由于Python是动态语言,根据类创建的实例可以任意绑定属性。
# 给实例绑定属性的方法是通过实例变量,或者通过self变量:
class Student(object):
def __init__(self, name):
self.name = name

s = Student('Bob')
s.score = 90
print(s.score)

# 但是,如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有:
class Student2(Student):
age = 3

s1 = Student2("b")
print(s1.age)

参考