标签:初步 大型软件 静态 stat 单词 mamicode sel mat python
1. 注意: Python支持 (1)面向过程 (2)面向对象 (3) 函数式编程等多种编程范式
2. 面向对象编程的思想主要是针对大型软件设计而来的. 面向对象编程使得程序的扩展性更强,可读性更好,使得编程可以像搭积木一样简单.
3. 面向对象编程将数据和操作数据相关的方法封装到对象中,组织到吗和数据的方式更加接尽人的思维,从而大大提高了编程的效率.
4. Python完全采用了面向对象的思想,是真正面向对象的编程语言,完全支持面向对象的基本功能,例如: (1)继承(2)多态(3)封装等. Python中一切都是对象,我们前面学习的(1)数据类型(2)函数都是对象.
1. 面向过程编程更加关注的是"程序的逻辑流程",是一种"执行者"思维,适合编写小规模的程序.
(1) 面向过程思考方式 => 完成这件事情的步骤是(1.... 2... 3...)
2. 面向对象更加关注的是"软件中对象之间的关系",是一种"设计者"思维,适合编写大规模的程序.
(1) 面向对象思考方式 => 完成这件事情需要由哪些对象来配合(需要调用哪些类)
3. 解决简单问题使用面向过程; 解决复杂问题: 宏观上是以哦那个面向对象把握,微观处理上仍然是面向过程. (一个优秀的软件设计师必然从程序员干起,底层的实现细节肯定也是十分了解)
1. Python中,"一切皆对象". 类也成为"类对象",类的实例也称为"实例对象".
2. 定义类的语法
class 类名:
类体
3. 定义类的要点:
(1) 类名必须符合"标识符"的规则,规定首字母大写,多个单词采用"驼峰原则".
(2) 类体中我们可以定义属性和方法
(3) 属性(变量)用来描述数据,方法(即函数)用来描述这些数据相关的操作.
# code01_一个典型类的定义.py
class Student:
def __init__(self, name: str, score: int) -> None: # 注意: self参数必须位于第一位
self.name = name
self.score = score
def say_score(self)->None: # 注意: self参数必须位于第一位
print("{0}的分数为:{1}".format(self.name, self.score))
def main():
# 解释器会默认把s1的地址传递给参数self
s1 = Student("rowry", 98) # 类名() 调用构造方法
s1.say_score() # 调用对象的方法
if __name__ == "__main__":
main()
__init__
构造方法和__new__
方法__init__()
的要点如下:
1. 名称固定,必须为 __init__().
2. 第一个参数固定(类中的方法第一参数都必须为self),必须为self.
(1)self指的就是刚刚创建好的实例对象(的内存地址).
(2) Python中的self相当于C++中的self指针, Java和C#中的this关键字.
(3) Python中self必须为构造参数的第一个参数,名字可以任意修改,但是一般遵守惯例,都叫做self.
3. 构造函数通常用来初始化实例化对象的实例属性(变量) => 给属性赋初值
def __init__(self,name,score):
self.name = name
self.score = score
4. 通过"类名(参数)"来调用构造函数(__init__). 解释器创建创建好对象后将对象的内存地址返回给相应的变量.
(1) 比如: s1 = Student("rowry",98)
5. __init__(self) 用于初始化创建好的对象. 初始化的意思是 "给实例属性赋值".
6. __new__(self) 用于创建对象. 一般是不需要重定义该方法的,知道有这个方法即可.
7. 如果我们不定义__init__(self)方法,系统会提供一个默认的无参__init__(self),如果我们定义了带参数的__init__(self),系统不创建默认的__init__(self).
实例属性
实例属性(变量)是从属于实例对象的属性,也称为"实例变量". 他的使用有如下几个要点:
1. 实例属性一般在 __init__() 中通过如下代码定义: self.实例属性名 = 初始值
2. 在本例的其他实例方法中,也是通过self进行访问: self.实例属性名
3. 创建实例对象后,通过实例对象访问:
obj01 = 类名() # 创建对象,调用__init__() 初始化属性
obj01.实例属性名 = 值 # 可以给已有属性赋值,也可以新加属性
实例方法
实例方法只是一个指向,并不是重新在定义一个方法没有必要
实例方法是从属于实例对象的方法.
1. 实例方法定义
def 方法名(self,[,形参列表]):
函数体
2. 实例方法调用: 对象.方法名([实参列表])
3. 要点
(1) 定义实例方法时,第一个参数必须为self,和前面一样,self指当前的实例对象.
(2) 调用实例方法时,不需要也不能给self传参. self由解释器自动传参.
4. 函数和方法的区别
(1) 都是用来完成一个功能的语句块,本质一样.
(2) 方法调用时,通过对象来调用. 方法从属于特定实例对象,普通函数没有这个特点.
(3) 直观上看,方法定义时需要传递self,函数不需要
5. 实例对象的实例方法调用本质
(1) 对象.实例方法() <=> 类名.实例方法(对象)
(2) 一般我们使用前者进行调用,然后解释器会将前者翻译为后者
6. 其他操作
(1) dir(对象)可以获得对象的所有属性,方法
(2) 对象.__dict__ 对象的属性字典, 获得自定义的对象属性变量字典
(3) pass 空语句
(4) isinstance(对象,类[型]) 判断"对象"是不是"指定类型"
# code02_实例属性和实例方法.py
class Student:
def __init__(self, name: str, score: int) -> None: # 注意: self参数必须位于第一位
self.name = name
self.score = score
def say_score(self) -> None: # 注意: self参数必须位于第一位
self.xxx = "xxx" # 动态新增的实例属性
print("{0}的分数为:{1} test新增实例属性{2}".format(self.name, self.score, self.xxx))
def main():
# 解释器会默认把s1的地址传递给参数self
s1 = Student("rowry", 98) # 类名() 调用构造方法
s1.say_score() # 调用对象的方法
# Python对象可以动态添加属性(变量)
s1.age = 18
s1.salary = 3000
s1.abs = abs # 其实是一样的,只是新增加了一个实例属性变量,这个变量指向abs函数
print(f"{s1.name}的年龄:{s1.age},工资:{s1.salary}")
# 重新用该类创建创建的对象是没有s1新增加的属性的
s2 = Student("张三", 60) # 是没有 age 和 salary 的
# 实例方法的本质
# 对象.方法名() <=> 类名.方法名(对象)
s2.say_score()
Student.say_score(s2)
# dir(对象) 查看对象的所有属性和方法
print(dir(s1))
print(dir(s2))
# 对象.__dict__ 对象的属性字典(自定义的属性)
print(s1.__dict__)
print(s2.__dict__)
# isinstance(对象,类型) 判断给对象是不是该类型的实例
print(isinstance(s1, Student))
if __name__ == "__main__":
main()
类对象
1. 我们签名将类定义格式中, "class 类名: ". 实际上,当解释器执行class语句时,就会创建一个类对象 (类本身就是一个对象, 是 type 类型的对象)
# code03_类对象的生成.py
class Student:
pass
def main():
print(type(Student)) # 所有自定义类都是type类型
print(id(Student)) # 已经有Student这个对象了,执行class时候就自动创建Student这个类对象
s1 = Student() # 现在相当于调用 __init__ 和 __new__
# 下面这种方式应该更加帮助理解类对象
stu = Student
s2 = stu()
if __name__ == "__main__":
main()
类属性
1. 类属性是从属于"类对象"的属性,也称为"类变量". 由于类属性从归属于类对象,可以被所有实例对象共享.
2. 类属性的定义方式:
class 类名:
类变量名 = 初始值
3. 在类中或者类的外部,可以通过"类名.类变量名"来进行读写
# code04_类属性.py
class Student:
company = "ByteDance" # 类属性
count = 0 # 类属性
def __init__(self, name, score):
self.name = name # 实例属性
self.score = score # 实例属性
Student.count += 1 # 使用类属性
def say_score(self): # 实例方法
print("我的公司是:", Student.company)
print(f"{self.name}的分数是:{self.score}")
def main():
s1 = Student("张三", 80)
s1.say_score()
s2 = Student("李四", 85)
s2.say_score()
print("一共创建{0}个Student对象".format(Student.count))
if __name__ == "__main__":
main()
类方法
1. 类方法是从属于"类对象"的方法. 类方法通过装饰器@classmethod来定义,格式如下:
@classmethod
def 类方法名(cls,[,形参列表]):
函数体
2. 类方法的要点:
(1) @classmethod必须位于方法上面一行
(2) 第一个cls参数必须有; cls指的是"类对象"本身,与self用法一致 (可以改名,但是一般不改)
(3) 调用类方法格式: "类名.类方法名(参数列表)". 参数列表中,不需要也不能给cls传值.
(4) 类方法中访问实例属性和实例方法会导致错误(类创建了,对象还没有创建,当然不能使用实例属性和实例方法)
(5) 子类继承父类方法是,传入cls是子类对象,而非父类对象.
# code05_类方法.py
class Student:
company = "ByteDance"
@classmethod
def print_company(cls): # 类方法第一个参数必须为cls
print(cls.company)
def main():
Student.print_company() # 直接运行类方法即可(class 已经创建了这个对象了)
if __name__ == "__main__":
main()
静态方法
1. Python中允许定义与"类对象"无关的方法,称为"静态方法".
2. "静态方法"和模块中定义普通函数没有区别,只不过"静态方法"放到了"类的名字空间里面",需要通过"类调用".
3. 静态放啊通过装饰器@staticmethod来定义,格式如下:
@staticmethod
def 静态方法名([形参列表]):
函数体
4. 静态方法要点:
(1) @staticmethod必须位于方法上面一行
(2) 调用静态方法格式: "类名.静态方法名(参数列表)"
(3) 静态方法中访问实例属性和实例方法会导致错误(需要传递self,但是还没有self呢)
# code06_静态方法.py
class Student:
company = "ByteDance"
@staticmethod
def add(a, b) -> None: # 静态方法(一般是不操作类属性的)
print("{0}+{1}={2}".format(a, b, (a + b)))
def main():
Student.add(10, 20) # 调用类的静态方法
if __name__ == "__main__":
main()
__del__
方法(析构函数)和垃圾回收机制1. 在创建对象时,系统会自动调用__init__(),在对象被清理时,系统也会自动调用一个__del__(),这个方法就是析构函数.
2. Python实现自动的垃圾回收,当对象没有被引用时(引用计数为0),由垃圾回收器调用__del__().
3. 我们也可以通过del关键字,手动调用__del__().
4. 系统会自动提供__del__(),一般不需要自定义析构方法.
# code07_析构方法.py
class Person:
def __del__(self):
print("销毁对象:", self)
def main():
p1 = Person()
p2 = Person()
del p2 # 手动触发__del__()
print("程序结束") # 程序结束收p1也会被自动回收
if __name__ == "__main__":
main()
__call__
方法和可调用对象对象() 实际上调用的是对象的 call()
定义了 call() 的对象,称为"可调用对象",即该对象可以像函数一样被调用. (函数本身也是一个对象)
# code08_可调用对象.py
class SalaryAccount:
def __call__(self, salary):
print("算工资啦...")
yearSalary = salary * 12
return f"年薪为:{yearSalary}"
def main():
s = SalaryAccount()
print(s(3000)) # 对象() <=> 函数()
if __name__ == "__main__":
main()
Python是没有方法重载的,如果出现同名函数,只保留最后一个(相当于不断的重新给变量赋值)
1. 在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可.
(1) 方法签名包含3个部分 (a)方法名 (b)参数数量 (c)参数类型
2. Python中,方法的参数没有声明类型(调用时确定参数的类型),参数的数量也可以由可变参数控制.因此,Python中式没有方法的重载的. 定义一个方法即可有多种调用方式,相当于实现了其他语言中的方法重载.
3. 如果我们在类体中定义了多个重名的方法,只有最后一个方法有效.
可以动态的修改 类方法,实例方法
本质就是方法也是一个对象,修改其实想到与给 类属性,对象实例属性 重新赋值一个对象引用而已
注意: 理解一下方法本质也是属性,只不过通过()执行 call() 而已
1. Python对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别.
2. 关于私有属性和私有方法,有如下要点:
(1) 通常我们约定,两个下划线开头的属性是私有的(private),其他为公共的(public).
(2) 类内部可以直接访问私有属性和私有方法
(3) 类外部不能直接访问私有属性和私有方法,但是可以间接以 _类名__私有属性 这样进行私有属性的访问(Python解释器的私有属性做的一些小变通)
# code09_私有属性和私有方法.py
class Employee:
__count = 100 # 类变量也是可以私有的
def __init__(self, name, age):
self.__name = name # 定义私有属性
self.__age = age
def __work(self): # 私有方法
pass
def main():
e = Employee("张三", 18)
# 私有属性和私有方法的存储名字
print(e.__dict__) # {‘_Employee__name‘: ‘张三‘, ‘_Employee__age‘: 18}
print(dir(e)) # ‘_Employee__age‘, ‘_Employee__name‘, ‘_Employee__work‘
if __name__ == "__main__":
main()
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查.
1. @property 可以讲一个方法的调用方式变成"属性调用".
2. 对于下面的第一个程序,要修改score,如果使用直接调用属性修改 s.score = 220 首先220是不合法的分数,其次是直接这么修改虽然方便但是非常不安全
3. 使用getter和setter虽然可以安全的修改score,但是不如直接 对象.属性=值 这么修改来的方便,所以 => 既能参数检查,又能类似属性这样简单的方式访问类的变量 <= Python内置的 @property装饰器就是负责把一个方法变成属性调用的.
4. 对getter()上加上@property, 然后会生成 @xxx.setter 这个装饰器
# code10_property装饰器01.py
class Student:
def __init__(self, name: str, score: int):
self.name = name
self.__score = score
# 现在设置一个 setter() 和 getter() 保证数据安全
def get_score(self):
return self.__score
def set_score(self, value: int):
if not isinstance(value, int):
raise ValueError("score must be an integer!")
if value < 0 or value > 100:
raise ValueError("score must between 0~100!")
self.__score = value
def main():
s = Student("张三", 60)
# s.set_score(-20)
s.set_score(20)
print(s.get_score())
if __name__ == "__main__":
main()
# code10_property装饰器02.py
class Student:
def __init__(self, name: str, score: int):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, value: int):
if not isinstance(value, int):
raise ValueError("score must be an integer!")
if value < 0 or value > 100:
raise ValueError("score must between 0~100!")
self.__score = value
def main():
s = Student("张三", 60)
# 把对属性的一个赋值操作(应该使用函数进行判断的) @property简化为直接赋值
# s.score = -20
s.score = 20
print(s.score)
if __name__ == "__main__":
main()
1. _xxx : 保护成员,不能用 from module import * 导入, 只有类对象和子类对象才能访问这些成员.
2. __xxx__ : 系统定义的特殊成员
3. __xxx : 类中的私有成员,只有类对象自己能访问,子类对象也不能访问. (但是私有成员在类外部可以通过 "对象名._类名__xxx"这种特殊方式访问. Python不存在严格意义的私有成员)
1. 类名首字母大写,多个单词之间采用驼峰原则.
2. 实例名,模块名采用小写,多个单词之间采用下划线隔开
3. 每个类,应紧跟"文档字符串",说明这个类的作用
4. 可以使用空行组织代码,但不能滥用. 在类中,使用一个空行隔开方法; 模块中,使用两个空行而开多个类.
标签:初步 大型软件 静态 stat 单词 mamicode sel mat python
原文地址:https://www.cnblogs.com/Rowry/p/12765141.html