面向对象有三大特征:封装、继承和多态,在认识这三大特征之前,需要先对类和对象有一个初步的了解。
类和对象同C++,是多个类似事物组成的群体的统称,能够帮助我们快速处理判断事物的性质。
类的创建# 语法及组成
class stu :
# 包含以下内容
# 类属性
# 实例方法
# 静态方法
# 类方法
pass # 这里以 pass 代表上述所有语句
举例:
class Stu: # 关于类名称的写法,通常采用驼峰式写法
# 类属性
name = 'jack'
def __init__(self, age):
self.age = age
# 实例方法
def print_name(self):
print(self.name)
def print_age(self):
print(self.name, ' :', self.age)
# 类方法
@classmethod
def fun_class(cls):
print('调用类方法!')
# 静态方法
@staticmethod
def fun1_static_fun():
print('调用静态方法!')
对象的创建
对象的创建又称为类的实例化
语法:
实例名 = 类名()
例子:
student = Stu(10)
有了实例,就可以调用类中的内容。
举例:
# 接上面的内容
student = Stu(10)
student.print_name()
student.print_age()
student.__init__(30)
Stu.print_age(student)
运行结果:
jack
jack : 10
jack : 30
类属性、类方法、静态方法
1、类属性:
类中方法外的变量称为类属性,被该类的所有对象共享。(类似C++中的public
)
2、类方法:
使用@classmethod
修饰的方法,使用类名直接访问的方法
3、静态方法
使用@staticmethod
修饰的方法,使用类名直接访问的方法
举例:
# 接上面内容
Stu.fun1_static_fun()
Stu.fun_class()
运行结果:
调用静态方法!
调用类方法!
动态绑定属性和方法
Python是动态语言,在创建对象之后,可以动态的绑定属性和方法。
举例:
# 类的创建之动态绑定属性和方法
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def print_info(self):
print(self.name, ':', self.age)
def show():
print('动态绑定方法成功!')
# 为了代码书写的的规范性,类与函数之间间隔2行
if __name__ == '__main__':
stu1 = Student('jack', 20)
stu1.print_info()
# 动态绑定属性
stu1.gender = '♂'
print(stu1.gender)
# 动态绑定方法
stu1.show = show
stu1.show()
运行结果:
jack : 20
♂
动态绑定方法成功!
封装
封装可以提高程序的安全性
1、将属性和行为包装到类对象中。在方法内部对属性进行 *** 作,在类对象的外部调用方法,这样就无需关注内部的实现细节,隔离了复杂度。
2、在Python中没有专门的修饰符用于属性的私有化,如果该属性不希望在类对象外部被访问,其前面加两个_
,即(__
)。【但其实这种方式并不代表在类外就完全不能访问了,也可以通过_类名称__类属性(方法)
的方式访问】
举例:
class Student:
def __init__(self, name, __age): # 不希望age在类外被访问
self.name = name
self.__age = __age
def show(self):
print(self.name, ':', self.__age)
if __name__ == '__main__':
stu1 = Student('jack', 30)
stu1.show()
print(stu1.name)
# print(stu1.__age) # 会提示报错 AttributeError
print(stu1._Student__age) # 这种方式虽然可以访问,但编译器仍然会给出警告,告诉你这是一种保护成员的访问类
运行结果:
jack : 30
jack
30
继承
继承提高代码的复用性。
1、语法格式:
class 子类类名(父类1, 父类2....):
pass
2、如果一个类没有继承任何类,则默认继承object
3、Python支持多继承
4、定义子类时,必须在其构造函数中调用父类的构造函数。
例子:
# 继承
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(self.name, self.age)
class FlyAnimal(Animal):
def __init__(self, name, age, type_name):
super().__init__(name, age) # 使用 supper() 可以避免重复的定义语句
self.type_name = type_name
def show(self): # 方法的重写
print(self.name, self.age, self.type_name)
if __name__ == '__main__':
an1 = FlyAnimal('麻雀', '2', '飞行')
an1.show()
运行结果:
麻雀 2 飞行
方法重写
1、如果子类对继承来自父类的某个属性或者方法不满意,可以在子类中对其重新编写
2、子类重写后的方法可以通过supper().FunName()
调用父类中被重写的方法。
例子可以参考上面的部分代码。
Object类1、object
类时所有类的父亲,因此所有类都有object
类的属性和方法、
2、内置函数dir()
可以查看指定对象所有属性
3、object
有一个__str__()
方法,用于返回一个对于"对象的描述",对应于内置函数str()
经常用于print()
方法,帮我们查看对象的信息,所以我们经常会对__str__()
进行重写。
至于区别的话,这里举个例子:
# 继承之 Object
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(self.name, self.age)
class Student(Person):
def __init__(self, name, age, uid):
super().__init__(name, age)
self.uid = uid
def show(self):
super().show()
print('uid = ', self.uid)
# def __str__(self): # 对象的描述
# return '__str__()已经被改写'
if __name__ == '__main__':
stu1 = Student('jack', 20, '001')
stu1.show()
o = object()
# print('显示object的属性:', dir(o))
# print('显示Student的属性:', dir(Student))
# 未重写 __str__()之前的输出
print('未重写 __str__()之前的输出')
print(stu1)
运行结果:
jack 20
uid = 001
未重写 __str__()之前的输出
<__main__.Student object at 0x00000270181D4EE0>
将class
的注释部分取消后:
代码:
# 继承之 Object
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(self.name, self.age)
class Student(Person):
def __init__(self, name, age, uid):
super().__init__(name, age)
self.uid = uid
def show(self):
super().show()
print('uid = ', self.uid)
def __str__(self): # 对象的描述
return '__str__()已经被改写'
if __name__ == '__main__':
stu1 = Student('jack', 20, '001')
stu1.show()
o = object()
# 重写 __str__()之前的输出
print('重写 __str__()之前的输出')
print(stu1)
运行结果:
jack 20
uid = 001
重写 __str__()之前的输出
__str__()已经被改写
多态
多态提高程序的可扩展性和可维护性。
即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行的过程中根据变量所引用对象的类型,动态决定带哦用哪个对象中的方法。
举例:
# 多态
class Animal:
def eat(self):
print('动物吃草')
class Dog(Animal):
def eat(self):
print('狗吃骨头....')
class Person:
def eat(self):
print('人吃五谷杂粮....')
def fun(obj):
obj.eat()
fun(Dog())
fun(Person())
运行结果:
狗吃骨头....
人吃五谷杂粮....
静态语言和动态语言
静态语言和动态语言关于多态的区别
Ⅰ、静态语言实现多态的三个必要条件
1、继承
2、方法重写
3、父类引用指向子类对象
Ⅱ、动态语言不关心对象的类型,只关心对象的行为
特殊方法和特殊属性名称 | 描述 | |
---|---|---|
特殊属性 | __dict__ | 获得类对象或者实例对象所绑定的所有属性和方法字典 |
特殊属性 | __bases__ | 返回类的父类元素 |
特殊属性 | __mro__ | 返回类的结构层次 |
特殊属性 | __subclass__() | 返回子类的列表 |
特殊方法 | __len__() | 通过重写该方法,然内置函数len() 的参数可以是自定义类型 |
特殊方法 | __add__() | 通过重写该方法,可以让自定义对象具有+ 的功能 |
特殊方法 | __new__() | 用于创建对象 |
特殊方法 | __init__() | 对创建的对象进行初始化 |
# 特殊方法
class Person(object):
def __init__(self, name, age): # 对其本来的 __init__()进行了重写
self.name = name
self.age = age
def show(self):
print(self.name, self.age)
p1 = Person('Kang', 20)
print(p1.__dict__)
print(Person.__bases__)
运行结果:
{'name': 'Kang', 'age': 20}
(,)
特殊方法的举例:
# 特殊方法
lst1 = range(1, 10) # 生成序列 1 2 3 4 5 6 7 8 9
print(lst1.__len__()) # __len__()计算lst1的长度
a = lst1[0]
b = a.__add__(lst1[-1]) # 序列的首尾相加
print(b)
class Student:
def __init__(self, math, chin):
self.math = math
self.chin = chin
def __add__(self, other): # 重写__add__()
return self.math + self.chin + other.math + other.chin
运行结果:
9
10
80
__new__()和__init__()
创建对象
# __new__() 和 __init__()
class Person:
def __new__(cls, *args, **kwargs):
print('调用___new__(),且其cls的id为{0}'.format(id(cls)))
obj = super().__new__(cls) # 创建一个对象
print("创建对象的id为:{0}".format(id(obj)))
return obj
def __init__(self, name, age):
print('调用__init__(),self 的id为:{0}'.format(id(self)))
self.name = name
self.age = age
if __name__ == '__main__':
# 在未创建对象之前
print('object这个对象的id为{0}'.format(id(object)))
print('Person这个类的id为{0}'.format(id(Person)))
p1 = Person('jack', 20)
print('p1的id为{0}'.format(id(p1)))
运行结果:
object这个对象的id为140717576510976
Person这个类的id为1823064928464
调用___new__(),且其cls的id为1823064928464
创建对象的id为:1823064743552
调用__init__(),self 的id为:1823064743552
p1的id为1823064743552
通过上面程序运行的id
变化可知,创建新对象的过程就是先通过__new__()
再通过__init__()
。
只是形成两个变量,实际上还是指向同一个对象
2、浅拷贝Python的拷贝一般都是浅拷贝,拷贝的时候,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象
3、深拷贝使用copy模块和deepcopy函数,递归拷贝对象中包含的子对象、源对象和拷贝对象所有子对象也不相同。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)