Python学习笔记(3)

面向对象

类的定义

  • 类的命名规则:首字母大写,驼峰表示法
  • 在另一个模块中实用类:from package.module import Student
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
class Student():

def __init__(self, name, age):
self.name = name
self.age = age

def print_file(self):
print('name:' + self.name)
print('age:' + str(self.age))


s = Student("ljl", 12)
s.print_file()

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

def __del__(self):
print('Persion is reclaimed')

def wake_up(self, name):
print("wake up %s" % name)

p = Person("Mars", 30)
print(hasattr(p, 'name')) # 是否有某个属性
print(getattr(p, 'name')) # 获取属性值
print(p.name)
setattr(p, 'name', 'ljl') # 设置属性值
print(p.name)
del(p.name) # 删除属性
# print(p.name) # Error
p.wake_up('ljl')
Person.wake_up(p, 'ljl') # 另一种调用成员方法的方式
p = None

方法与函数的区别

  • 方法:是一个面向对象的概念,类中的函数应该称为方法
  • 函数:是一个面向过程的概念
  • 数据成员:对象的特征

实例化与构造函数

  • 实例化时,构造函数是自动调用,不需要显式调用
  • 显式调用构造函数会返回 None
  • Python 中,一个类只能定义一个构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Student():

def __init__(self, name, age):
self.name = name
self.age = age

def print_file(self):
print('name:' + self.name)
print('age:' + str(self.age))


s = Student("ljl", 12)
s1 = Student("lyb", 13)
s.print_file()
s1.print_file()

类变量与实例变量

  • 类变量属于类的属性,定义在类内,构造方法外
  • 实例变量属于对象的特征,定义在构造方法内
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():

# 类变量
count = 1

def __init__(self, name, age):
# name和age都是实例变量
self.name = name
self.age = age

def print_file(self):
print('name:' + self.name)
print('age:' + str(self.age))
print('Count: ' + str(Student.count))

def add(self):
Student.count += 1


s = Student("ljl", 12)
s1 = Student("lyb", 13)
s.add()
s.print_file()
s1.add()
s1.print_file()
  • 对象的__dict__保存着对象的所有变量以及变量的值
  • python 对象查找实例变量的流程
    • 现在实例变量的列表中查找,如果找到,则直接返回
    • 如果没有找到,则会在类变量中查找
    • 如果类变量没有找到,会到父类中找
1
2
3
4
5
6
7
8
9
10
11
class Student():

# 类变量
name = "Class Value"

def __init__(self):
pass


s = Student()
print(s.name) # Class Value, Student并没有定义实例变量name,因此会找到类变量name

self 与实例方法

  • 实例方法第一个参数必须是 self,必须显式声明,调用实例方法时不用传入 self
  • self 只是一个名字,也可以使用其他名字,建议使用 self
  • self 代表当前的实例
1
2
3
4
5
6
7
8
class Person():
def __init__(this, name, age):
this.name = name
this.age = age


p = Person('ljl', 12)
print(p.name)

实例方法中访问实例变量与类变量

  • 实例方法中访问实例变量:self.name
  • 实例方法中访问类变量:Student.sum, self.__class__.sum
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Student():

# 类变量
sum = 0

def __init__(self, name, age):
self.name = name
self.age = age
# Student.sum = 12
self.__class__.sum += 1


s = Student('ljl', 12)
print(Student.sum)
s1 = Student('ljl', 12)
print(Student.sum)
s2 = Student('ljl', 12)
print(s2.__class__.sum)

类方法

  • 类方法中可以操作类变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Student():

# 类变量
sum = 0

def __init__(self, name, age):
self.name = name
self.age = age
self.__class__.plus_sum()

@classmethod
def plus_sum(cls):
cls.sum += 1


Student.plus_sum()
Student.plus_sum()
Student.plus_sum()
Student.plus_sum()
s = Student("ljl", 12)
print(Student.sum)
s.__class__.plus_sum()
print(Student.sum)

静态方法

  • 第一个参数不需要指定特定的对象
  • 对象和类都可以调用静态方法
  • 静态方法可以访问类变量: Student.sum1
  • 静态方法和类方法都不能直接访问实例变量
  • 静态方法相当于普通的方法,与类和实例没有太大关联
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student():
sum = 0

def __init__(self, name="ljl", age=12):
self.name = name
self.age = age
self.__class__.sum += 1

@staticmethod
def hello_world():
print("hello world")
print(Student.sum)


s = Student()
s.hello_world()
Student.hello_world()

成员可见性

  • 给变量或实例方法名前加双下划线__name,则该方法或变量名是私有的
  • 严格来讲,Python 的类是没有私有变量和私有方法,Python 解释器只是把带双下划线的实例变量和实例方法改了一个名字而已,格式:_Student__name_Student__private_method
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():

# 类变量
sum1 = 0

def __init__(self, name, age):
self.__name = name # 存储时私有变量的名字为_Student__name
self.__age = age

def get_name(self):
return self.__name

def __private_method(self):
print(self.__name)


s = Student('ljl', 12)
print(s.get_name())
# s.__private_method() # error
s.__name = "lyb" # 添加了一个新的实例变量,而不是原来的实例变量,而且新添加的实例变量不是私有的变量
print(s.__name) # OK
print(s.get_name())
s1 = Student('ljl', 13)
print(s1.__name) # error, s1没有新建实例变量__name
print(s1._Student__name) # ok,可以通过这种方法访问私有变量
  • 静态方法和类方法也可以是私有的
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
class Student():

# 类变量
sum1 = 0

def __init__(self, name, age):
self.__name = name # 存储时私有变量的名字为_Student__name
self.__age = age

def get_name(self):
return self.__name

def __private_method(self):
print(self.__name)

@classmethod
def __private_class_method(cls): # 私有类方法
print(cls.sum1)

@staticmethod
def __private_static_method(): # 私有静态方法
print("hello")


Student.__private_class_method() # error
s = Student('ljl', 12)
s.__private_static_method() # error

继承

  • 继承的目的:避免定义重复变量和方法
  • 子类可以继承父类的类变量,实例变量,构造方法,实例方法,类方法
  • 子类可以定义自己特有的实例变量
  • 可以通过类调用示例方法,但必须传入一个实例对象,Student.method(s),虽然可以这样做,但不推荐这样做
  • 在子类的构造函数中可以调用父类的构造函数
    • Human.__init__(self, name, age)
    • super(Student, self).__init__(name, age)推荐使用这种方法
  • super 也可以用在实例方法中
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
class Human():
sum = 0

def __init__(self, name, age):
self.name = name
self.age = age

def get_name(self):
print(self.name)

@classmethod
def super_class_method(cls):
print('super class mthod')

def do_homework(self):
print('do home')


class Student(Human):
def __init__(self, school, name, age):
self.school = school
# Human.__init__(self, name, age) # 这里不能缺少self
super(Student, self).__init__(name, age)

def do_homework(self):
super(Student, self).do_homework()
print('do a lot home')


s = Student('school', 'ljl', '12')

Student.super_class_method()
print(s.name)
print(s.age)
s.do_homework()
print(issubclass(Student, Human)) # 判断Student是否是Human的子类
pritn(isinstance(s, Student)) # True
pritn(isinstance(s, Human)) # True