day23

## 复习

 

4.类与对象的语法
class 类名:
代码块(一堆属性与方法)
对象名 = 类名()


变量 | 函数 => 属性 | 方法:前者直接使用,通过所属者.语法调用

 

类会随所属文件加载而加载(执行内部所有代码),形成类的名称空间
3.提前在类中属性的属性与方法,在对象一产生就可以使用这些属性和方法
'''
'''
2.拥有名称空间的对象:有__dict__属性,该属性就是指向对象的名称空间
-- 文件 | 包(__init__.py文件) | 函数 | 类
-- 可以为__dict__属性添加值,简化为.语法,也可以对__dict__整体赋值一个字典
'''
dic = {'a': 1, 'b': lambda x, y: x + y}
def fn():
print('fn run')
fn()
fn.name = '函数'
print(fn.name)
print(fn.__dict__)
fn.__dict__ = dic
print(fn.__dict__)
print(fn.a)
print(fn.b(10, 20))

class Student:
def __init__(self, name, sex):
print('2>>>', self)
self.name = name
self.sex = sex


def fn():
print('fn run')
def set_stu(stu, name, sex):
stu.name = name
stu.sex = sex

 

 

## 对象独有的名称空间: 在产生对象时就赋初值


class Student:
def __init__(self, stu_name, sex):
self.name = stu_name
self.sex = sex # 通常建议参数名与新增的属性名同名

stu = Student('Bob', 'male') # 实例化对象
print(stu.name, stu.sex)


# __init__方法会在实例化对象时被调用
# 1.会为实例化的对象形成空的名称空间
# 2.就是一个方法,可以被传参,在 类名(实参) 这种方式下调用并传参 __init__(self, 形参)
# 3.第一个self就是要产生的当前对象
# 重点:在方法内部,形参拿到了实参值,利用self.属性名 = 形参 = 实参值,对对象的名称空间添加属性


#对象特有的名称空间


# print(Student.__dict__)
Student.fn()
stu1 = Student()
# print(stu1.__dict__) # set_stu并不存在stu1的名称空间,由类来调用
Student.set_stu(stu1, 'Bob', 'male')
print(stu1.__dict__)
print(stu1.name)
print(stu1.sex)

stu2 = Student()
Student.set_stu(stu2, 'Tom', 'female')
print(stu2.name, stu2.sex)

```

 

## 类中方法的第一个默认参数:对象方法


class A:
# 对象方法
def test(self, num):
pass
a = A()

# 调用方法
# 二级优化
a.test(10)
# 一级优化
A.test(a, 10)
# 实现原理
A.__dict__['test'](a, 10)

# 总结:对象a传递给self,数字10传递给num
# 重点:方法的第一个参数一定是调用该方法的对象


class Student:
pass
stu = Student()

# def fn(a, b):
# print('fn run')
# stu.fn = fn
# stu.fn(10, 20)

def func(arg):
print('func run')
Student.func = func # 将这个函数加入到类中的话,必须要写一个参数arg,不管有没有用,固定的就是将对象传入func,不然会报错
# Student.func()
# stu.func() == Student.__dict__['func'](stu) == Student.func(stu)
'''
```

 

## 类中@classmethod修饰的方法:类方法

```python
class Tool:
@classmethod
def add(cls, n1, n2): # 统一类与对象都可以调用类方法,一定有默认传入第一个参数
return n1 + n2

# 建议
Tool.add(10, 20) # 默认第一个传入自身 - Tool

# 不建议
tool = Tool()
tool.add(100, 200) # 默认第一个传入自身所属类 - tool.__class__


class Tool:
def add(n1,n2):
return n1+n2

res=Tool.add(10,20) # 类调用自己的函数属性,就是function,函数需要传入几个参数,就需要传入几个参数,
# 然后拿到返回值,如果是对象调用的话,就不需要,因为对象调函数就是bound method
print(res)
```

 

## 属性与方法的总结

```python
class Tool:
# 类自己的方法
def add(cls, n1, n2):
cls.fn()
return n1 + n2

def fn():
pass

# a如果被外界对象tool调用,那么内部调用b,b其实也是被外界对象tool调用的
def a(self):
self.b()
def b(self):
pass

res = Tool.add(Tool, 10, 20) # 类调用,外界传入两个参数,内部接收到两个
print(res)


class Tool:
# 类方法:可以被类与对象调用的方法,第一个参数一定是类
# 类方法不建议拿对象来调用
@classmethod
def add(cls, n1, n2):
print(id(cls))
cls.test()
return n1 + n2

@classmethod
def test(cls):
pass

print(Tool.add(10, 20))
tool = Tool()
print(tool.add(100, 200))
print(id(Tool), id(tool))

# 对象调用所属类的类方法,默认第一个参数传入的是 对象.__class__ 就是所属类
print(tool.__class__)

class OldBoy:
# 属于类的属性
name = '老男孩'

# 属于对象的属性
def __init__(self, name):
self.name = name

# 属于类的方法
# 需求:获取机构的名字
@classmethod
def get_class_name(cls):
return cls.name

# 属于对象的方法
# 需求:获取校区的名字
def get_school_name(self):
return self.name

# 先创建校区
shanghai = OldBoy('上海校区')
shenzhen = OldBoy('深圳校区')

# 类方法的使用
# 建议使用类调用
print(OldBoy.get_class_name())
# 类方法拿对象调用并没有多少新增的意义,不建议拿对象调用
print(shanghai.get_class_name())
print(shenzhen.get_class_name())

# 对象方法的使用
# 类调用对象方法,必须把要操作的对象手动传入,不建议使用
print(OldBoy.get_school_name(shanghai))
print(OldBoy.get_school_name(shenzhen))
# 对象调用对象方法,默认将自身传入,建议使用
print(shanghai.get_school_name())
print(shenzhen.get_school_name())
```

 

### 封装

 

#封装语法
class A:
# __开头的属性,在外界不能通过 cord | __cord 直接访问:对外隐藏了
__cord = '01012300'

# __开头的方法,在外界不能通过 get_money | __get_money 直接访问:对外隐藏了
@classmethod
def __get_money(cls):
print('输入密码,取出100w零花钱')

# 内部还是可以直接访问__开头的属性与方法
@classmethod
def test(cls, flag):
print('test方法被外界调用')
# 在调用test与访问具体数据与功能间添加安全处理的操作
if flag == '自家人':
print(cls.__cord)
cls.__get_money()

# print(A.__cord)
# A.__get_money()
A.test('自家人')


# 封装的原理:把用__开头的名字更名为 _类名__变量名,所以直接通过 变量名 | __变量名就访问不到
# print(A.__dict__)
print(A._A__cord)
A._A__get_money()

## 对象的属性方法封装与接口提供


# 对象的属性与方法封装集中与类的属性与方法封装原理一样
class AAA:
def __init__(self, money):
self.__money = money
self.__id = 1000

@property
def id(self):
return self.__id
@id.setter
def id(self, id):
self.__id = id

# 对象的属性封装
# 1.对象的属性值一般都来源于外界,外界是有权力再次访问的
# 2.封装的目的不是让外界无法访问,而且不让其直接访问,可以在完成安全处理后再访问
# 3.如何做到外界还是通过变量名来对属性进行取值赋值,但是是走的方法间接拿到的值
# -- __money被封装,外界还是可以通过 对象.money 取值赋值


# 取值
@property # 在外界可以 对象.money 进行取值
def money(self):
# print('走方法拿到的money')
return self.__money

# 赋值
@money.setter # 在外界可以 对象.money = 新值 进行赋值
def money(self, money):
self.__money = money

# 删除
@money.deleter
def money(self):
# print('逗你玩')
del self.__money

def get_money(self, flag):
if flag == '自家人':
return self.__money
return 0

def set_money(self, money):
self.__money += money

# 对象的方法封装一般的实现需求都是,这些方法只在内部使用
def __test(self):
print('test run')

a = AAA(88888)
# print(a.__money) # 正常方法不能访问
# print(a._AAA__money) # 通过实现的原理也可以正常访问,假装不知道
# a._AAA__test()

print(a.get_money('自家人'))
a.set_money(100000)
print(a.get_money('自家人'))

print(a.money)
a.money = 999999
print(a.money)

# del a.money
# print(a.money)
```

 


# 重点:
# 1.类的属性如何定义,类的方法如何定义
# 2.对象的属性如何定义,对象的方法如何定义
# 3.什么时候定义类方法与对象方法
# 4.封装的语法与原理
# 5.封装的目的
# 6.对象属性的封装对外提供操作接口的手段
```

## 主要的总结


#类:对象是特征与技能的结合体,而类则是一系列对象相同的特征与技能的结合体
# 类体代码会在类定义阶段立即执行,会产生一个类的名称空间,用来将类体代码执行过程中的名字都会丢进去。
# 1类的本质就是一个名称空间,或者说是一个用来存放变量与函数的容器
# 2类的用途之一就是当作名称空间从其内部取出名字来使用
# 3类的用途之一是调用来产生对象
'''
#站在老男孩的角度
#总结出现实世界中的老男孩学生对象
学生对象1:
特征:
school=’odlboy'
name='李铁蛋
age=18
sex='male'
技能:
选课

 

学生对象2:
特征:
school=’odlboy'
name='赵钢弹‘
age=38
sex='female'
技能:
选课


学生对象3:
特征:
school=’odlboy'
name='刘银弹‘
age=28
sex='male'
技能:
选课


老师对象1:
特征:
school=’odlboy'
name='刘银弹‘
age=28
sex='male'
level=10
技能:
打分


总结现实世界中的老男孩学生类:特征与技能相同结合体
相同的特征:
school=’lodboy‘
相同的技能
选课
'''


'''
#在程序中:
#1.先定义类
'''
class OldboyStudent:
school='oldboy'
def choose_course(self):
print('choosing course')

 

#查看类的名称空间 2.类与对象都可以通过.语法来拓展新功能
print(OldboyStudent.school)
print(OldboyStudent.__dict__)
print(OldboyStudent.__dict__['school'])
OldboyStudent.choose_course('qwe') #必须要传值,不管是什么,如果是类调用的话
# OldboyStudent.choose_course() #报错

 

#可以改变类内的值,也可以加值,调用类内的函数\
#改值
OldboyStudent.school='OLDBOY'
#加值
OldboyStudent.country='China'
print(OldboyStudent.__dict__['country'])
#删值
del OldboyStudent.country


# 后调用类来产生对象,产生三个空的名称空间 1.每个实例化出来的对象及类都有自己的名称空间
stu1=OldboyStudent()
stu2=OldboyStudent()
stu3=OldboyStudent()

print(stu1.__dict__)
print(stu2.__dict__)
print(stu2.__dict__)

#,然后要往里面丢自己的特征与技能(加值)
stu1.name='李铁蛋'
stu1.age=18
stu1.sex='male'
print(stu1.__dict__)

stu2.name='赵钢蛋'
stu2.age=38
stu2.sex='male'
print(stu2.__dict__)

stu3.name='赵银蛋'
stu3.age=28
stu3.sex='female'
print(stu2.__dict__)

#为对象定制自己独有的特征

def init(obj,name,age,sex):
obj.name=name
obj.age=age
obj.sex=sex

init(stu1,'李铁蛋',18,'male')
init(stu2,'赵钢蛋',28,'female')
init(stu2,'赵银蛋',38,'male')
#缺点就是重复的调用init

# 将init加入要类中,将init 改为__init__为自动调用,减少函数体代码
class OldboyStudent:
school='oldboy'
def __init__(obj, name, age, sex):# 这个函数内不能有返回值,因为这样会跟类冲突,因为类返回的是对象,而__init__是在对象产生后才运行的
obj.name = name # obj必须是一个内存地址,有名称空间
obj.age = age #在方法内部,形参拿到了实参值,利用self.属性名 = 形参 = 实参值,对对象的名称空间添加属性
obj.sex = sex
def choose_course(self):
print('choosing course')
#调用类发生了
#1、产生一个空的对象,然后返回
#2、触发类中的__init__的执行,将对象连同调用类括号内指定的参数一同传入__init__

# 在类中定义__init__的好处就是对象拥有自己独有的特征
stu1=OldboyStudent('李铁蛋',18,'male')
stu2=OldboyStudent('赵钢蛋',28,'female')
stu3=OldboyStudent('赵银蛋',38,'male')

print(stu1.__dict__)
print(stu2.__dict__)
print(stu3.__dict__)

 

#二、属性的查找顺序:先从对象自己的名称空间找,没有则去所属的类中找,如类中没有就报错

# 三、类中的定义的变量是所有对象共享的,对象可以来用,类也可以来用,类一旦改变自己的数据属性的值,所有的对象都能感知到,
# 而如果是对象本身自己改变,对其他对象没有影响

#四、绑定方法
# 类中的变量是类的数据属性,类可以用,对象也可以用,大家都指向同一个内存地址,类变量一旦改变都跟着改变
# 类中定义的函数时类的函数属性,类可以使用,但类来调用就是一个普通的函数而且绑定给对象用的
#类来调用函数就是该传几个值就传几个值function
# 绑定方法:指向类的函数,特殊之处就是,绑定给谁就应该由谁来调用就会将谁当作第一个参数传入(bound method)

 

上一篇:day23单例模式 , 日志处理 , 项目结构目录


下一篇:shell训练营Day23