-
指定对象的值:
class Student:
pass
#指定属性
stu1 = Student()
stu1.name = '张无忌'
stu1.sex = 'man'
stu1.age = 18
#指定属性
stu2 = Student()
stu2.name = '周芷若'
stu2.sex = 'woman'
stu2.age = 18
-
但是,如果有1000个学生,怎么优化写法?
定义函数,用于为对象设置属性:
def set_attr(obj,name,sex,age):
obj.name = name
obj.sex = sex
obj.age = age
set_attr(stu3,'赵敏','woman',18)
print(stu3.__dict__)
#输出内容 : {'name': '赵敏', 'sex': 'woman', 'age': 18}
把函数放到类中就是一个初始化函数
-
初始化函数应该和类是一个整体
-
set_attr() 这个函数的目的用于设置对象的属性,如果没有对象此函数则没有存在的意义
新的调用方式:
class Student:
def set_attr(obj, name, sex, age):
obj.name = name
obj.sex = sex
obj.age = age
```
#新的调用方式
stu3 = Student()
Student.set_attr(stu3,'赵敏','woman',18)
print(stu3.__dict__)
-
但是,对象与初始化函数是分开的,可以创建对象,而不必执行函数
通常对象一旦被创建,初始化函数就会执行,对象与初始化函数通常是绑定关系:
示范1:
class Student:
#初始化函数名称是固定的,__开头__结尾的函数,会在某些时机下自动触发执行
def __init__(self):
print('执行了__init__')
print(self)
pass
s1 = Student()
#__init__在类的调用是就会执行
print(s1)
#self就是自身的意思
示范2:
class Student:
def __init__(self):
self.name = '张三丰'
self.age = 78
s1 = Student()
print(s1.__dict__)
s2 = Student()
print(s2.__dict__)
#这样写死了,因为两个的值是一样的
正确的写法:
class Student:
def __init__(self,name,age):
self.name = name
self.age = age#固定的写法,self可以自定义,但是不建议,相当于标识符
s1 = Student('张三丰',78)
print(s1.__dict__)
s2 = Student('金庸',68)
print(s2.__dict__)
总结:
-
init函数用于初始化对象,它在创建对象时,就会自动执行:
-
并传入调用类时传递的参数,self作为第一个参数没有意义,固定写法,标识符
练习:
class Phone:
def __init__(self,p_type,price,country):
self.p_type = p_type
self.p_price = price
self.country = country
p1 = Phone('iphone','5800','American')
print(p1.__dict__)
绑定方法
-
绑定方法有类的绑定,对象的绑定,
-
绑定方法可以理解为绑定函数,有绑定类的方法,绑定对象的方法,以及非绑定方法
-
在面向对象编程思想中,就是要求我们模仿现实生活中的抽象概念,因此把函数称之为方法
-
为什么要绑定?
-
调用函数,即处理与函数绑定在那个在一起的数据,即会返回对象
-
而对象本质上就是一种存放数据的容器
-
所以就相当于把数据和函数绑定在一起
-
为什么要把数据和函数绑定在一起?
-
得到对象,就得到了数据和处理数据的方法,就相当于执行了我们一个希望运行到的功能完整的函数.
我们实现一个循序渐进的过程:
处理一份数据:
name = '张三'
age = 20
sex = 'man'
def show_info():
print('hello,i am %s my age is %s my sex %s'%(name,age,sex))
show_info()
把数据引用到一个函数里面,完成对其的调用或处理
如果继续重复这样的数据,我们需要重新定义变量的值,可以优化为传参的形式:
def show_info(name,age,sex):
print('hello,i am %s my age is %s my sex %s'%(name,age,sex))
show_info(name,age,sex)
name = '张三'
age = 20
sex = 'man'
但是,传参的缺点如下:
-
传参的缺点在于如果参数的传递形式或者格式有误,报错
-
另一方面如果传入的参数较多,费时费力,解决办法的一种方式是把数据装到容器里
-
但是每次处理都要需要先获取数据,然后再传递给函数,依然比较容易出错
-
而且数据和函数是分离的,所以
-
** 将要处理的数据与处理数据的函数进行绑定,函数和数据就不是分离状态了**
-
如何绑定,就得用类和对象了
代码:
绑定对象
class Student:
school = 'BeiJing'
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
赋予某些技能(方法)
def learning(self):
print('正在学习...')
赋予某些具体的技能
def say_hi(self):
print('hello,i am %s my age is %s my sex %s'%(self.name,self.age,self.sex) )
默认情况下,在类中定义的方法都是绑定方法
stu1 = Student('李白',18,'man')
stu1.say_hi()#用对象调用
Student.say_hi(stu1)#用类调用
注释:以对象开头,用对象来调类中的方法(函数),默认会把对象传入方法中,也就是self,自身的意思
以类开头,用类来调用方法时,需要手动传入对象
内存原理(可以无视):
-
print(stu1.say_hi)
输出 : <bound method Student.say_hi of <main.Student object at 0x000001CE452B9EF0>>
这是一个绑定方法,本质上是Student类中的sayhi函数,现在把这个函数绑定给内存中地址为0x000001CE452B9EF0的对象
-
只要拿到对象,就同时拿到了数据和处理数据的方法,这就是之所以绑定的原因
-
可以更有效和更有效率的处理数据
-
以上是绑定给对象的方法,默认是绑定对象的
-
绑定给对象的意思就是方法(函数)用的都是类里面对象的内容,而不直接调用类
绑定类:
class Student:
school = 'BeiJing'#school就是类里的属性
def __init__(self,name,sex,age):
self.name = name#这些就是对象的属性
self.sex = sex
self.age = age
(self.age_1 = age)也可以这样写,age_1是可变的,不过默认两边是一样的
这是绑定给对象的方法,只涉及对象
def sayhello(self):
print(self.name,'你好')
绑定给类的方法,直接访问类,需要一个装饰器,默认参数变为cls,类的缩写,固定格式
@classmethod
def print_school(cls):
print('学校名为%s'%Student.school)#访问类中叫school的属性
print(cls.school)
def sayhello(self):
print(self.school) # 这样也可以操作,但是要用对象去掉,违背初衷,且太过于麻烦
Student.print_school()#类的调用
s1 = Student('name','sex','age')
s1.sayhello()#对象的调用
解释:
-
不加装饰器,正常调用不需要传入参数,就像访问普通函数一样,
-
但是函数需要一个参数,这是类中方法的固定用法,因此不可避免要报错。
-
引入@classmethod装饰器,固定用法,cls表示类,缩写
-
-
明确两点
如何定义对象绑定方法,以及类的绑定方法:
绑定对象是用于调取对象(非类里)属性的方法,绑定类是调取类的属性
在调用时有何区别
绑定类要加@classmethod装饰器
-
-
-
思考,一个方法在什么场景下会绑定对象或者类?
当要处理的数据包含在类里时,就不能绑定给对象,应该直接绑定给类
当要处理的数据包含在对象里时,就应该直接绑定给对象
-
-
非绑定方法
class Teacher:
def __init__(self,name,sex):
self.name = name
self.sex = sex
@staticmethod #静态方法,用于定义一个非绑定方法
def test_func(): #也可以传参
print('test_func, run!')
Teacher.test_func() #类访问
t1 = Teacher('name','fun')
t1.test_func() #对象访问
非绑定方法,在类中定义,既不绑定给类,也不绑定给对象 特点: 没有自动传参的效果,谁都可以调用,就是一个普通函数 使用场景,这个功能不需要访问类和对象的数据
练习
1.创建Student类
2.拥有以下属性: 姓名 性别 年龄 学校 班级
3.拥有以下方法
-
save(name) 其作用是将这个对象序列化到文件中
-
get_obj(name) 其作用是根据name从文件中反序列化为得到一个对象
-
分析save方法和get_obj 应该作为绑定给对象还是绑定给类
import json
class Student:
school = "beijing"
def __init__(self,name,sex,age,classes):
self.name = name
self.age = age
self.sex = sex
self.classes = classes
def save(self):
dic = {"name":self.name,"sex":self.sex,
"age":self.age,"classes":self.classes}
with open(self.name,"wt",encoding="utf-8") as f:
json.dump(dic,f)
@classmethod
def get_obj(cls,name):
with open(name,"rt",encoding="utf-8") as f:
dic = json.load(f)
obj = cls(dic["name"],dic["sex"],dic["age"],dic["classes"])
return obj
# stu1 = Student("阿尔法","man",20,"py5期")
# stu2 = Student("张三","woman",20,"py5期")
# stu1.save()
# stu2.save()
stu = Student.get_obj("阿尔法")
print(stu)
print(stu.name)
总结
类和对象的绑定方法的总结
1,相同点 都会自动传值 都可以被类和对象调用 参数名都可以被修改,但是不建议修改 2,不同点 对象绑定方法在对象调用时,传的是对象自己,而类绑定方法自动传的是类自己 第一个参数不一样,一个是self , 一个是cls
个人总结
访问顺序:
对象 ------> 类
调用方式:
1,对象调用
以对象开头的调用方式,对象要先定义对象,因此要用对象传参
2,类的调用
以类的名字开头的调用方式,不用提前定义
初始化函数:
以init为标志的函数,通常直接与方法绑定,方法直接调用其内定义的属性
绑定方法:
1,对象的绑定
对象的绑定就是方法中,参数是初始化函数定义中的属性,函数的结果或返回值就是对象
2,类的绑定
类的绑定就是方法中,直接调用初始化函数之外的属性,要加一个装饰器@classmethod
绑定的情景:
1,对象的绑定
属性在对象里,就不需要绑定给类,多此一举
2,类的绑定
属性包含在类里,直接绑定给类
非绑定方法:
在类中定义,既不绑定给类,也不绑定给对象
已解决
类的公共内容是什么?
是类里所有对象共有的属性,也即是初始化函数之外的内容,一般写在初始化函数上面
对象跟类是什么关系?
对象是使用类里某些属性和方法的东西,实例化的内容,从类里创建出来的内容
调用类会产生对象,返回的是对象
初始化函数外的属性是不是叫类里的属性?
不止是之外的属性,类里的所有东西都是一种属性,方法也是一种属性,万物皆对象,万物皆属性
方法是函数,也是对象的技能,也是一种属性.
怎么区分处理的数据是在对象里还是类里?
对象里是作为属性返回的,类是是共有的属性
对象的属性和技能?
属性是类似于你的名字,身高,体重,年龄,技能就类似于你使用的python
对象的属性和技能就是调用类里属性和方法返回的值.