一、面向对象概念
面向对象是一种主流的编程思想,基本单元:对象,把数据和对象封装起来,实现很好的复用性、灵活性、扩展性;
面向对象是一种抽象,抽象是指用分类的眼光看待事物的方法,需要对事物进行总结,分析共性,利用抽象能够简化解决问题的难度;
基本概念
类:定义事物的抽象特点
对象:类的一个实例基本要素:
属性:类的信息
方法:类的功能类的特性
封装:类可以实现很多的功能,对外调用时,不需要知道具体是怎么实现的;
继承:定义一个新类时,不必从头编写,可以从现有的类中继承,获得现有类的所有功能,新类只需要编写现有类缺少的功能;
多态:继承于同一个父类的不同之子类,父类的方法,各个子类都有,但调用时的结果却不相同;
类对象创建后,类命名空间中所有的命名都是有效属性名。
二、定义类
语法:
class Class_name(object):
__init__
:定义类时,为类设置必要的属性,即初始化实例示例
class Student(object):
def __init__(self, name, sex, grade):
self.name = name,
self.sex = sex,
self.grade = grade
if __name__ == '__main__':
student = Student('larry', 'male', 5) # 创建实例
print('student of class:\n', student) # 查看student类
print('----------------------------')
print('type of student:\n', type(student)) # 查看student的类型
print('----------------------------')
print('attribute of student:\n', dir(student)) # 查看student的属性
student of class:
<__main__.Student object at 0x1063207b8>
----------------------------
type of student:
----------------------------
attribute of student:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__', 'grade', 'name', 'sex']
三、定义类的属性
- 方法
- 直接在类中定义:被类的所有对象(方法)共享,其属性值都是一样的;
- 通过构造函数:
def __init__(self, [, ....])
,其属性值依赖于传入的值;
- 访问控制
实际上,Python中并没有访问控制,Python没有提供私有属性的功能;
通过属性命名规范可以实现访问控制,不希望被外部访问的属性,在属性名前添加双下划线
(__)
即可。在实际工作中,这些命名规范全靠自觉;单下划线开头的属性,可以在子类中使用;双下划线开头的属性,不能被外部调用,也不能在子类中使用,即继承时这些私有属性和方法不会被覆盖。
- 示例
class Person(object):
hobby = 'Play Computer' # 直接在类中定义属性hobby
def __init__(self, name, sex, age): # 构造函数中定义初始化属性
self.name = name,
self._sex = sex,
self.__age = age
def get_age(self):
return self.__age
if __name__ == '__main__':
person = Person('larry', 'female', '28') # 创建实例
print('attribute of person:\n', dir(person)) # 查看类的属性
print(person.__dict__) # 查看构造函数中定义的属性
print(person.get_age()) # 调用获取age属性的方法
print(person._Person__age) # 变相获取双下划线开头的age属性
attribute of person:
['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'_sex', 'get_age', 'hobby', 'name']
{'name': ('larry',), '_sex': ('female',), '_Person__age': '28'}
28
28
四、定义类的方法
- 概念
函数是直接使用函数名进行调用;
方法是类的一部分,必须和对象结合在一起使用,使用类名进行调用,而不是某个对象;
方法的访问限制,和属性一样,没有严格的语法控制,只是遵循一些规范;
类中定义的方法,都是实例方法,可以看作是类的一个属性,第一个参数永远是self,表示创建的实例本身,
@classmethod:装饰的方法是类方法,类方法的第一个参数将传入类本身,通常将参数名命名为cls;
@property:装饰的方法,调用时,像访问属性一样(不需要带括号)。
- 示例
class Person(object):
hobby = 'Play Cumputer' # 直接在类中定义属性hobby
def __init__(self, name, sex, age): # 构造函数中定义初始化属性
self.name = name,
self._sex = sex,
self.__age = age
@classmethod
def get_hobby(cls):
return cls.hobby
@property
def get_age(self):
return self.__age
def self_introduction(self):
print(f"My name is {self.name[0]}\nI am {self.__age} years old")
if __name__ == '__main__':
person = Person('larry', 'male', 28)
print(dir(person))
print(Person.get_hobby())
print(person.get_age)
person.self_introduction()
['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_sex',
'get_age', 'get_hobby', 'hobby', 'name', 'self_introduction']
Play Cumputer
28
My name is larry
I am 28 years old
五、类的继承
- 概念
- 继承的子类:会继承父类的属性和方法,也可以自己定义,覆盖父类的属性和方法;
- 使用supper()调用父类的方法,或者直接使用父类的名称调用;
- isinstance():可以判断一个实例是否是指定的类;
- issubclass():判断一个类是否是子类;
- 类继承机制允许多重继承,派生类可以覆盖(override)基类中的任何方法或类,可以使用相同的方法名称调用基类的方法。
- 示例
# 类的继承
class Person(object):
hobby = 'Play Cumputer' # 直接在类中定义属性hobby
def __init__(self, name, sex, age): # 构造函数中定义初始化属性
self.name = name,
self._sex = sex,
self.__age = age
@classmethod
def get_hobby(cls):
return cls.hobby
@property
def get_age(self):
return self.__age
def self_introduction(self):
print(f"My name is {self.name[0]}\n I am {self.__age} years old")
class Student(Person):
def __init__(self, name, sex, age, weight):
super(Student, self).__init__(name, sex, age)
self.weight = weight
if __name__ == '__main__':
student = Student('larry', 'male', 28, 62)
print(type(student))
print(dir(student))
print(student.__dict__)
print(isinstance(student, Student)) # 实例student,是否是指定的类Student
print(issubclass(Student, Person)) # 类Student,是否是类Person的子类
['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_sex',
'get_age', 'get_hobby', 'hobby', 'name', 'self_introduction', 'weight']
{'name': ('larry',), '_sex': ('male',), '_Person__age': 28, 'weight': 62}
True
True
六、多态
- 概念
- 有了继承,才有了多态,在调用类实例方法时,尽量把变量当作父类,以便所有子类类型都可以正常接收;
- 多态:继承于同一个父类的不同之子类,父类的方法,各个子类都有,但调用时的结果却不相同。
- 示例
# 类的多态
class Person(object):
hobby = 'Play Cumputer' # 直接在类中定义属性hobby
def __init__(self, name, sex, age): # 构造函数中定义初始化属性
self.name = name,
self._sex = sex,
self.__age = age
@classmethod
def get_hobby(cls):
return cls.hobby
@property
def get_age(self):
return self.__age
def self_introduction(self):
return f"My name is {self.name[0]}\nI am {self.__age} years old"
class Student(Person):
def __init__(self, name, sex, age, weight):
super(Student, self).__init__(name, sex, age)
self.weight = weight
def self_introduction(self):
return f"My name is {self.name[0]}\n My weight is {self.weight}"
def introduce(class_name):
if isinstance(class_name, Person):
return class_name.self_introduction()
if __name__ == '__main__':
person = Person('larry', 'male', 28)
student = Student('larry', 'male', 28, 62)
print(introduce(person))
print(introduce(student))
My name is larry
I am 28 years old
My name is larry
My weight is 62
七、类的魔术方法
- 概念
- 绝大多数的Python内置函数,都有对应的魔术方法,可以在类中使用;
- 魔术方法,可以更方便自由地进行定制类,包括:对象建立、属性访问、运算符的支持、特殊语法等;
- 面向对象中,名称前后各有2个下划线
(__)
的方法,都是魔术方法,是定义在类中的,不需要直接调用; - 类中常用的魔术方法
魔术方法 | 含义 |
---|---|
__init__() | 构造函数,创建实例的时候被调用 |
__str__() | 返回适合人看的字符,print()调用的就是该方法 |
__repr__ | 返回适合机器看的字符 |
__eq__ | 判断是否相等,比较运算符 |
__add__ | 相加,数字运算符 |
__and__ | 判断条件,逻辑运算符 |
__dir__ | 查看对象的属性 |
__setattr__ | 设置对象的属性,注意避免循环递归,导致死循环 |
__getattribute__ | 访问对象的属性,注意避免死循环 |
__len__ | 获取对象参数个数 |
__call__ | 调用对象 |
- 示例
# 类中的魔术方法
class Person(object):
def __init__(self, name, age):
"""
构造函数,初始化定义属性
"""
self.name = name,
if isinstance(age, int): # 确保age属性必须是数值
self.age = age
else:
raise Exception ('age must be int')
def __eq__(self, other):
"""
判断2个对象是否相等
"""
if isinstance(other, Person): # 确保2个对象是同一个父类
if self.age == other.age:
return True
else:
return False
else:
raise Exception ('The class of object must be Person')
def __add__(self, other):
"""
2个对象相加
"""
if isinstance(other, Person): # 确保2个对象是同一个父类
return self.age + other.age
else:
raise Exception ('The class of object must be Person')
def __str__(self):
"""
输出指定内容
"""
return f"{self.name[0]} is {self.age} years old"
def __dir__(self):
"""
设置输出的属性
"""
return self.__dict__.keys()
def __setattr__(self, name, value):
"""
设置对象的属性
"""
self.__dict__[name] = value
def __getattribute__(self, name):
"""
访问对象的属性
"""
return super(Person, self).__getattribute__(name)
def __len__(self):
"""
返回类的参数个数
"""
return len(self.name)
def __call__(self, friend): # friend是调用对象时传入的参数
"""
调用对象
"""
return f"My name is {self.name[0]} ... My friend is {friend}"
if __name__ == '__main__':
p1 = Person('Larry', 28)
p2 = Person('Python', 30)
print(p1 == p2) # __eq__根据age属性,判断是否相等
print(p1 + p2) # __add__对age属性,相加
print(p1) # __str__返回指定的内容
print(dir(p1)) # __dir__输出指定的属性
print(p1.age) # __setattar__设置对象的属性
print(len(p1)) # __len__返回类的参数个数
print(p1('Tom')) # __call__调用对象
False
58
Larry is 28 years old
['age', 'name']
28
1
My name is Larry ... My friend is Tom