一切皆对象,将现实世界事务使用类与实例来模拟(e.g. 灯、汽车、导弹、杯子)
一、三大特性
1.封装:
数据:(e.g. 名字、年纪);数据相关操作:(e.g. 获取名字、设置名字、获取年纪、设置年纪)
python
class Students:
def __init__(self, name, age):
print("初始化函数")
self.name = name
self.age = age
def get_self(self):
return self
def describe_self(self):
return self.age
s0 = Students("x", 417)
print(id(s0), isinstance(s0, Students))
print(s0.name, s0.age)
s1 = s0.get_self()
print(s1 == s0.get_self(), s1 is s0.get_self())
print(id(s1), id(s0.get_self()))
print(s1)
s2 = s0.get_self()
print(s1 == s2, s1 is s2)
2.继承:
子类拥有父类的数据以及操作,子类不需要从新编写。
子类(派生类),父类(基类)。
base:获取父类; bases:获取父类元组; class:返回实例对应的类。
python
# 子类拥有父类的数据以及操作
# 子类 派生类
# 父类 基类
"""
object是所有类的父类
Python3中可以省略父类object
object 是基类,父类
Person 是object的子类 是SuperPerson的父类
SuperPerson 是Person的子类
子类拥有父类的功能方法,先在子类中找对应的方法 子类如果没有 则去父类中找 父类也没有则去父类的父类 直到object
"""
import math
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"{self.x} {self.y}"
p0 = Point(0, 0)
print(p0)
class Circle(Point):
def __init__(self, x, y, r):
super().__init__(x, y)
self.r = r
def __str__(self):
return f"{super().__str__()} r:{self.r}"
def acreage(self):
return math.pi * self.r ** 2
c0 = Circle(0, 0, 6)
print(c0)
print(c0.acreage())
class Rectangle(Point):
def __init__(self, x, y, w, h):
super().__init__(x, y)
self.w = w
self.h = h
def __str__(self):
return f"{super().__str__()} w:{self.w} h:{self.h}"
def acreage1(self):
return self.w * self.h
r0 = Rectangle(0, 0, 2, 3)
print(r0)
print(r0.acreage1())
多继承:继承多个父类,java,c# 只支持单继承,通过接口等来实现多继承的功能,Python直接就可以有多个父类。
python
# 继承多个父类
# java,c# 只支持单继承,通过接口实现多继承功能
# paython直接就可以多个父类
class MoveAble:
def __init__(self, speed):
self.speed = speed
def move(self):
print(f"{self.speed}")
def __str__(self):
return f"攻速"
class SpeakAble:
def __init__(self, language):
self.language = language
def speak(self):
print(f"{self.language}")
def __str__(self):
return f"语种"
class AttackAble:
def __init__(self, skill):
self.skill = skill
def attack(self):
print(f"使用{self.skill}进攻")
def __str__(self):
return f"攻击"
class Person(MoveAble, SpeakAble):
def __init__(self, name, speed, language):
# 通过类名表明需要初始化哪个父类 必须传入self
MoveAble.__init__(self, speed)
SpeakAble.__init__(self, language)
self.name = name
def show(self):
print(f"{self.name} 听召 前来")
def __str__(self):
return f"角色"
p0 = Person("x", 230, "chinese")
p0.move()
p0.speak()
p0.show()
class YS(Person, AttackAble):
def __init__(self, name, speed, language, skill):
Person.__init__(self, name, speed, language)
AttackAble.__init__(self, skill)
def __str__(self):
return f"游戏"
ys0 = YS("x", 230, "chinese", "平A")
ys0.show()
ys0.move()
ys0.speak()
ys0.attack()
print(ys0)
# 多继承 mro: method(方法) retrieval(检索) order(顺序)
# python3 使用广度优先
print(YS.mro())
3.多态:
Python中没有多态,也可以理解到处都是多态。
两种形式:
(1).函数同名不同参数,通过*args实现。
(2).父子类多态,函数名参数都相同,但是实现不同,拥有多种实现
python
# 同名不同参数
def my_fun1(a):
print(a)
my_fun1(6)
# 解释器 使用第二个函数 覆盖第一个 (第一个函数丢失)
def my_fun2(a, b):
print(a, b)
my_fun2(10, 20)
# 通过形参*ages实现多态功能
def my_fun(*ages):
print(ages)
my_fun(1)
my_fun(1, 2, 3)
class Animal:
def walk(self, speed):
print(f"z", speed)
class Dog(Animal):
def walk(self, speed):
print("ywb", speed)
class Cat(Animal):
def walk(self, speed):
print("zlzq", speed)
二、类与实例
类:是对现实世界描述的一种类型;"class 类名: pass",类名是大驼峰;是抽象的,约定了未来实例应该有的内容,是实例的模板。
实例:调用类则生成实例,类名() 产生实例;实例是具体的,有具体数据,实例的内容依赖于类。
1.类中内容、self
self:出现在类内来代表未来的实例,需要通过实例来访问。
初始化函数:init(self);通过初始化self来初始化未来的实例;向self中添加数据 就是向实例中添加数据。
(1).实例属性
向实例中添加的数据;类内:通过self;类外:通过实例;需要通过实例来访问。
python
class MyClass3:
def __init__(self, name):
self.name = name
m1 = MyClass3(6)
print(m1.name)
(2).实例方法
第一个形参是self;类内:通过self;类外:通过实例;需要通过实例来访问。
python
class MyClass4:
def __init__(self, x):
self.x = x
def instance_method(self, y):
return self.x + y
m0 = MyClass4(6)
result = m0.instance_method(2)
print(result)
(3).类属性
向类中添加数据,获取与设置直接通过类名。
注意事项:通过实例可以获取类属性(不推荐);通过实例不可以设置类属性
python
class MyClass2:
class_attribute = 10
print(MyClass1.class_attribute)
(4).类方法
第一个形参一般是cls;带有装饰器classmethod,将第一个形参编程类名。
目的:为了获取类相关信息(类名、父类、类注释)
实例可以获取类方法(不推荐)
python
class MyClass1:
class_attribute = 10
@classmethod
def class_method(cls, multiplier):
return cls.class_attribute * multiplier
result = MyClass1.class_method(6)
print(result)
(5).静态方法
没有特殊形参,有装饰器staticmethod将方法升级为静态方法,通过类名调用,实例可以访问(不推荐),项目的辅助类一般都会使用静态方法。
python
class MyClass:
@staticmethod
def static_method(x, y):
return x + y
result = MyClass.static_method(2, 6)
print(result)
2.抽象类
一个特殊的类:内部可以编写抽象方法,抽象类不能直接实例化,也可以编写普通实例方法。子类继承抽象类,必须实现抽象类的抽象方法。
python
"""
抽象类:不直接实例化 通过子类来产生实例
"""
from abc import ABC, abstractmethod
class Animal(ABC):
"""
抽象类:拥有抽象方法 不能直接实例化
通过装饰器 abstractmethod把walk变为抽象方法
"""
@abstractmethod
def walk(self):
pass
def eat(self):
print("c")
# a0 = Animal()
# print(a0, isinstance(a0, Animal))
class Dog(Animal):
"""
抽象类子类: 必须实现抽象类中的抽象方法
"""
def walk(self):
print("ywb")
dog = Dog()
dog.eat()
dog.walk()
print(isinstance(dog, Dog), isinstance(dog, Animal))
class Cat(Animal):
def walk(self):
print("sxt")
cat = Cat()
cat.eat()
print(isinstance(cat, Cat), isinstance(cat, Animal))
3.单例类
只有一个实例
通过控制构造函数判定是否需要从新生成实例:第一次,生成,放入类属性;以后,返回第一次生成的实例。
python
class Manage(object):
instance = None
def __new__(cls, *args, **kwargs):
"""
对构造函数进行控制 不是每次都生成新的实例
1、对类属性instance判断 如果不为空 则直接把他返回
2、对类属性instance判断 如果为空 就构造一个实例 并且把实例赋予instance
:param args:
:param kwargs:
"""
if not Manage.instance:
Manage.instance = super().__new__(cls)
return Manage.instance
def __init__(self):
"""
初始化函数 初始化实例 向self中添加内容
"""
print("初始化函数执行")
m1 = Manage()
m2 = Manage()
print(m1 is m2, m1 is None, m2 is None)
class Manage:
def __new__(cls, *args, **kwargs):
if not hasattr(Manage, "instance"):
obj = super().__new__(cls)
setattr(Manage, "instance", obj)
return getattr(Manage, "instance")
m3 = Manage()
m4 = Manage()
print(m3 is m4)
三、构造函数与析构函数
1.构造函数:
用于创建实例( self ),返回实例,通过父类来创建实例【super().new()】。
2.析构函数:实例不在使用,销毁之前执行。
python
"""
构造函数:创建并且返回实例(self)
初始化函数:self已经创建完成,可以向self中添加数据
析构函数:销毁实例 清理实例内存 实例不再使用则回收实例内存之前会执行对应的析构函数
"""
class MyClass:
def __new__(cls, *args, **kwargs):
# 调用父类的new方法创建一个实例
instance = super().__new__(cls)
print(f"构造函数", id(instance))
# 将创建好的实例返回 返回给初始化函数
return instance
def __init__(self, name):
print(f"初始化函数", id(self))
self.name = name
mc0 = MyClass("xk")
print(id(mc0), mc0 is None)
class MyOpen:
def __init__(self, filename, mode="r", encoding="utf8"):
self.f = open(filename, mode=mode, encoding=encoding)
def read_all(self):
return self.f.read()
def __del__(self):
self.f.close()
m0 = MyOpen("./53.魔法函数.py")
print(m0.read_all())
四、属性封装与操作
口头称呼:类封装数据与操作,属性与行为;类属性,实例属性,公有属性,私有属性,保护属性。
property:fget,获取触发,@property;fset:设置触发,@属性名.setter;装饰器。
1. 属性封装:
python
class Person:
def __init__(self, name, age, sex, height):
self.__name = name
self.age = age
self.__sex = sex
self.__height = height
# 将指数变为函数
@property
def height(self):
return self.__height
# 指明属性的setter
@height.setter
def height(self, height):
self.__height = height
def get_name(self):
return self.__name
def set_name(self, name):
if 1 <= len(name) <= 4:
self.__name = name
else:
print("bhf")
def __get_sex(self):
print("发现你在获取")
"""当获取属性时 会触发"""
return self.__sex
def __set_sex(self, sex):
print("发现你在获取")
"""当获取属性时 会触发"""
if sex in ["男", "女"]:
self.__sex = sex
else:
print("输入不合法")
sex = property(__get_sex, __set_sex)
# 封装真正属性 拥有get与set方法
p0 = Person("x", 2000, "n", 190)
# 获取设置age 直接使用 (容易产生不合法数据)
print(p0.age)
p0.age = -6
print(p0.age)
# 获取设置name 需要通过函数 可以保证数据安全
print(p0.get_name())
p0.set_name("k")
print(p0.get_name())
print(p0.sex)
p0.sex = "nan"
print(p0.sex)
print(p0.height)
p0.height = 185
print(p0.height)
2.属性操作:
python
"""
todo 属性 attribute
delattr: delattr(对象,"属性名") 返回布尔值
getattr: getattr(对象,"属性名") 返回属性值
hasattr: hasattr(对象,"属性名") 返回布尔值
setattr: setattr(对象,"属性名",属性值)
"""
import types
class Person:
pass
p = Person()
p.name = "x"
Person.MAX_AGE = 2000
print(hasattr(p, "name"), hasattr(p, "MAX_AGE"))
print(hasattr(Person, "MAX_AGE"))
p.get_name = types.MethodType(lambda self: self.name, p)
@classmethod
def info(cls):
return cls.__name__
Person.info = info
@staticmethod
def my_max(a, b):
return a if a > b else b
Person.my_max = my_max
print(hasattr(p, "get_name"), hasattr(p, "info"), hasattr(Person, "info"), hasattr(Person, "my_max"))
if hasattr(p, "get_name"):
value = getattr(p, "get_name")
print(f"属性值为:{value()}")
if hasattr(p, "age"):
pass
else:
print("未发现属性age")
setattr(p, "age", 2000)
if hasattr(p, "age"):
print("设置成功后的age值为", getattr(p, "age"))
delattr(p, "age")
if not hasattr(p, "age"):
print("删除成功")
五、Python是一门解释性语言
可以向类中动态添加内容。
添加实例属性:实例名.属性名=值;
添加实例方法:实例名.实例方法=types.MethodType(原始方法名, 实例),原始方法第一个参数是self;
添加类属性:向类中添加类属性 类可以正常访问 所有实例均可访问。
添加类方法:向类中添加类方法 方法格式符合类方法格式 类与所有实例均可访问。
添加静态方法:向类中添加静态方法 方法要符合静态方法格式 类与实例均可访问。
python
import types
class Person:
pass
p0 = Person()
p = Person()
# 向实例中添加实例数据 其他实例无影响
p.name = "张飞"
print(p.name)
def my_set_name(self, name):
self.name = name
# 向实例中添加实例数据 其他实例无影响
p.set_name = types.MethodType(my_set_name, p)
p.set_name("赵云")
print(p.name)
# 向类中添加类属性 类可以正常访问 所有实例均可访问
Person.MAX_AGE = 120
print(Person.MAX_AGE, p.MAX_AGE, p0.MAX_AGE)
@classmethod
def my_info(cls):
print(cls.__bases__)
# 向类中添加类方法 方法格式符合类方法格式 类与所有实例均可访问
Person.info = my_info
Person.info()
p0.info()
p.info()
#
@staticmethod
def my_max(x, y):
return x if x > y else y
# 向类中添加静态方法 方法要符合静态方法格式 类与实例均可访问
Person.max = my_max
print(Person.max(10, 20), p.max(50, 100), p0.max(200, 500))
六、数据的访问级别
1.公有类型:public,普通名字,类内和类外,子类都可以使用。
2.私有类型:private,以 _ _开头,只能在类内访问。
3.保护类型:protect,以 _ 开头,在类内可以访问,在子类可以访问,在类外、可以 强制访问。
python
"""
公有类型:public 普通名字 类内与类外、子类都可以使用
私有类型:private 以__开头 只能在类内访问
保护类型:protect 以_开头 在类内可以访问 在子类可以访问 在类外可以强制访问
"""
class MyClass:
def __init__(self, name, __age, _sex):
self.name = name
self.__age = __age
self._sex = _sex
def get_age(self):
return self.__age
def set_age(self, __age):
self.__age = __age
def get_sex(self):
return self._sex
def set_sex(self, _sex):
self._sex = _sex
def get_name(self):
return self.name
def set_name(self, name):
self.name = name
def __str__(self):
return f"name:{self.name} age:{self.__age} sex:{self._sex}"
m0 = MyClass("x", 2000, "n")
print(m0)
m0.set_name("kk")
print(m0.get_name())
m0.set_age(10000)
print(m0.get_age())
m0.set_sex("n")
print(m0.get_sex())
m0.set_name("sz")
print(m0.get_name())
m0.set_sex("nv")
print(m0.get_sex())
m0.set_age(1000)
print(m0.get_age())
Python 中的面向对象编程为程序员提供了一种结构化的方法来组织和管理代码,通过类和对象可以更好地模拟现实世界的复杂性,并提供了更灵活和可扩展的代码结构。