类和对象
1.理论上的定义
类:就是拥有相同功能和相同属性的对象的集合(类是抽象的)
对象:类的实例(对象是具体的)
2.从生活的角度
如果说电脑是一个类,我桌上的这台电脑就是一个对象
如果说车是一个类,具体的一辆车就是一个对象
3.编程思想
面向过程编程:以算法为工具
函数式编程:以函数为工具
面向对象编程:以类和对象为工具(面向生活)
封装效果:一个类中可以对多个功能进行封装(多个函数),对多个属性进行封装
类的声明
1.类的声明格式
class 类名(父类列表):
——类的说明文档
——类的内容
2说明:
- class:声明类的关键字
- 类名:标识符,不能是关键字。驼峰式命名(第一个单词首字母小写,其它的单词首字母大写),首字母大写!!!,见名知义
例如:Person、StudentSystem - (父类列表):括号与括号里的内容可以省略,这个是继承语法
- 冒号:固定的
- 类的内容:包括类的方法和类的属性
3.类中的方法
方法:声明在类中的函数
- a.对象方法:对象方法需要对象来调用,对象,函数名()
直接写在类中的方法,自带一个self参数 - b.类方法
- c.静态方法
4.创建对象
创建类的时候,系统会默认给我们创建这个类对应的构造方法
构造方法:类名()–》创建类对应的对象
# 创建一个类
class Person:
'''人类'''
def eat(self):
print('人吃饭')
if __name__ == '__main__':
# 创建对象
p1 = Person() # 创建Person类的对象,并且将对象地址存到p1中
# 一个类可以有多个对象
p2 = Person()
# 只有在调用构造方法的时候才会产生新的对象
p3 = p2
print(id(p1),id(p2),id(p3))
# 2.调用对象
# 通过对象调用对象方法,默认参数self不需要传参,系统自动传参
p1.eat()
构造方法和init方法
1.构造方法:系统自动创建,方法名和类名一样,用来创建对象
2.init:init方法的功能是用来做初始化和添加对象属性的
当我们通过构造方法去创建对象的时候,系统会自动调用init方法(不用主动调用init方法)
class Dog:
def __init__(self):
print('init方法')
class Person:
# init方法可以添加参数
def __init__(self,name,age = 18):
print(name,age)
print('人类的init方法')
if __name__ == '__main__':
# 创建对象的过程:调用构造方法在内存中开辟空间创造一个对象,然后用新建的这个对象去调用init方法,
# 来初始化对象的属性,最后才将对象返回
dog1 = Dog()
dog2 = Dog()
# 如果类的init方法有参数,通过给构造方法传参类init方法传参
p1 = Person('小明')
p2 = Person('小红',20)
p3 = Person(age = 20,name = '东东')
对象属性
类中的内容:属性和方法
1.属性:(保存值的)
- a.对象的属性:不同的对象,对应的值可能不一样,这样的属性就是对象属性属于对象
类中的对象属性是声明在init方法中的,并且声明格式:self.属性名 = 初值
对象属性的使用:对象,属性名 - b.类的字段:属于类的,所有的对象对应的值是一样的
2.方法:(保存功能的)
- a.对象方法
- b.类方法
- c.静态方法
class Student:
'''学生类'''
def __init__(self):
# 声明对象属性name,age,id
self.name = '李青'
self.age = 0
self.id = '001'
class Dog:
'''狗类'''
# 创建Dog的对象的时候,必须传类型和颜色
def __init__(self,type1,color1):
self.type = type1
self.color = color1
class Computer:
'''电脑类'''
# 创建对象的时候可以使用默认值,也可以使用自己传的值
def __init__(self,color= '白色',memory= 0):
self.color = ''
self.memory = 1000
class rectangle:
def __init__(self,long= 100,width= 50):
self.long = long
self.width = width
if __name__ == '__main__':
# stu1就是Student类的对象
stu1 = Student()
# 通过对象去使用对象的属性
print(stu1.name,stu1.age,stu1.id)
# 通过对象去修改对象的属性
stu1.name = 'SB'
print(stu1.name)
dog1 = Dog('土狗','黄色')
print(dog1.type,dog1.color)
dog2 =Dog('斗狗','黑色')
print(dog2.type,dog2.color)
comp1 = Computer()
print(comp1.color,comp1.memory)
comp2 = Computer('黑色',512)
print(comp2.color,comp2.memory)
sq = rectangle()
print(sq.long,sq.width)
sq = rectangle(10,5)
print(sq.long,sq.width)
对象属性的增删改查
Python是动态语言,Python中类的对象的属性可以进行增删的操作
class Person:
'''人类'''
def __init__(self):
self.name = '李四'
self.age = 18
self.height = 160
1.查
方法一:对象.属性
方法二:def getattr(对象,属性名,default=None)
方法三:对象._ getattribute _(‘height’)
print(p1.name)
# print(p1.nmae2) # 属性不存在会报错
print(getattr(p1,'age2',0)) # 属性不存在可以通过设置默认值,让程序不崩溃,并且返回默认值
height = p1.__getattribute__('height')
print(height)
2.改(修改属性的值,属性存在)
方法一:对象.属性 = 新值
p1.name = '张三'
print(p1.name)
方法二:def setattr(对象,属性名,新值)
setattr(p1,'age',20)
print(p1.age)
方法三:对象._ setattr _(属性名,新值)
p1.__setattr__('height',170)
print(p1.height)
3.增(增加属性)
注意:添加只能给某一个对象添加对应的属性
方法一:对象.属性 = 新值
p1.sex = '女'
print(p1.sex)
方法二:def setattr(对象,属性名,新值)
setattr(p1,'weight',55)
print(p1.weight)
方法三:对象.setattr(属性名,新值)
p1.__setattr__('color', '绿色')
print(p1.color)
# print(p2.sex) # 添加只影响一个对象
4.删(删除对象属性)
注意:删除只针对指定的对象
方法一:del 对象.属性
del p1.name
# print(p1.name) 可行
方法二:delattr(对象,属性名)
delattr(p1,'age')
# print(p1.age) 可行
方法三:对象._ delattr _(属性名)
p1.__delattr__('height')
# print(p1.height) 可行
print(p2.name,p2.age)
对象方法
1.对象方法:
- a.什么样的方法是对象方法:直接声明在类里面的函数默认是对象方法,有一个默认参数self
- b.对象方法要通过对象来调用:对象.对象方法()
- c.对象方法中的默认参数self不需要传参,因为在调用这个方法的时候,
系统会自动将当前对象传给self,那个对象调用方法,self就指向谁
import math
class Circle:
'''圆类'''
def __init__(self,radius1):
self.radius = radius1
# 声明了一个对象方法area
# 在这,self就是调用area方法的对象,对象能做的事情,self都可以做
def area(self):
# print(id(self))
# print('求圆的面积')
return math.pi * self.radius **2
- 练习1:写一个矩形类,有属性长和宽,有两个功能,分别是求周长和面积
class Rectangle: '''矩形类''' def __init__(self,long,width): self.long = long self.width =width # 对象方法是否需要额外参数,看实现函数的功能需不需要除了对象属性以外的其他数据 def area(self): return self.long * self.width def perimeter(self): return (self.width + self.long) *2
- 练习2:写一个班级类,班级里面有多个学生的一门成绩,班级名,可以获取班级成绩中的最高分
class Grade: '''班级类''' def __init__(self,class_name,*grade): self.class_name = class_name self.grade = grade # self.grade = [] def top_score(self): # if not self.grade: # return None # max(序列)----》获取序列中元素的最大值 # min (序列)----》获取序列中元素的最小值 return max(self.grade)
`
python
if name == ‘main‘:
c1 = Circle(3)
print(id(c1))
print(‘c1的面积’,c1.area())
c2 = Circle(5)
print('c2的面积', c2.area())
g1 = Grade('python1806',90,80,70)
print(g1.class_name)
print(g1.top_score())
g2 = Rectangle(10,5)
print(g2.area())
print(g2.perimeter())
### 类的字段
1.类的属性叫类的字段
- a.什么是类的字段
类的字段就是声明在类的里面,方法的外面的变量
- b.什么样的属性声明成类的字段:
属于类的,对于这个类的所有的对象来说,其值是一样的
- c.怎么使用
通过类使用:类.字段
```python
class Person:
# number就是类的字段
number = 10
练习:写一个球类,用一个属性来保存这个类的创建对象的个数
class Ball:
count = 0
# 每次创建球的对象都会调用init方法,所以调用init方法的次数就是Ball创建的对象的个数
def __init__(self):
Ball.count += 1
ball1 = Ball()
ball2 = Ball()
print(Ball.count)
if __name__ == '__main__':
# 通过类获取类的字段的值
print(Person.number)
Person.number = 70
print(Person.number)
类的方法
类中的方法
- 1.对象方法(实例方法)
声明的形式:直接声明在类中
特点:自带一个不需要主动传参的默认参数self,谁来调用指向谁 - 2.类方法
声明形式:声明方法前需要使用@classmethod
特点:自带一个参数cls,这个参数调用的时候不需要传值,系统自动传值,谁调用,传给谁!始终指向当前类
调用:通过类调用—》类.类方法() 3.静态方法
声明的形式:声明方法前需要使用@staticmethod说明
特点:没有默认参数
调用:通过类来调用–》类.静态方法()`
python
class Class1:类字段
number = 10
声明一个对象方法
def object_func(self):
print('对象方法')
声明一个类方法
@classmethod
def class_func(cls):# 通过cls去使用类的字段 print('cls:',cls.number) # 通过cls去创建对象 tc =cls() tc.object_func() print('这是一个类方法')
@staticmethod
def static_func():print('这是一个静态方法')
c1 = Class1()
调用对象方法
c1.object_func()
print(Class1.number)
调用类方法
Class1.class_func()
调用静态方法
Class1.static_func()
4.遇到问题怎么来选择使用那种方法:
+ a.大前提:只要实现方法的功能需要用到对象的属性,我们就使用对象方法,否则就使用静态方法或者类方法
+ b.不使用对象方法的前提下,如果实现功能需要类的字段就使用类方法
+ c.实现功能既不需要对象的属性,又不需要类的字段就使用静态方法
注意:静态方法和类方法划分不严格,静态方法能做的,类方法可以做,反之成立
```python
class Person:
# 类的字段,存储人类数量
number = 61
@classmethod
def show_number1(cls):
print('人类的数量是:%d亿'% cls.number)
@staticmethod
def show_number2():
print('人类的数量是:%d亿'% Person.number)
Person.show_number1()
Person.show_number2()
内置类属性
内置类属性就是魔法属性
魔法属性:属性名的前面和后面都有两个下划线
魔法方法:方法的前后都有两个下划线
import datetime
class Person:
'''人的类'''
# 类的字段
number = 61
def __init__(self,name1,age1,height1):
# 对象的属性
self.name = name1
self.age = age1
self.height =height1
def run(self):
print('%s在跑步'% (self.name))
#类方法
@classmethod
def show_number(cls):
print('人类的数量为:%d亿'% (cls.number))
# 静态方法
@staticmethod
def destroy():
print('人类在破坏环境!')
if __name__ == '__main__':
p1 = Person('张三丰',20,173)
1.name属性 — 类的名字(是字符串)
# 类的属性
name = Person.__name__
print(name,type(name))
2.class属性 — 获取对象对应类(是一个类)
# 对象的属性
# my_classs是一个类,之前类能做的事情他都能做
my_class = p1.__class__
p2 = my_class('小明',20,100)
print(p2.name)
3.dict属性 — 将对象和类的属性及其对应的值转换成键值对存到一个字典中
# print(Person.__class__)
print(p1.__dict__) # {'name': '张三丰', 'age': 20, 'height': 173}
4.doc属性—-获取类的说明文档
# 类的属性
doc = Person.__doc__
print(doc)
5.module属性 —- 获取所有模块对应的名字
print(Person.__module__)
print(datetime.datetime.__module__)
6.bases属性 —获取当前类的父类
# 类的属性
print(Person.__bases__)
slots魔法
class Person:
'''人的类'''
# 通过__slots__中存的元素的属性的值来约束当前这个类的对象的属性,对象的属性只能比元组中的少,不能多
__slots__ = ('name','age','face')
def __init__(self):
# 对象的属性
self.name = '张三丰'
self.age = 20
self.face = 80
# self.sex = 'boy' # __slots__中并没有sex
if __name__ == '__main__':
p1 = Person()
# p1.sex = 'girl'
# print(p1.sex)
# p1.name = '小明'
print(p1.name)
# 注意:一旦在类中给__slots__属性赋了值,那么这个类的对象的__dict__属性就不能使用了
# print(p1.__dict__)
私有化
python中并没有真正的私有化
1.私有化的语法
a.类中的属性和方法都可以通过在属性名和方法名前加两个下划线,来让属性和方法变成私有的
b.私有的属性和方法只能在当前的类中使用
2.私有化的原理
在前面有两个下划线的属性名和方法名前添加了’_类名’来阻止外部直接访问属性名来使用属性
cclass Dog:
# 字段
number = 100
__count = 200
def __init__(self):
# 对象的属性
self.color = '黄色'
self.age = 3
self.name = '大黄'
self.__sex = '公狗'
# 对象方法
def __eat(self):
print('%s啃骨头'% (self.name))
def eat(self):
# 在类中可以使用私有的属性
self.__eat()
print('%s在吃屎·' % (self.name))
# 类方法
@classmethod
def shout(cls):
print('count',cls.__count)
print('汪汪汪~~~')
# 静态方法
@staticmethod
def function():
print('看家!!')
# python的类中默认的属性和方法是公开的
dog1 = Dog()
print(Dog.number)
print(dog1.name,dog1.color,dog1.age)
dog1.eat()
Dog.shout()
Dog.function()
# 在类的外面不能使用私有属性
# print(Dog.__count) AttributeError: type object 'Dog' has no attribute '__count'
# print(dog1.__sex) AttributeError: 'Dog' object has no attribute '__sex'
dog1.eat()
print(dog1.__dict__)
属性的getter和setter
1.解释
- a.保护类型的属性:就是在声明对象属性的时候在属性名前加一个下划线来代表这个属性是受保护的属性,
那么以后访问这个属性的时候就不要直接访问,要通过getter来获取这个属性的值,通过setter来给这个属性赋值 - b.如果一个属性已经声明成保护类型的属性,那么我们就要给这个属性添加getter,也可以添加setter
2.添加getter
添加getter就是声明一个没有参数,有一个返回值的函数
- a.格式:
@property
def 去掉下划线的属性名(self):
——函数体
——将属性相关的值返回 - b.使用场景
场景一:如果想要获取对象的某个属性的值之前,想要做其他处理,就可以给这个属性添加getter
场景二:想要拿到某个属性被使用的时刻
3.添加setter
添加setter就是声明一个有一个参数,但是没有返回值的参数,作用是给属性赋值
a.格式
b.使用场景
在给属性赋值前要进行其他操作,就给属性声明一个setter函数
class Car:
def __init__(self):
self.color = '黄色'
self.type = '自行车'
# price是保护类型
self._price = 2000
# 给_price属性添加getter
@property
def price(self):
print('在使用_price属性')
return self._price/1000
# 想要给一个属性添加setter,就必须先给这个属性添加getter
@price.setter
def price(self,price):
if isinstance(price,int) or isinstance(price,float):
self.price
else:
self._price = 0
练习:声明一个员工类,其中一个属性是否已婚(bool),获取值之前根据存的值返回”已婚”/“未婚”
class Staff:
'''员工类'''
def __init__(self,name,age):
self.name =name
self.age = age
self._is_marry = False
@property
def is_marry(self):
print('在使用_price属性')
if self._is_marry:
return '已婚'
return '未婚'
@is_marry.setter
def is_marry(self, marry):
self._is_marry = marry
if __name__ == '__main__':
car1 = Car()
print(car1.color,car1._price)
# 添加完getter后就通过getter去获取属性值,实质就是调用getter对应方法
# price就是属性_price的getter
print(car1.price,'k')
# 通过setter给属性赋值,实质是调用setter对应的方法
car1.price= 'abc'
print(car1.price)
s1 = Staff('张三', 20)
print(s1.is_marry)
s1.is_marry = True
print(s1.is_marry)
继承
python中类可以继承,并且支持多继承
程序中的继承:就是让子类字节拥有父类的属性和方法(继承父类中的内容不会因为被继承而减少)
1.继承的语法
class 子类(父类):
类的内容
注意:如果声明类的时候没有写继承,那么这个类会自动继承python中的基类,object;相当于class 类名(object):
python中所有的类都是直接和间接的继承自object
2.能继承那些东西
a.所有的属性和方法都能继承
b.slots的值不会继承,但是会影响子类对象的dict属性,不能获取父类继承下来的属性
class Person:
'''人类'''
# 字段
number = 61
# __slots__ = ('name','age')
# 对象属性
def __init__(self,name='张三',age=18):
self.name = name
self.age = age
self._height = 173
# 对象方法
def show_message(self):
print('姓名:%s 年龄:%d'% (self.name,self.age))
@classmethod
def show_number(cls):
print('人类的数量:%d亿'% cls.number)
@staticmethod
def show_message():
print('人类殴打小动物!')
class Student(Person):
'''学生类'''
pass
#创建Person类的对象
p = Person()
# 学生类
stu1 = Student()
print(Student.number)
print(stu1.name)
stu1.show_number()
stu1.show_message()
print(stu1.__dict__)
if __name__ == '__main__':
pass
方法的重写
子类继承父类,拥有父类的属性和方法以后,还可以添加自己的属性和方法
1.添加方法和类的字段
直接在子类中声明相应的字段和方法
2.添加对象属性
对象的属性是通过继承父类的init方法而继承下来
如果想要保留父类的对象的同时添加自己的对象属性,需要在子类的init方法中通过super()去调用父类的init方法
3.方法的重写
在子类中重新实现父类的方法,就是重写
方式一:直接覆盖父类的实现
方式二:保留父类的功能再添加其他功能
4.类中方法的调用过程
先在当前这个中的去找,没有找到就去父类中找,还是没找到就去,就去父类的父类中去找,以此类推,如果在基类中也没找到,才崩溃
在第一次找到的位置,去调用
注意:使用super的时候必须通过super()来代替父类或者是父类的对象
class Animal:
'''动物'''
def __init__(self):
self.age = 0
self.sex = '雌'
def shout(self):
print('嗷嗷叫')
class Cat(Animal):
'''猫'''
def __init__(self):
# 调用父类的init方法
super().__init__()
self.name = '小花'
food = '鱼'
def shout(self):
print('喵喵喵~~~')
class Dog(Animal):
'''狗'''
def shout(self):
# 通过super()调用父类的方法,保留父类功能
super().shout()
print('汪汪汪~~~')
cat1 = Cat()
print(cat1.name,cat1.age,cat1.sex)
cat1.shout()
dog1 = Dog()
dog1.shout()
init方法的重写
练习:写一个人类,拥有属性name,age,sex。要求创建Person对象的时候必须给name和age赋值,sex可赋可不赋,再写一个Staff类继承自Person类,要求保留Person中所有的属性,并且添加新的属性salary,要求创建Staff类的对象的时候,只能给name赋值(必须赋)
class Person:
'''人类'''
def __init__(self,name,age,sex='boy'):
self.name = name
self.age =age
self.sex = sex
class Staff(Person):
def __init__(self,name):
super().__init__(name,20)
self.salary = '10000'
if __name__ == '__main__':
p1 = Person('张三',20)
s1 = Staff('李四')
运算符的重载
如果希望类的对象支持相应的运算符(+,-,*,/,>,<ect),就必须实现相应的魔法方法
继承一样有用
: daa
:gt
一般情况需要对>或者<进行重载,重载后可以通过sort方法直接对对象的列表进行排序`
python
class Student:
def init(self,name=’’,age=0,score=0):self.name = name self.age = age self.score = score
self:+ 前面的对象
other:+ 后面的对象
def add(self, other):
return self.score + other.score
重载 > 符号
注意:重载>和<可以只重载一个,另一个对应的功能自动取反
def gt(self, other):
return self.age > other.age
重写魔法方法str,用来制定对象的打印样式
def str(self):
return 'Student:%s %d %d'% (self.name,self.age,self.score)
if name == ‘main‘:
stu1 = Student(‘小明’,18,90)
stu2 = Student(‘老王’,29,84)
stu3 = Student(‘项羽’,24,70)
print(stu1 + stu2)
print(stu1 > stu2)
print(stu1 < stu2)
all_student = [stu1,stu2,stu3]
all_student.sort()
for stu in all_student:
print(stu.name,stu.age,stu.score)
print(stu1.str())`