函数/面向对象-类

1501-姬同学

发表文章数:20

热门标签

首页 » Python » 正文

函数

嵌套函数_内部函数_数据隐藏

嵌套函数:在函数内部定义的函数
嵌套函数只能在函数内部调用,不能在外部调用,所以可用来隐藏内部函数

一般在什么情况下使用嵌套函数?
1、封装-数据隐藏
外部无法访问嵌套函数

def f1():
    print('f1 running...')

    def f2():
        print("f2 running...")

    f2()

f1()##外部无法直接调用f2()

2、贯彻DRY(Dont Repeat Yourself)原则
嵌套函数,可以让我们在函数内部避免重复代码

def printName(isChinese,name,familyName):
    def inner_print(a,b):
        print('{0} {1}'.format(a,b))

    if isChinese:
            inner_print(familyName,name)
    else:
            inner_print(name,familyName)

printName(True,'凝','姬')
printName(False,'Jane','Trump')

3、闭包(后面才进行讲解)

nonlocal_global

nonlocal   用来声明外层的局部变量

(外部函数的变量,如果想在某个内部函数内使用,则需要在这个内部函数内使用nonlocal进行声明)

global     用来声明全局变量

(在函数外部全局变量,如果想在函数内部使用并修改,则需要在函数内使用global进行声明)

a=100
def outer():
   b=10
   def inner():
       global a
       nonlocal  b
       print('inner b:',b)
       print('a:', a)
       b=20
       a=30

   inner()
   print('outer b:',b)
outer()
print('a:',a)

LEGB规则

python在查找‘名称’时,是按照LEGB规则查找的:
Local–>Enclosed–>Global–>Built in
如没找到,就会报错-NameError

Local 指的就是函数或者类的方法内部(局部作用域)
Enclosed 指的是嵌套函数(一个函数包裹另一个函数,闭包)
Global 指的是模块中的全局变量
Built in 指的是python为自己保留的特殊名称

str='global'#3
def outer():
    str='outer'#2
    def inner():
        str='inner'#1
        print(str)
        pass
    inner()

outer()
#4class'str'

面向对象编程

OOP(Object oriented Programming)
主要针对大型软件设计而来。面向对象编程使得程序的扩展性更强、可读性更好、使编程像搭积木一样简单。

将数据和操作数据相关的方法封装到对象中,组织代码和数据的方式更加接近人的思维,从而大大提高了编程的效率

面向对象和面向过程的区别_执行者思维_设计者思维

  • 面向过程(Procedure Oriented)思维(动词)
    ‘执行者’思维,适合编写小规模的程序,按步骤实现,将步骤对应成方法,一步一步最终完成。
  • 面向对象(Object Oriented)思维(名词)
    ‘设计者’思维,适合编写大规模的程序。

对象的进化故事

简单数据
数据变多(将同类型数据放在一起)- ->数组
数据类型变复杂(将不同类型的数据放在一起)- ->结构体
处理数据的方式和逻辑变复杂(将不同类型的数据与方法(即函数)放在一起)- ->对象

类的定义_类和对象的关系

类包含数据类型的属性(数据/变量)和方法(行为/函数)
对象包含属性(每个对象维持自己的属性)和方法(由同一个类创建,所有对象共享)

class Student:#类名首字母大写,多个单词采用驼峰原则
    def __init__(self,name,score):#self必须位于第一个参数;name、score为类的两个属性
        self.name = name
        self.score = score

    def say_score(self):#类的方法
        print("{0}的分数是{1}".format(self.name,self.score))

s1 = Student('jining',18)
s1.say_score()

构造函数__init__

  • 要点:
    1、名称固定__init__()
    2、第一个参数固定,必须为self
    3、构造函数通常用来初始化实例对象的实例属性
    4、通过‘类名(参数列表)’来调用构造函数,调用后,将创建好的对象返回给相应的变量
    5、init()方法:初始化创建好的对象,初始化指的是:‘给实例属性赋值’
    6、new()方法:用于创建对象,但我们一般无需重定义该方法
    7、如果我们不定义__init__()方法,系统会提供一个默认的__init__方法。如果我们自行定义,则系统将不创建默认的该方法。

实例属性_内存分析

实例属性是从属于实例对象的属性,也称为实例变量

  • 要点:
    1、实例属性一般在__init__()方法中通过如下代码定义:
    self.实例属性名 = 初始值
    2、在本类的其它实例方法中,也是通过self进行访问。
    self.实例属性名
    3、创建实例对象后,通过实力对象访问:
    obj01=类名()# 创建对象,调用__init__()初始化属性
    obj01.实例属性名 = 值 #也可以给已有属性赋值,也可以新加属性
class Student:#类名首字母大写,多个单词采用驼峰原则
    def __init__(self,name,score):#self必须位于第一个参数;name、score为类的两个属性
        self.name = name
        self.score = score

    def say_score(self):#类的方法
        print("{0}的分数是{1}".format(self.name,self.score))
s1 = Student('jining',100)
s1.say_score()

s1.age = 18
s1.salary = 20000
print(s1.age)
#########################
运行结果:
jining的分数是100
18

实例方法_内存分析方法调用过程__dir()__isinstance

实例方法是从属于实例对象的方法,实例方法的定义格式如下:
def 方法名(self[,形参列表])
函数体
方法的调用格式如下:
对象.方法名([实参列表])
要点:
1、定义实例方法时,第一个参数必须为self。和前面一样,self指当前的实例对象
2、调用实例方法时,不需要也不能给self传参,self由解释器自动传参。
函数和方法的区别
1、都是用来完成一个功能的语句块,本质一样
2、方法调用时通过对象来调用。方法从属于特定实例对象,普通函数没有这个特点
3、直观上看,方法定义时需要传递self,函数不需要。
其他操作
1、dir(obj)可以获得对象的所有属性、方法
2、 obj. _ _ dict_ _
3、pass 空语句
4、isinstance(对象、类型)判断‘对象’是不是指定类型

class Student:#类名首字母大写,多个单词采用驼峰原则
    def __init__(self,name,score):#self必须位于第一个参数;name、score为类的两个属性
        self.name = name
        self.score = score

    def say_score(self):#类的方法
        print("{0}的分数是{1}".format(self.name,self.score))
s1 = Student('jining',100)
s1.say_score()

s1.age = 18
s1.salary = 20000

s2=Student('jiyu',100)
************************
s2.say_score()
Student.say_score(s2)
这两种调用方式均可
************************
print(dir(s2))
运行结果:
['__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', 'say_score', 'score']
************************
print(s2.__dict__)
运行结果:
{'name': 'jiyu', 'score': 100}
************************
print(isinstance(s2,Student))
运行结果:True

类对象

当解释器执行class语句时,会创建一个类对象

class Student:
    pass
print(type(Student))
print(id(Student))
Stu2 =Student
s1 =Stu2()
print(s1)
运行结果:
<class 'type'>
140430218841576
<__main__.Student object at 0x7fb878263be0>

我们可以看到实际上生成了一个变量名就是类名‘Student’的对象,通过赋值给到‘Stu2’,也能实现相关的调用

类属性_内存分析创建类和对象的底层

类属性时从属于‘类对象的’属性,也称为类变量。由于类属性从属于类对象,也可以被所有实例对象共享
类属性的定义方式:
class 类名:
类变量名=初始值
在类中,或者类的外面,我们可以通过:“类名.变量名”来读写

class Student:
    company = 'SXT'#类属性
    count = 0  #类属性

    def __init__(self,name,score):
        self.name=name  #实例属性
        self.score=score
        Student.count=Student.count+1

    def say_score(self):   #实例方法
        print('我的公司是:',Student.company)
        print(self.name,'的分数是:',self.score)

s1= Student('张三',80)
s1.say_score()

s1= Student('李四',100)
s1.say_score()


print('一共创建了{0}个对象'.format(Student.count))
运行结果:
张三 的分数是: 80
我的公司是: SXT
李四 的分数是: 100
一共创建了2个对象

类方法_静态方法_内存分析图示

类方法时从属于类对象的方法。类方法通过装饰器@classmethod来定义,格式如下:
@classmethod
def 类方法名(cls[,形参列表]):
函数体

  • 要点:
    1、@classmethod必须位于方法上面一行
    2、第一个cls必须有;cls指的是‘类对象’本身;
    3、调用类方法格式:“类名.类方法名(参数列表)”。参数列表中,不需要也不能给cls传值
    4、类方法中访问实例属性和实例方法会导致错误
    5、子类继承父类方法时,传入cls时子类对象,而非父类对象

静态方法
python中允许定义与类对象无关的方法,称为静态方法。
静态方法和在模块中定义普通函数没有区别,只不过静态方法放在了类的名字空间里面,需要通过类调用
格式:
@staticmethod
def 静态方法名([参数列表])
函数体

  • 要点:
    1、@staticmethod必须位于方法上面一行
    2、调用静态方法格式:类名.静态方法名([参数列表])
    3、静态方法中访问实例属性和实例方法会导致错误
class Student:
    company = 'SXT'

    @staticmethod
    def add(a,b):
        print('{0}+{1}={2}'.format(a,b,a+b))
        return a+b
Student.add(30,40)
运行结果:
30+40=70

del()析构方法和垃圾回收机制

用于实现对象被销毁时所需的操作。比如:释放对象占用的资源,例如打开的文件资源或者网络连接等
python实现自动的垃圾回收,当对象没有被引用时(引用计数为0),由垃圾回收器调用__del__方法
我们也可以通过del语句删除对象,从而保证方法的调用
系统会自动提供该方法,一般不需要自定义析构方法。

call()方法和可调用对象

定义了__call__方法的对象,称为‘可调用的对象,即该对象可以像函数一样被调用’

当我们定义了函数a,那我们就可以用a()进行函数的调用,但是无法直接通过obj()对对象进行调用。
例如:
a=30
b=50
c=a+b
d=a.add(b)#当我们输入a+b时,解释器做的事情是调用__add__方法

obj()实际是调用__call__方法

class SalaryAccount:

    def __call__(self,salary):
        print("算工资啦···")
        yearSalary = salary*12
        daySalary = salary//22.5
        hourSalary = daySalary//8

        return dict(monthSalary = salary,yearSalary=yearSalary,daySalary =daySalary ,hourSalary=hourSalary)

s=SalaryAccount()
print(s(7000))
运行结果:
算工资啦···
{'monthSalary': 7000, 'yearSalary': 84000, 'daySalary': 311.0, 'hourSalary': 38.0}

标签:

未经允许不得转载:作者:1501-姬同学, 转载或复制请以 超链接形式 并注明出处 拜师资源博客
原文地址:《函数/面向对象-类》 发布于2021-02-23

分享到:
赞(0) 打赏

评论 抢沙发

评论前必须登录!

  注册



长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu3.3主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录