目录
-
类
类也是一个对象,内部包括了方法(函数)和属性(变量)
类的创建
# 定义一个类
class Student: # 类的首字母一般大写,多个单词使用驼峰结构,如 GoodStudent
def __init__(self, name, score): # 注意这里是 init 、 双下划线!!!
self.name = name
self.score = score
def print_student(self):
print("{0}的分数是: {1}".format(self.name, self.score))
s1 = Student("Lu", 75)
s1.print_student()
print(dir(Student)) # 查看对象的属性和方法
print(s1.__dict__) # 查看对象的字典
print(isinstance(s1, Student)) # 判断 s1 是不是 Student 类型
--------------------------------------------------
Lu的分数是: 75
['__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__', 'print_student']
{'name': 'Lu', 'score': 75}
True
--------------------------------------------------
构造函数 __init__()
1. 函数名称固定,必须是 __init__
2. 第一个参数必须是 self
3. 用来初始化实例对象,即初始化对象的各属性(如上方的 name 和 score),没有返回值
4. 通过 类名(参数列表) 调用构造函数
虽然说没有返回值,实际上已经把将创建好的对象返回给变量(如上方的 Lu,75,返回给了 s1)
5. 包括了两个过程
(1)__new__() 创建一个新的对象(忽略,编程时无需定义)
(2)__init__() 初始化对象的各属性
实例对象和类对象
class Student:
company = 'XX' # 类属性,从属于类对象 Student
count = 0 # 类属性
def __init__(self, name, score):
self.name = name # 实例属性,从属于实例对象 self
self.score = score # 实例属性
Student.count += 1
def print_student(self): # 实例方法
pass # 表示一个空语句
@classmethod # 声明定义类方法
def pp(cls): # 括号里面要加 cls
pass
s1 = Student("Lu", 75)
s1.print_student()
# 从属于那个对象,就可以被对象内部共享
调用过程
堆的左边实例对象,堆的右边类对象。
1. 实例对象中不包括类方法
2. 类对象中的 print_student 是实例方法,类对象中只是保存了代码,以便调用
静态方法
用于在类里面定义和类完全无关的方法,可以通过类名去访问
@staticmethod # 装饰器声明
def ppp(a, b): # a b 为形参
pass
静态方法和类方法不能调用实例参数实例方法!!!否则会报错
把类对象比作一个模具,我们只能设计花纹,不能使用模具造出来的产品,可能产品还没造出来
__del__(析构函数)和垃圾回收机制
class Person:
def __del__(self): # 重建析构函数(Python自带,这里只是为了测试)
print("销毁对象:{0}".format(self))
p1 = Person()
p2 = Person()
del p2 # 可以通过 del 调用析构函数
print("程序结束")
---------------------------------
销毁对象:<__main__.Person object at 0x004E9F50>
程序结束
销毁对象:<__main__.Person object at 0x004E9CF0>
---------------------------------
Python中的垃圾回收机制:当引用计数为0,即对象没有被引用,垃圾回收器自动调用析构函数进行垃圾回收
__call__ 方法和可调用对象
定义 __call__ 方法的对象,称为可调用对象,即对象可以像函数一样被调用
class Test:
def __call__(self, salary):
yearsalary = salary * 12
daysalary = salary // 30
return dict(yearsalary=yearsalary, monthsalary=salary, daysalary=daysalary)
a = Test()
print(a(24000)) # 将对象像函数一样调用
-------------------------------------
{'yearsalary': 288000, 'monthsalary': 24000, 'daysalary': 800}
-------------------------------------
Python中方法没有重载
即不要定义重名的方法(其他一些语言可以),如果重名,前面的会被后面的覆盖
方法的动态性
为类添加新方法,修改方法
但是,对于最原始的模具不会变!!!
# 万物皆对象
class Life:
def work(self):
print("day day up")
def study():
print("study day day up!")
def work2():
print("work day day up!")
p = Life()
p.work() # 下面的修改全是针对 p 这个对象
p.study = study # 增加了 study 方法
p.study()
p.work = work2 # 修改 work 方法为 work2 方法
p.work()
p2 = Life() # 注意,这里的类是不变的!!!
p2.work()
--------------------------------
day day up
study day day up!
work day day up!
day day up
--------------------------------
-
面向对象的三特征(封装、继承、多态)
私有属性和私有方法(封装)
通常约定,双下划线开头的属性(方法)是私有的
在私有属性所属类的内部可以直接访问,类的外部不能直接访问,可以通过 _类名__私有属性名 (前面是单下划线)
class Student:
def __init__(self, name, age):
self.name = name
self.__age = age # 私有属性
def __work(self):
print("aaaaa!") # 私有方法
print(self.__age) # 在类的内部可以直接调用,相当于自己人用自己家东西
s1 = Student("Lu", 25)
print( s1._Student__age ) # 私有属性的访问
s1._Student__work() # 私有方法的调用
@property 装饰器
将方法变成属性
# 原始办法
class Student:
def __init__(self, name, salary):
self.__name = name
self.__salary = salary
def get_salary(self):
return self.__salary
def set_salary(self, salary):
if 1000<salary<50000:
self.__salary = salary
else:
print("Your input is wrong!")
s1 = Student("Lu", 3000)
print(s1.get_salary()) # 这里还是用的方法
s1.set_salary(4000)
print(s1.get_salary())
# 使用 property 修饰器
class Student:
def __init__(self, name, salary):
self.__name = name
self.__salary = salary
@property # 装饰器
def salary(self):
return self.__salary
@salary.setter # 装饰器
def salary(self, salary):
if 1000<salary<50000:
self.__salary = salary
else:
print("Your input is wrong!")
s1 = Student("Lu", 3000)
print(s1.salary) # 变成属性
s1.salary = 4000
print(s1.salary)
继承
子类(派生类)继承父类(基类)的特征,实现代码复用,更好地实现拓展
Python 中可以继承多个直接父类
没有指定父类,默认 object 类(所有类的父类)
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age # 私有属性
def print_age(self):
print(self.__age)
class Student(Person): # 继承,括号中是父类
def __init__(self, name, age, score):
Person.__init__(self, name, age) # 继承父类的用法
self.score = score
s = Student("Lu", 25, 75)
s.print_age()
print(dir(s)) # 显示 s 的所有属性
print(s._Person__age) # print(s.age) 报错,子类可以继承私有属性,但是不能直接查看
-----------------------------------------
25
['_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__', 'name', 'print_age', 'score']
25
-----------------------------------------
方法的重写
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_age(self): # 对该方法重写
print(self.age)
class Student(Person):
def __init__(self, name, age, score):
Person.__init__(self, name, age)
self.score = score
def print_age(self): # 重写
'''重写父类中的代码'''
print("My age is", self.age)
s = Student("Lu", 25, 75)
s.print_age()
-------------------------
My age is 25
-------------------------
查看类的层次
class A:
pass
class B(A):
pass
class C(B):
pass
print(C.mro()) # 查看类的层次
------------------------------------
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
------------------------------------
object 根类
使用 dir() 查看所有的属性!!!
方法也是属性!!!
特殊属性
class A:
pass
class B:
pass
class C(B, A):
def __init__(self, name):
self.name = name
c = C("Lu")
print(dir(c))
print(c.__dict__) # 对象的属性字典
print(c.__class__) # 对象所属的类
print(C.__bases__) # 类的基类元组
print(C.__base__) # 类的基类
print(C.mro()) # 类的层次结构
print(A.__subclasses__()) # 查看子类的列表
-------------------------------------------------------
['__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__', 'name']
{'name': 'Lu'}
<class '__main__.C'>
(<class '__main__.B'>, <class '__main__.A'>)
<class '__main__.B'>
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
[<class '__main__.C'>]
-------------------------------------------------------
重写特殊方法
只是为了了解本质,一般不需要重写。
每个运算符都对应一个特殊方法,如 + 本质上是 __add__(),运算符也可以重载
class Person:
def __init__(self, name):
self.name = name
def __str__(self): # 改写
return "My name is {0}".format(self.name)
p = Person("Lu")
print(p)
------------------------------------------
My name is Lu
------------------------------------------
多重继承
一般不建议使用
class A:
def aa(self):
print("aa")
class B:
def bb(self):
print("bb")
class C(A, B):
def cc(self):
print("cc")
c = C() # 三个方法全部可以使用
c.aa()
c.bb()
c.cc()
方法解析顺序
class A:
def aa(self):
print("aa")
class B:
def aa(self):
print("bb")
class C(A, B): # 按这里括号内的顺序
pass
class D(B, A): # 按这里括号内的顺序
pass
c = C()
d = D()
c.aa()
d.aa()
------------------------------
aa
bb
------------------------------
当父类中出现相同的方法
直观上:按照括号中的顺序解析
实际上:解析顺序是 mro() 顺序,从左往右
super()
获得父类的定义,但不是父类的对象(可以理解为获得父类的代码)
class A:
def say(self):
print(self)
class B(A):
def say(self): # 注意以下三个语句的区别
A().say() # 调用
A.say(self) # 继承
super().say() # super实现的继承
print(self)
b = B()
b.say()
--------------------------------
<__main__.A object at 0x0249F6B0> # 调用,对象是 A
<__main__.B object at 0x02499CF0>
<__main__.B object at 0x02499CF0>
<__main__.B object at 0x02499CF0>
--------------------------------
多态
同一个方法调用,由于对象不同,产生的行为不同(如张三的休息是睡觉,李四的休息是打游戏)
1. 多态是方法的多态,属性没有多态
2. 多态存在的两个必要条件:继承,方法的重写
class Man:
def eat(self):
print("吃饭")
class Chinese(Man):
def eat(self):
print("中国人用筷子吃饭")
class American(Man):
def eat(self):
print("美国人用叉子吃饭")
def maneat(m):
if isinstance(m, Man):
m.eat()
else:
print("不能吃饭")
maneat(Chinese())
maneat(American())
组合(获得其他类中方法的另一种方式)
区别不同的结构,使用组合与继承
继承:动物,猫是一个动物
组合:屏幕,手机有一个屏幕
class Mobilephone:
def __init__(self, cpu, screen):
self.cpu = cpu
self.screen = screen
class CPU:
def say(self):
print("980")
class SCREEN:
def say1(self):
print("daxingxing")
a = Mobilephone(CPU(), SCREEN())
a.cpu.say()
a.screen.say1()
#################################################
980
daxingxing
#################################################