赞
踩
封装(encapsulation)就是把抽象出的数据[属性]和对数据的造作[方法]封装在一起,数据保护在内部。
程序只有通过被授权的操作,才能对数据进行访问。
优点:隐藏实现细节、可以对数据进行验证(直接访问赋异常值被攻击)、保护数据隐私。
默认情况下,类中的变量和方法都是共有的,在类的外部、类的内部都可以正常访问
私有化:将变量或方法以__
开头,只能在本类内部使用,类的外部无法使用
如何访问私有属性/方法:提供公共的方法,用于对私有成员的操作
class Clerk: name = None __job = None __salary = None def __init__(self, name, job, salary): self.name = name self.__job = job self.__salary =salary def set_job(self, job): self.__job = job def get_job(self): return self.__job clerk = Clerk("tiger", "python工程师", 20000) clerk.__job = "java工程师" 动态创建__job属性 print(clerk.name) #tiger print(cler.__job) #伪私有属性 python工程师 print(clerk.get_job) #java工程师 debug可以看出实际属性是 _Clerk__job
继承可以解决代码复用,并让编程更加靠近人类思维。当多个类存在相同的属性(成员变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有子类无需重新定义。父类/基类-子类/派生类。
class DrivedClassName(BaseClassName[, Base2, Base3...]):
statements
object
是所有其它类的基类,通过ctrl+H
可以查看类的继承关系如果子类和父类出现同名成员,访问父类成员的方式:
父类名.成员变量
父类名.成员方法(self) #需要把自己传过去
super().成员变量
super().成员方法()
super()
的方式,因为如果使用父类名方式,一旦父类名修改,调用也需修改class A: n1 = 100 def run(self): print("A-run()...") class B: n1 = 100 def run(self): print("B-run()...") def say(self): print(f"父类的n1{A.n1} 本类的n1{self.n1}") # self.属性名 先在本类找,若无去父类找 A.run() self.run() # self.方法名()先在本类找,若无去父类找 def hi(self): print("父类的n1 {super().n1}") super().run()
重写又称覆盖(override),即子类继承父类的属性和方法后,根据业务需要,再重新定义同名的属性或方法。鼠标停留在重写代码行左边的环形图标可看到提示
忘记方法参数类型,python是解释型语言,只有运行时才能发现问题,因此需要对类型提示的支持。
· 类型提示,防止运行时出现参数类型、返回值类型、变量类型不符合。
· 作为开发文档附加说明,方便使用者调用时传入和返回参数类型。
· 加入后并不会影响程序的运行,不会报正式的错误,只有提醒。
· PyCharm支持类型注解,参数类型错误会给黄色三角感叹号提示。
def f(a: str):
for i in str:
print(i)
变量: 类型 # 变量类型注解
实例对象: 类型(类名) # 实例对象类型注解,注解父类即可使用子类
my_list: list = [1, 2, 3] #容器类型注解
my_tuple: tuple[str, float] = ["jack", 0.1]
my_set: set[str] = {"jack", "tom"}
my_dict: dict[str, int] = ["no1":1, "no2":2]
# 在注释中使用注解
代码 # type:类型
def 函数/方法名(形参名:类型, 形参名:类型...) -> 返回值类型:
函数/方法体
联合类型 Union[type1, type2, ...]
等价于 type1 | type2 | ...
,意味着满足几个类型之一即可。在变量、函数(方法)都可以使用联合类型注解。使用时需先导入from typing import Union
需求引入:
class Food: # 父类食物 name = None def __init__(self, name): self.name = name class Fish(Food): # 食物子类鱼类 pass class Animal: #父类动物 name = None def __init__(self, name) self.name = name class Cat(Animal): #动物子类猫 pass class Master: # 主人类 name = None def __init__(self, name): self.name = name # 问题: 每次扩展需增加动物子类、食物子类、主人喂食方法 def feed_cat(self, cat: Cat, fish: Fish): print(f"主人{self.name}给动物{cat.name}喂的食物是{fish.name}") cat = Cat("Bosi") fish = Fish("liyu") xiaoming = Master(xiaoming) xiaoming.feed_cat(cat, fish)
多态:不同的对象调用相同的方法,表现出不同的状态,通常作用在继承关系上
例如:一个父类具有多个子类,不同的子类对象调用相同的方法,执行的时候产生不同的状态(类型)
优点:灵活,无论对象变化,同一种形式调用;扩展性,通过继承创建新类,再调用,无需改原代码(业务执行操作)
· Python中函数/方法的参数是没有类型限制的,所以多态在python中体现并不是很严谨(相对java等强类型语言);
· python并不要求严格的继承体系,关注的不是对象的类型本身,而是它是否具有要调用的方法(行为)
class AA:
def hi(self):
print("AA-hi()...")
class BB:
def hi(self):
print("BB-hi()...")
def test(obj): # 根据传入参数动态决定类型
obj.hi()
aa = AA()
bb = BB()
test(aa) # AA-hi()... #无继承关系,仅关注调用方法
test(bb) # BB-hi()... #不同对象调用同一方法表现不同的状态
需求问题解决
class Master: # 主人类
name = None
def __init__(self, name):
self.name = name
# 解决: 每次扩展仅需增加动物子类、食物子类
def feed(self, animal: Animal, food: Food):
print(f"主人{self.name}给动物{animal.name}喂的食物是{food.name}")
# 不同的主人对象调用同一方法,传入不同类型的参数,返回不同状态类型
cat = Cat("Bosi")
fish = Fish("liyu")
xiaoming = Master(xiaoming)
xiaoming.feed(cat, fish)
isinstance()
用于判断对象是否为某个类或其子类的函数
isinstance(object, classinfo) # object对象 是不是 classinfo(类名、基本类型或由它们组成的元组) 的(元组中某个)类或子类
num = 9
print(f"num是不是str/int/list: {isinstance(num, (str, int. list))}")
魔术方法:Python中所有以双下划线__
包起来的方法。
魔术方法是一种特殊方法,普通方法需要调用,魔术方法在类或对象的某些事件发生时会自动执行,如果希望根据自己的程序定制特殊功能的类,就需要对这些方法进行重写
python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的
__str__
打印对象默认返回:类型名+对象内存地址,默认情况下返回对象的属性信息。
<__main__.Person object at 0x0000019314BC7C90> # 类型Person 当前对象地址(10进制内存地址的16进制形式表达,同hex(id(my_obj)) ), 实际是父类object的__str__方法
实际开发中往往重写__str__
方法,print(对象)或str(对象)时,都会自动调用该对象的__str__
方法。
class Monster:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def __str__(self):
return f"{self.name} {self.age} {self.gender}"
m = Monster("青牛怪", 500, '男')
print(m)
__eq__
== 是一个比较运算符:对象之间进行比较时,比较的是内存地址是否相等,即判断是不是同一个对象
重写 __eq__
方法,可以用于判断对象内容/属性是否相等
class Person: def __init__(self): self.name = name self.age = age self.sex = sex # def __eq__(self, other): #p1 == p2 true #if isinstance(other, Person): #否则不同类属性相同也会判断true # return self.name == other.name and \ # self.age == other.age and \ # self.sex == other.age #else: # return False p1 = Person("smith", 20, "男") p2 = Person("smith", 20, "男") print(f"p1==p2: {p1 == p2}") # false 对象地址不同,属性地址相同
类本身也是对象,即:Class对象(万物皆对象)。可以通过未实例化的类对象访问属性、调用非静态方法className.func(className)。
装饰器@staticmethod
将方法转为静态方法,静态方法不会接收隐式的第一个参数self,声明静态方法的语法如下。
class C:
@staticmethod
def f(arg1, arg2...):...
静态方法可以有类调用C.f()
,也可以有实例调用C().f()
(匿名实例):
class Monster
@staticmethod
def ok():
print("ok()...")
Nonster.ok() #不需要实例化,通过类调用静态方法
# 通过实例对象调用静态方法
monster = Monster()
monster.ok()
需求:当父类的某些方法需要声明,但又不确定如何实现;不需要实例化父类对象,父类主要用于设计和制订规范,让其它类来继承并实现。
介绍:默认情况下python不提供抽象类,python附带一个为定义抽象类提供基础的模块abc。
from abc import ABC
),并且需要至少一个用@abstractmethod
声明的抽象方法,抽象类不能实例化。设计模式:在大量实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
模板设计模式:抽象类作为多个子类的通用模板
e.g:计算工作时间
使用设计模式前:
class AA: def job(self): start = time.time() num = 0 for i in range(1, 800001): num += 1 end = time.time() print("计算任务执行时间:", (end - start)) class BB: def job(self): start = time.time() #epoch所有平台上都是1970-01-01 00:00:00 (UTC) num = 0 for i in range(1, 900001): num -= 1 end = time.time() print("计算任务执行时间:", (end - start)) if __name__ == '__main__': aa = AA() aa.job() bb = BB() bb.job
使用设计模式后:
class Template(ABC): @abstractmethod def job(self): pass def cal_time(self): start = time.time() self.job() end = time.time() print("计算任务执行时间:", (end - start)) class CC(Template): def job(self): num = 0 for i in range(1, 800001): num += 1 if __name__ == '__main__': cc = CC() cc.cal_time() #从父类继承下的方法
顶层环境判断__name__ == '__main__'
:当一个 Python 模块或包被导入时,name 被设为模块的名称——通常为 Python 文件本身的名称去掉 .py 后;而若模块是在顶层代码环境(程序运行入口)中执行的,则其 name 被设为字符串 ‘main’。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。