Python 学习之路(中)

一、函数的特殊用法

1.变量可以指向函数

代码演示:

#abs------>absolute

#abs()是一个系统的内置函数【built-in function】
print(abs(-10))   #10
print(abs)   #<built-in function abs>

#结论一:abs(-10)是函数的调用,而abs是函数本身
x = abs(-20)
print(x)   #20

f = abs
print(f)   #<built-in function abs>

#结论二;函数本身也可以直接赋值给一个变量,也就是说:变量可以指向一个函数   num = 10
#如果一个变量指向了一个函数,则可以通过这个变量去调用这个函数
print(f(-30))

#结论三:f = abs, 则表示f已经指向了abs所表示的函数,调用abs和调用f实现的效果是一样的

def test():
    return  "fjskghs"

print(test())
fun = test
print(fun())
2.函数名是一个变量

代码演示:

#函数的特殊用法之函数名是一个变量

#结论一:函数名其实就是指向函数的变量

#abs():可以将abs看做一个变量,指向了一个可以计算绝对值的函数

#abs更改指向【变量的重新赋值】

num = 10
num = "hello"

#让abs指向一个整型
print(abs)
abs = 10
print(abs)

#print(abs(-100))
3.函数作为参数

代码演示:

#函数的特殊用法之函数作为参数

#变量可以指向函数,函数名是一个变量,而函数的形参本身就是一个变量,可以接收实参,那么一个函数就可以接收另一个函数作为参数
#高阶函数【一个函数就可以接收另一个函数作为参数】

#一个简单的高阶函数【需求:求两个数的绝对值的和】
#参数:x和y就是需要参与运算的数据,fun是一个函数
"""
def add(x,y):
    return abs(x) + abs(y)

"""
def add(x,y,fun):
    return fun(x) + fun(y)    #abs(x) + abs(y)

#将函数名abs作为参数使用
result = add(-5,6,abs)    #x = -5  y = 6   fun = abs  fun()
print(result)


#自定义函数
def show():
    print("abc")

def func(f):
    print("hello")
    f()

func(show)

二、偏函数【了解】

默认参数:可以降低函数调用的难度

偏函数:对函数参数做一些控制的函数

注意:偏函数不需要自定义,直接使用【系统函数】

代码演示:

import  functools

# 偏函数的使用


#int(x)   可以将字符串或者浮点型转换为整型
#默认:将其中的字符串按照十进制输出
print(int("123"))

#int()还提供了一个额外的参数:base
#print(int("abc123"))
#base;指明前面数据的进制,int()执行完成之后,最终还是以十进制输出
print(int("123",base = 10))   #123
print(int("123",base = 8))    #83


print(int("110",base = 2))
print(int("11010",base = 2))
print(int("110001",base = 2))

#转换大量的二进制,每次传入base = 2麻烦,可以将这个功能提取出来
def customInt(x,base=2):
    return int(x,base)
print(customInt("110"))  #6
print(customInt("11010"))  #26

#上面通过默认参数模仿了偏函数的使用,但是系统提供了功能:functools.partial可以创建一个偏函数【前提;需要导入import  functools】
#参数:需要创建偏函数的原函数名  需要设定的参数
int2 = functools.partial(int,base=2)
print(int2("110"))   #6
print(int2("11010"))  #26

print(int2("110",base=10))   #110

#总结:偏函数
#主要针对的是系统函数,如果系统默认的操作满足不了需求,则可以在这个系统函数的基础上生成一个新的函数【偏函数】,两个函数可以实现不同的需求

三、闭包【掌握】

如果在一个函数的内部定义另外一个函数,外部的函数叫做外函数,内部的函数叫做内函数

如果在一个外部函数中定义一个内部函数,并且外部函数的返回值是内部函数,就构成了一个闭包,则这个内部函数就被称为闭包【closure】

代码演示:

"""
如果在一个函数的内部定义另外一个函数,外部的函数叫做外函数,内部的函数叫做内函数

如果在一个外部函数中定义一个内部函数,并且外部函数的返回值是内部函数,就构成了一个闭包,
则这个内部函数就被称为闭包【closure】
"""

#1.最简单的闭包
#外函数
def func(str):
    #内函数【闭包】
    def innerFunc():
        print("hello")

    return innerFunc

#f中存储了外函数func的返回值,而func的返回值是innerFunc,j就相当于f = innerFunc
f = func("abc")   #f = innerFunc
#f()就相当于innerFunc()
f()

#2.
#a和b被称为外函数中的临时变量【自由变量】
def outer(a):
    b = 10
    def inner():
        #在内函数中可以直接使用外函数中临时变量
        print(a + b)
    return  inner

f1 = outer(5)
f1()

#3.
def outer1(num1):
    def inner1(num2):
        #在内函数中可以直接使用外函数中临时变量
        print(num1,num2)
    return  inner1

f2 = outer1(10)
f2(20)

#应用场景:装饰器

四、变量的作用域

1.出现的原因

变量的作用域:变量可以被使用【被访问】的范围

程序中的变量并不是在任意的语句中都可以被访问,访问权限取决于这个变量被定义在哪个位置

2.作用范围划分

局部作用域:L【Local】

函数作用域:E【Enclosing】 将变量定义在闭包外的函数中

全局作用域:G【Global】

內建作用域:B【Built-in】

代码演示:

#1.不同作用域变量的定义
num4 = int(2.9)    #B;內建作用域
num3 =  3    #G;全局作用域
def outer():
    num1 = 1    #E:函数作用域

    def inner():
        num2 = 2   #L:局部作用域

        #注意:当所有的变量不同名的时候,在闭包中,可以任意访问四种不同作用域对应的变量
        print(num4,num3,num2,num1)

    return  inner

f = outer()
f()
3.变量的查找规则

查找的顺序:L------>E------>G------>B【极端情况:当所有的变量同名的情况下】【面试题】

代码演示:

#变量的查找规则

#注意:全局作用域和内置作用域,当重名的时候,谁出现在后面,则先匹配到谁
x = 0
x1 = int(3.3)

def outer1():
    j = 1
	
    def inner1():
        i = 2
        #【就近原则】
        print(x)

    return  inner1

f1 = outer1()
f1()
#函数
def show(a):
    num1 = 10
    print(num1,a)
show(20)
#print(num1,a)
#结论一:在函数中定义的变量【形参,在函数体中定义的变量】,作用域仅限于函数内部
# 【变量的生命周随着函数的出现而出现,函数执行完毕则变量随着被销毁】

#if语句
if True:
    msg = "hello"
    print(msg)
print(msg)


 #for循环
for i in range(0,5):
    print(i)
print(i)

#结论二;Python中只有模块【module】、类【class】和函数【def,lambda】才会引入新的作用域
#其他的代码块:if语句,while语句,for语句,try-except语句都不会引入新的作用域
4.全局变量和局部变量【掌握】

全局变量:将变量定义在函数的外面

局部变量:将变量定义在函数的内部

注意:局部变量只能在其被声明的当前函数中使用,而全局变量可以在整个程序中使用

代码演示:

#全局变量
total = 0

def show():
    print(total)
show()

if True:
    total = 20
    print(total)

total = 10
print(total)

def add(arg1,arg2):
    #arg1,arg2,total1都属于局部变量
    total1 = arg1 + arg2
    print(total1)

add(10,20)
#print(total1)

作业讲解:

#1.计算1~某个数范围内奇数的和并返回
def fun1(num):
    sum = 0
    for i in range(1,num + 1):
        if i % 2 == 1:
            sum += 1

    return sum

print(fun1(100))

#2.判断某个数是否是质数,返回结果
def fun2(num):
    is_prime = True

    for x in range(2,num):
        if num % x == 0:
            is_prime = False
            break
    if is_prime and num != 1:
        return "质数"
    else:
        return "不是质数"

fun2(10)
5.global和nonlocal关键字的使用【掌握】

使用场景:当内部作用域【局部作用域,函数作用域】想要修改全局变量的作用域的时候

1.global

代码演示:

#global

#全局变量
num = 1
def fun1():

    #此时要使用全局变量中的num,需要给编译器做一个声明,声明此处使用num就是使用的全局变量中的num
    global num
    print(num)
    print(id(num))   #1355785312

    #局部变量
    num = 123
    print(num)
    print(id(num))   #1355789216

fun1()


#练习
a = 10
def test():
    global  a
    a = a + 1
    print(a)

test()

2.nonlocal

代码演示:

#前提:nonlocal关键字是定义在闭包中
x = 0

def outer():
    x = 1

    def inner():
        #使用nonlocal关键字进行声明,相当于将局部作用域范围扩大了
        nonlocal x
        x = 2
        print("inner:",x)
    #return  inner

    inner()

    print("outer:",x)   #2

outer()
print("global:",x)
"""
原本:
inner: 2
outer: 1
global: 0
"""

"""
修改:
inner: 2
outer: 2
global: 0
"""

五、列表生成式和生成器【掌握】

1.列表生成式

list comprehension

系统内置的用于创建list的方式

range(start,end,step)缺点:生成的列表一般情况下都是等差数列

代码演示:

#列表生成式

list1 = list(range(1,11))
print(list1)   #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


#需求:[1, 4, 9, 16, 25]
list2 = []
for x in range(1,11):
    list2.append(x ** 2)
print(list2)  #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

#1
#使用列表生成式完成上面的需求
#列表生成式的格式:[生成的元素 for-in循环]
list3 = [x ** 2 for x in range(1,11)]
print(list3)   #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

#2.
#[4,16,36,64,100]
list4 = [x ** 2 for x in range(1,11) if x % 2 == 0]
print(list4)


#3.嵌套for循环,第一个循环就相当于外层循环,第二个循环就相当于内层循环
list5 = [m + n for m in "ABC" for n in "XYZ"]
print(list5)

#["AX","AY","AZ"....]

"""
for m in "ABC":
    for n in "XYZ":
        print(m + n)

"""

#4
#for k,v in dict.items)():
d = {"x":"1","y":"2","z":"3"}
for k,v in d.items():
    print(k,v)

list6 = [k + "=" + v for k,v in d.items()]
print(list6)   #['x=1', 'y=2', 'z=3']


#练习:使用列表生成式生成一个新的列表,将一个已知列表中的所有的字符变为小写
l1 = ["Hello","GOOD","ABC","kkH"]
#l2 = ["hello","good","abc","kkh"]

newList1 = []
for element in l1:
    str = element.lower()
    newList1.append(str)
print(newList1)


newList2 = [s.lower() for s in l1]
print(newList2)
2.生成器

generator

next()

代码演示:

#生成器

#方式一:(),将列表生成式中的[]改成()
#列表生成式的类型是list,生成器的类型是generator【当做一种新的数据类型】
r1 = (x ** 2 for x in range(1,6))
print(r1)   #(1,4,9,16,25)
print(type(r1))

"""
for i in r1:
    print(i)
"""

#生成器区别于列表生成式:可以使用next遍历,每调用一次则获取一个元素
#next()
print(next(r1))
print(next(r1))
print(next(r1))
print(next(r1))
print(next(r1))
#注意:当生成器中的元素全部获取完成之后,接着调用next函数的,则会出现StopIteration
#print(next(r1))   #StopIteration异常


#方式二:yield---->让步
#(x for x in range(1,6))----->1,2,3,4,5
def test(n):
    for i in range(1, n + 1):
        #执行到yield的时候,则函数会停止,将yiled后面的变量返回
        yield i ** 2
        #yield后面的代码的执行时机:当调用next函数的时候
        print(i)

t = test(5)
print(t)  #<generator object test at 0x0000019CC432A1A8>
print(next(t))
print(next(t))
print(next(t))
print(next(t))
print(next(t))

六、迭代器【掌握】

1.可迭代对象

可迭代对象【实体】:可以直接作用于for循环的实体【Iterable】

可以直接作用于for循环的数据类型:

​ a.list,tuple,dict,set,string

​ b.generator【() 和yield】

isinstance:判断一个实体是否是可迭代的对象

代码演示:

#一、可迭代对象

#1.导入
from  collections  import  Iterable

#2.使用isinstance(数据,Iterable)
print(isinstance([],Iterable))
print(isinstance((),Iterable))
print(isinstance({},Iterable))
print(isinstance((x for x in range(10)),Iterable))
print(isinstance("hello",Iterable))

print(isinstance(10,Iterable))   #False
print(isinstance(True,Iterable))  #False

print("****88")
2.迭代器

不但可以作用于for循环,还可以被next函数遍历【不断调用并返回一个元素,直到最后一个元素被遍历完成,则出现StopIteration】

目前为止,只有生成器才是迭代器【Iterator】

结论:迭代器肯定是可迭代对象,但是,可迭代对象不一定是迭代器

isinstance:判断一个实体是否是迭代器

代码演示:

#二、迭代器
from  collections  import  Iterator

print(isinstance([],Iterator))
print(isinstance((),Iterator))
print(isinstance({},Iterator))
print(isinstance("hello",Iterator))
print(isinstance((x for x in range(10)),Iterator))   #True

print("****88")
3.可迭代对象和迭代器之间的转换

可以将可迭代对象转换为迭代器:iter()

代码演示:

#三、虽然list、tuple、dict、set、string都不是迭代器
#iter():将list、tuple、dict、set、string的  Iterable转换为Iterator
print(isinstance(iter([]),Iterator))
print(isinstance(iter(()),Iterator))
print(isinstance(iter({}),Iterator))
print(isinstance(iter("hello"),Iterator))

总结:

​ a.凡是可以作用于for循环的对象都是Iterable类型

​ b.凡是可以作用于next函数的对象都是Iterator类型

​ c.list/tuple/dict/set/string都不是Iterator,可以通过iter()获得一个Iterator对象

【面试题】

区分可迭代对象和迭代器

七、装饰器【掌握】

1.案例

代码演示:

def test():
    print("拼搏到无能为力,坚持到感动自己")

f = test()  #变量可以指向指向函数,函数名也是一个变量,所以变量可以当做函数调用
f()

#思考问题:test增加功能,但是不能修改test函数内部----->装饰器

在代码运行期间,可以动态增加函数功能的方式,被称为装饰器【Decorator】

也就是说,在不修改原函数的基础上,给原函数增加功能

好处:在团队开发中,如果两个或者两个以上的程序员会用到相同的功能,但是功能又有细微的差别,采用装饰器:相互不影响,代码简化

2.使用
2.1简单装饰器

代码演示:

#1.简单的装饰器
def test():
    print("拼搏到无能为力,坚持到感动自己")

#a.书写闭包
#b.给外部函数设置参数,fun表示的是原函数
def outer(fun):
    def inner():
        # d.给原函数增加功能
        print("hello")

        #c.调用原函数
        fun()
    return inner

#e.使用闭包
f = outer(test)   #f = inner
f()   #inner()

#注意:增加的功能可以写在原函数调用的前面或者后面
#注意:outer函数就被称为装饰器


#练习:给下面的函数添加功能,打印九九乘法表
def show():
    for i in range(10):
        print(i)

def outer1(fun):
    def inner1():
        fun()
        for i in range(1,10):
            for j in range(1,i + 1):
                print("%dx%d=%d"%(j,i,i * j),end=" ")
            print("")
    return  inner1

f1 = outer1(show)
f1()
2.2有参数的装饰器

代码演示:

#2.原函数有参数的装饰器
def getAge(age):
    print(age)

getAge(10)
getAge(-5)

print("************")

#需求:在不修改原函数的基础上,进行数据的过滤:当用户输入age为负数的时候,则置为0
def wrapper(fun):
    #注意:当原函数有参数,装饰器的作用是为了操作原函数中的参数,给inner设置参数
    def inner(num):
        #增加新功能:过滤负数
        if num < 0:
            num = 0

        #调用原函数
        fun(num)  #age = num
    return  inner

f = wrapper(getAge)
f(10)   #num = 10
f(-5)
2.3系统的简写

代码演示:

#3.简化demo2中的操作:@装饰器的名称  应用到原函数中

#需求:在不修改原函数的基础上,进行数据的过滤:当用户输入age为负数的时候,则置为0
def wrapper(fun):
    #注意:当原函数有参数,装饰器的作用是为了操作原函数中的参数,给inner设置参数
    def inner(num):
        #增加新功能:过滤负数
        if num < 0:
            num = 0

        #调用原函数
        fun(num)  #age = num
    return  inner

#将wrapper装饰器应用在了getAge函数上,
@wrapper
def getAge(age):
    print(age)

getAge(10)
getAge(-5)

"""
@wrapper

等价于

f = wrapper(getAge)
f(10)   #num = 10

#注意;当使用@的时候,在同一个文件中,装饰器必须出现的原函数的前面

"""
2.4不定长参数的装饰器

代码演示:

#4.不定长参数的装饰器

#应用场景:当同一个装饰器作用于不同函数的时候,这些函数的参数的个数是不相同的
def wrapper(fun):
    def inner(*args):
        print("hello")

        fun(*args)   #a = args[0]   b = args[1]

    return  inner

@wrapper
def fun1(a,b):
    print(a + b)

@wrapper
def fun2(a,b,c,d):
    print(a,b,c,d)

fun1(10,20)   #args = (10,20)
fun2(1,2,3,4)
2.5多个装饰器作用于同一个函数

代码演示:

#5.将多个装饰器应用到同一个函数上
def wrapper1(fun):
    def inner1():
        print("1~~~~")
        fun()
	
    return inner1

def wrapper2(fun):
    def inner2():
        print("2~~~~")
        fun()

    return inner2

@wrapper1
@wrapper2
def show():
    print("hello")

show()

"""
1~~~~
2~~~~
hello
"""

#结论:多个装饰器作用于同一个函数的时候,从第一个装饰器开始,从上往下依次执行,但是,原函数只会被执行一次

八、函数递归【掌握】

1.概念

递归函数:一个会调用自身的函数【在一个函数的内部,自己调用自己】

递归调用

递归中包含了一种隐式的循环,他会重复指定某段代码【函数体】,但这种循环不需要条件控制

使用递归解决问题思路:

​ a.找到一个临界条件【临界值】

​ b.找到相邻两次循环之间的关系

​ c.一般情况下,会找到一个规律【公式】

2.使用

代码演示:

#案例一
"""
               1 2 3 4 5 6 7  8  9 10  11.。。。
斐波那契数列:1,1,2,3,5,8,13,21,34,55,89.....

解决问题:报一个数,输出数列中对应的数

规律:
a.第一个位置和第二个位置上数是固定的,都是1
b.第n个位置上的数:第 n - 1 的数  +   第 n - 2 的数

r1 = func1(1)  ------>1
r2 = func1(2)  ------>1
r3 = fun1(3) ------>func1(1) + func1(2)----->1 + 1 = 2
r4 = fun1(4)------->fun1(3) + fun1(2) ----->func1(1) + func1(2) +  fun1(2) ---->1  + 1 + 1 = 3
r5 = fun1(5) ----->fun1(4) + fun1(3) ----->fun1(3) + fun1(2) + func1(1) + func1(2)--->func1(1) + func1(2) ++ fun1(2) + func1(1) + func1(2)--->5
.....
rn = fun1(n) ----->fun1(n- 1) + fun1(n - 2)
"""

def func1(num):
    #临界值
    if num == 1 or num == 2:
        return 1
    else:
        #print("~~~~",num)
        result = func1(num- 1) + func1(num - 2)    #result = func1(1) + func1(2)  --->1 + 1 =2
        return result

print(func1(10))

#练习;使用递归计算1~某个数之间的和
"""
add(1) = 1   :临界值
add(2) = add(1) + 2
add(3) = add(2) + 3 ---->add(1) + 2 + 3 = 1 + 2 + 3
add(4) = add(3) + 4---->add(2) + 3 + 4 ---->add(1) + 2 + 3 + 4---->1 + 2 + 3 + 4
....
add(n) = add(n - 1) + n
"""
def add(num):

    """
    n = 1
    sum = 0
    while n <= 100:
        sum += n
        n += 1

    return sum

    sum1 = 0
    for i in range(1,num + 1):
        sum1 += i
    return  sum1
    """
    #使用递归实现
    if num == 1:
        return 1
    else:
        return add(num - 1) + num

print(add(100))

注意:以后在实际项目中尽量少用递归,如果隐式循环的次数太多,会导致内存泄漏【栈溢出】

优点:简化代码,逻辑清晰

九、栈和队列【了解】

用于存储数据的线性表

栈:在表的一端进行插入和删除

队列:在表的一端进行插入,在表的另一端进行数据的删除

1.栈

Stack

开口向上的容器:先进后出,后进先出

代码演示:

#list的底层维护了一个栈的线性表

myStack = []

#插入数据
#数据入栈【压栈】
myStack.append(1)
print(myStack)
myStack.append(2)
print(myStack)
myStack.append(3)
print(myStack)
myStack.append(4)
print(myStack)   #[1,2,3,4]

#出栈
myStack.pop()
print(myStack)
myStack.pop()
print(myStack)
myStack.pop()
print(myStack)
myStack.pop()
print(myStack)
2.队列

queue

水平放置的水管:先进先出,后进后出

代码演示:

import  collections   #数据结构的集合

queue  = collections.deque([1,2,3,4])
print(queue)

#入队【存储数据】
queue.append(5)
print(queue)
queue.append(6)
print(queue)

#出队【获取数据】
queue.popleft()
print(queue)
queue.popleft()
print(queue)
queue.popleft()
print(queue)

十、目录遍历

os 用于获取系统的功能,主要用于操作文件或者文件夹

代码演示:

import  os

path = r"C:\Users\Administrator\Desktop\SZ-Python"

#获取指定目录下所有的文件以及文件夹,返回值为一个列表
filesList = os.listdir(path)
print(filesList)

#C:\Users\Administrator\Desktop\SZ-Python
#通过初始路径拼接子文件或者子文件夹形成新的路径
filePath = os.path.join(path,"作业")
print(filePath)

#判断指定的路径是否是文件夹【目录】
result = os.path.isdir(filePath)
print(result)
1.使用递归遍历目录

代码演示:

#递归
import os

def getAll(path):
    #1.获取当前目录下所有的文件以及文件夹
    fileList = os.listdir(path)
    print(fileList)

    #2.遍历列表
    for i in fileList:
        #3.拼接路径
        filePath = os.path.join(path,i)

        #4.判断filePath是否是文件夹
        if os.path.isdir(filePath):
            #文件夹:递归
            getAll(filePath)
        else:
            #文件
            print("文件:",i)

getAll(r"C:\Users\Administrator\Desktop\SZ-Python")

十一、包

包:初期理解为文件夹

作用:一种管理Python模块命名空间的形式,采用"点语法"   os.path

包和文件夹之间的区别:Python的包中有一个特殊的文件__init__.py文件,前期里面不写任何内容,但是,就是为了告诉编译器,当前这个目录不是普通目录,是一个包

创建方式:选中工程,创建Python package

代码演示:

"""
1.在Python中,一个py文件其实就是一个模块
2.如果要跨模块调用函数,需要在运行的模块中导入需要使用的模块,调用函数的时候需要指明函数的路径
"""

#第一步:导入模块
#导入格式:包名.模块名
import aaa.textDemo01
import ccc.module

#os.path.isdir()
aaa.textDemo01.test()
ccc.module.test()

#包存在的意义:在团队开发的过程中,为了解决文件命名冲突的问题,只要保证最上层的包命名不相同,就不会与别人的发生冲突

十二、模块

1.概述

为了解决维护问题,一般情况下,在一个完整的项目中,会将特定的功能分组,分别放到不同的文件中,在使用的过程中,可以单独维护,各个不同的文件之间互不影响,每个.py文件就被称为一个模块,通过结合包的使用来组织文件

封装思路: 函数 => 类 => 模块 => 包 => 项目

优点:

a.提高了代码的可维护性

b.提高了代码的复用性【当一个模块被完成之后,可以在多个文件中使用】

c.引用其他的模块【第三方模块】

d.避免函数名和变量的命名冲突

2 os模块

提供有关于操作系统的函数,处理文件或者文件夹

代码演示:

import os
# operation system 操作系统

#1.获取当前操作系统的名称
# nt----->Windows   
# posix------>Linux, Mac os
print(os.name)

#2.获取当前系统的环境变量
#以字典的形式返回
print(os.environ)
#通过key获取对应的value
print(os.environ.get("APPDATA"))

#3,获取指定目录下所有的文件或者文件夹的列表
l = os.listdir(r"C:\Users\Administrator\Desktop\SZ-Python")
print(l)

#4.在指定的路径下创建文件夹
#os.mkdir(r"C:\Users\Administrator\Desktop\aaa")

#5.删除文件夹
#os.rmdir(r"C:\Users\Administrator\Desktop\aaa")
#删除文件
#os.remove("")

#6.获取文件属性
#print(os.stat(r"C:\Users\Administrator\Desktop\aaa"))

#7.给文件或者文件夹重命名
#注意:当前的文件在关闭状态
#rename(old,new)
#os.rename(r"C:\Users\Administrator\Desktop\aaa",r"C:\Users\Administrator\Desktop\abc")

#os.path模块下
#1.路径的拼接
path = os.path.join(r"C:\Users\Administrator\Desktop\SZ-Python","Day1Code")
print(path)

#2.绝对路径和相对路径【掌握】
"""
绝对路径:带有盘符的路径,缺点:只能在指定的计算机上使用
相对路径:不带盘符的路径,一般情况下是以当前的工程为参照物
    例如:
        aaa/textDemo01.py
        ccc/module.py
"""
#os.rename("bbb/check.py","bbb/show.py")

#3.拆分路径
#注意:返回的结果为元组,默认情况下只会拆分最后的文件或者文件夹
tuple1 = os.path.split(r"C:\Users\Administrator\Desktop\SZ-Python\Day1Code")
print(tuple)

#4.拆分路径,获取指定路径对应的文件的扩展名
print(os.path.splitext(r"C:\Users\Administrator\Desktop\SZ-Python\Day2Code\assignDemo.py"))

#5.判断指定路径是否是文件夹
print(os.path.isdir("aaa/textDemo01.py"))

#6.判断指定路径是否是文件
print(os.path.isfile("aaa/textDemo01.py"))

#7.判断一个指定路径是否存在
print(os.path.exists("aaa/textDemo01.py"))

#8.获取文件的大小【字节】
print(os.path.getsize("aaa/textDemo01.py"))

#9.
#获取指定文件夹的父路径
print(os.path.dirname(r"C:\Users\Administrator\Desktop\SZ-Python\Day1Code"))
#获取当前文件夹的名称
print(os.path.basename(r"C:\Users\Administrator\Desktop\SZ-Python\Day1Code"))

练习:

import  os
#练习:获取指定目录下所有的py文件或者txt文件
"""
思路:
1.判断指定的目录是否存在
2.获取指定目录下所有的文件以及文件夹: listdir()
3.拼接路径: 
4.判断拼接之后的路径是否是文件
5.判断文件名称的后缀
"""
def getFile(path):
    #1.
    if os.path.exists(path):
        #2
        fileList = os.listdir(path)

        #3.
        for fileName in fileList:
            filePath = os.path.join(path,fileName)

            #4
            if os.path.isfile(filePath):
                #5
                if fileName.endswith("py") or fileName.endswith("txt"):
                    print(fileName)
            else:
                print(fileName,"不是文件")

    else:
        print("指定的路径不存在")

getFile(r"C:\Users\Administrator\Desktop\SZ-Python\Day5Code")
3.自定义模块【掌握】
3.1自定义import模块

代码演示:

#1.格式:import  包1.包2.模块的名称
#注意1:通过点语法区分包的层级关系
#引入模块

#注意2:如果要同时导入多个模块,有两种方式
#方式一
"""
import os
import datetime
import math
"""
#方式二
import os,math,datetime

#注意3:当导入自定义模块的时候,需要注意包的存在
#注意5:当通过import将模块导入的时候,将模块对应的文件整个加载了一遍
import ccc.module
import moduleTextDemo01

print("***************")

#注意4:当模块有包的层级关系时,需要调用其中函数的时候,需要指明函数的路径
ccc.module.test()     #os.path.isdir()

moduleTextDemo01.fun1()
moduleTextDemo01.fun2()
moduleTextDemo01.fun3()

print(moduleTextDemo01.num)
3.2自定义from-import模块

代码演示:


#form 模块名  import 函数名1/类名,函数名2.。。。
#import  moduleTextDemo01
from moduleTextDemo01 import  fun1,fun2,fun3

#注意:采用了form。。。import的方式导入指定的函数之后,可以直接调用函数
fun1()
fun2()
fun3()

#好处:进行局部的导入,避免内存空间的浪费


#注意:当前文件中如果存在和模块中同名的函数的时候,当前文件中的函数仍然会将模块中的函数给覆盖掉
def fun1():
    print("hello")

fun1()
3.3自定义from-import*模块

代码演示:

#from 。。。。 import  *      *代表全部
"""
下面三种导入方式完全等价:将moduleTextDemo01模块中的所有的内容全部导入
from moduleTextDemo01 import  *
import moduleTextDemo01
from  moduleTextDemo01 import  fun1,fun2,fun3
"""
from moduleTextDemo01 import  *

fun1()

总结:在python中,每个py文件其实都是一个模块,如果跨模块调用函数,则采用导入的方式

将不同的功能进行划分,调用函数的时候相对比较方便的

4.__name__属性和dir函数
4.1name属性
#__name__的作用:如果不想让模块中的某些代码执行,可以通过属性仅仅调用程序中的一部分功能
#【写在if判断中的代码只有当前模块被执行的时候才会被执行,检测到是其他的文件在使用当前的模块,则if语句中的代码不会被执行】

def fun1():
    print("aaa")

def fun2():
    print("bbb")

def fun3():
    print("ccc")


#作用:写在下面判断中的代码,只有当前模块运行的时候才会被执行【起到屏蔽的作用】
if __name__ == "__main__":
    fun1()
    fun2()
    fun3()
4.2dir函数

代码演示:

#dir:
import math,moduleTextDemo01

#获取指定模块里面的所有的内容
#dir(模块名称)  返回的是一个列表
print(dir(math))
print(dir(moduleTextDemo01))

十三. 系统模块

UTC:国际标准时间, 格林尼治天文时间,UTC+8

时间戳:指定时间距离1970.1.1 00:00:00的秒数

time:时间

datetime:日期

calendar:万年历

os:系统,文件和文件夹

2.1time时间模块

时间的表示形式:

​ a. 时间戳: 如:1523158416.681

​ b. 元组格式

​ c. 字符串

tm_year: 年
tm_mon: 月(1~12)
tm_mday:天(1~31)
tm_hour:时(0~23)
tm_min:分(0~59)
tm_sec:秒(0~59)
tm_wday: 一周中的第几天(0~6,0表示星期一)
tm_yday:一年中的第几天(1~366)
tm_isdst:是否是夏令时

​ c.时间字符串:如:2019-09-08 11:11:11

%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00-59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%% %号本身

代码演示:

#导入
import time

#1。获取当前时间对应的时间戳,使用浮点型表示【掌握】
t1 = time.time()
print(t1)

#2。将时间戳转换为UTC
g = time.gmtime(t1)
print(g)  #time.struct_time(tm_year=2018, tm_mon=5, tm_mday=29, tm_hour=2, tm_min=29, tm_sec=1, tm_wday=1, tm_yday=149, tm_isdst=0)

#3.根据时间戳生成当地时间【掌握】
l = time.localtime(t1)
print(l)

#4.将具体时间转换为时间戳【掌握】
m = time.mktime(l)
print(m)

#5.将时间转换为字符串形式【掌握】
a = time.asctime(l)
print(a)  #Tue May 29 10:36:57 2018

#6.将时间戳转换为字符串形式
c = time.ctime(t1)
print(c)

#7.将时间进行格式化【指定字符串的格式】【掌握】
"""
%Y:年
%m:月
%d:日
%H:时【24小时制】
%h:时【12小时制】
%M:分
%S:秒
"""
s1 = time.strftime("%Y.%m.%d %H:%M:%S",l)   #string format
print(s1)

#8.休眠,参数的单位为秒【掌握】
print("4674747")
time.sleep(2)
print("hello")

#9.用浮点数【一般用科学计数法】计算的秒数返回当前cpu的时间,用于衡量不同程序的耗时
print(time.clock())  # 新版本Python已经不再支持

练习:

#需求;已知一个时间的字符串,然后输出三天之后的时间
"""
思路:
1.将已知的字符串转换为对应的时间戳
2.利用时间戳计算三天后的时间【加法运算 + 3 * 24 * 3600】
3.将时间戳转换为时间的字符串,并且将时间格式化
"""
import time

str = "2017-5-20"

#1.将已知的字符串转换为对应的时间戳
newStr = time.strptime(str,"%Y-%m-%d")
print(newStr)
time1 = time.mktime(newStr)
print(time1)
#2.利用时间戳计算三天后的时间【加法运算 + 3 * 24 * 3600】
time2 = time1 + 3 * 24 * 3600
#3.将时间戳转换为时间的字符串,并且将时间格式化
time3 = time.strftime("%Y-%m-%d",time.localtime(time2))
print(time3)   #2017-05-23
2.2datetime日期模块【掌握】

是对time模块的封装,比time模块更加全面

dt_now = datetime.datetime.now()
        获取当前的日期对象,包含时间的
dt_ziding = datetime.datetime()
        根据指定的日期、时间生成一个日期对象
        
dt.strftime()  将日期对象转化为指定的格式
dt.date()   获取日期对象中的日期
dt.time()   获取日期对象中的时间
dt.timestamp()  获取日期对象的时间戳
dt.hour\minute\second  获取小时、分钟、秒

datetime.datetime.fromtimestamp()
        根据一个时间戳,转化为指定的日期对象
datetime.timedelta()
        生成一个差值对象,可以和日期对象直接进行相加减
        参数有,days,hours,minutes,seconds

代码演示:

import  datetime

#1.获取当前时间
d1 = datetime.datetime.now()
print(d1)  #2018-05-29 11:20:51.432757

#2.获取指定的时间,通过元组形式
d2 = datetime.datetime(2015,10,1,10,23,23,1234)
print(d2)

#3.将时间格式化
d3 = d1.strftime("%Y.%m.%d")
print(d3)

#4.将时间字符串转换为datetime实体
d4 = datetime.datetime.strptime(d3,"%Y.%m.%d")
print(d4)

#5.直接进行加减运算
date1 = datetime.datetime(2015,10,1,10,23,23,0)
print(date1)

date2 = datetime.datetime(2015,10,4,10,23,23,0)
date3 = date2 - date1
print(date3)  #3 days, 0:00:00

print(date3.days)
print(date3.seconds)
2.3calendar日历模块(了解)
calendar(year,w=2,l=1,c=6)  
   打印某一年的日历【c间隔距离; w每日宽度间隔; l是每星期行数 】
       
isleap(year)   判断是否是闰年

leapdays(y1, y2)  [y1, y2) 中间闰年的个数

month(year,month,w=2,l=1)  打印指定月份的日历

monthcalendar(year,month)  
   返回一个整数的单层嵌套列表。每个子列表装载代表一个星期的整数。
   Year年month月外的日期都设为0;范围内的日子都由该月第几日表示,从1开始。

monthrange(year,month)  
   返回两个整数。第一个是该月的星期几的日期码,第二个是该月的日期码。
   日从0(星期一)到6(星期日);月从1到12。

代码演示:

import  calendar

#返回指定年份中指定月份的万年历表示
print(calendar.month(2018,5))

#返回指定年份的万年历表示
print(calendar.calendar(2018))

#返回一个列表【二维列表】
print(calendar.monthcalendar(2018,5))

#当前周起始的日期
print(calendar.firstweekday())

#判断某年是否为闰年
print(calendar.isleap(2010))

#统计两个年份之间闰年的总数
print(calendar.leapdays(2000,2020))

#获取的是星期,0【星期一】~6【星期天】   1~12
print(calendar.weekday(2018,5,29))

十四、面向对象思想

1.面向对象思想设计

基于哲学观点:万物皆对象, 一切皆对象

举例说明:

案例一:我想吃大盘鸡

面向过程 面向对象

1.自己去买菜 1.委托一个人帮忙买菜

2.自己择菜 2.委托一个人帮忙择菜

3.自己做菜 3.委托一个人厨师做菜

4.自己吃 4.自己吃

案例二:小明是一个电脑小白,想要配置一台电脑

面向过程 面向对象

1.小明补充电脑知识 1.委托一个懂电脑的人买零件

2.小明去买零件 2.委托一个人组装

3.小明把零件运回来 3.小明打开玩游戏

4.小明组装

5.小明打开玩游戏

案例三:一辆红色的法拉利在京藏高速上奔驰

法拉利 京藏高速

2.面向过程和面向对象的区别
2.1面向过程

process:处理

在生活案例中:

​ 一种看待问题的思维方式,在解决问题的时候,侧重于问题是怎样一步一步解决的,然后亲力亲为的去解决

在程序中:

​ 代码从上往下依次执行

​ 各个模块之间的关系尽可能的独立的,当import的时候,加载的顺序也是从上往下依次加载

​ 每个模块中的语句结构:顺序,分支,循环

2.2面向对象

在生活案例中:

​ 一种看待问题的思维方式,侧重于找到一个具有特殊功能的个体,然后委托这个个体帮忙完成某件事情,这个个体就被称为对象

​ 好处:可以将复杂的问题简单化,将程序员从执行者变成了指挥者

在程序中:

​ 根据不同的需求执行代码【代码执行顺序不一定】

​ 程序的流程完全由需求决定【对象】

​ 思想:如果对象存在,则直接使用;如果对象不存在,则创建对象

注意:面向对象只是一种思想,并不是一门编程语言

Python是一门面向对象的编程语言,类和对象是 面向对象的核心

示例: 小狗吃食(闻一闻smell、舔一舔lick、咬一咬bite)
	  分别采用面向过程和面向对象来分析

面向过程 :  先闻一闻, 然后再舔一舔, 最后再咬一咬 (注重过程) 
面向对象 :  小狗是一个对象, 它可以闻一闻食物, 可以舔一舔食物, 可以咬一咬食物.      (不注重过程, 注重对象)

十五、类和对象【掌握】

1.类和对象的概念

类:多个具有特殊功能的个体的集合

对象:在一个类中,一个具有特殊功能的个体,能够帮忙解决某件特定的事情,也被称为实例【instance】

两者之间的关系:类用于描述某一类对象的共同特征,而对象是类的具体的存在【包含关系】

思考问题:先有类还是先有对象?

【不好说,但是,在程序中使用的时候,一般是先定义类,然后创建对象】

举例:

​ 类 对象

​ 人 王麻子,李四. 赵四。。

​ 快递 韵达,中通,圆通。。

​ SupreHero 蝙蝠侠,蜘蛛侠,美国队。。

帮忙理解:类其实也是一种数据类型,只不过一般情况下是自定义的,所以可以将类认为是自定义的数据类型,用法和整型,string,list等基本是相同的【定义变量,传参】

2.类的定义

语法:

class 类名( ):

​ 类体

说明:

​ a.Python中使用class关键字定义类

​ b.类名只要是一个合法的标识符即可,但是要求:遵循大驼峰命名法则【首单词的首字母大写,不同单词之间首字母大写】

​ c.通过缩进区分类体

​ d.类体一般包含两部分内容:对类的特征的描述、对类的行为的描述

代码演示:

#类的定义
#类的声明
class MyClass():
    #类的实现
    #类体
    #print("hello")   #一般不会这么书写
    pass

#注意:在同一个py文件中可以同时定义多个类,但是,为了提高代码的可读性,结合模块的使用,最好是一个文件一个类
class MyClass1():
    pass
3.类的设计【类体的实现】

三要素:

​ 事物名称【类名】:举例:人

​ 事物的特征【变量】:名词,举例:姓名,年龄。。。。

​ 事物的行为【函数/方法】:动词,举例:吃,跑。。。。

十六、类中的方法和变量【掌握】

1.类中的方法和变量的定义

类中的方法和变量是为了描述事物的行为和特征

类中定义的方法被称为成员方法

类中定义的变量被称为成员变量,也被称为属性 [os.name]

成员变量:类具有的特征

成员方法:类具有的行为

类存在的意义:拥有相同特征和行为的对象可以抽取出来一个类,类的存在是为了创建一个具体的对象

代码演示:

#定义类
#1.事物的名称:类名
class Person():
    #2.事物的特征:成员变量、属性
    name = ""
    age = 0
    height = 0.0

    #3.事物的行为:成员方法【函数】
    #注意:类中的成员方法区别于普通方法:参数部分一定包含self,而且最好self出现在参数列表的第一个
    #调用函数的时候,self不需要被传参
    #初次之外,成员方法的用法和普通方法的使用完全相同,也可以设置默认参数或者关键字参数,不定长参数

    #注意:self:自己,代表类的实例【对象】
    #此处的self可以是任意的标识符,只不过为了结合其他编程的使用,习惯上使用self
    def eat(self,food):
        print("eating",food)
    def run(self):
        print("running")
2.类中方法和属性的使用

2.1创建对象【实例化对象】

已知类,通过类创建对象

对象的创建过程被对象的实例化过程

语法:变量名 = 值

​ 对象名 = 类名()

代码演示:

#定义类
#1.事物的名称:类名
class Person():
    #2.事物的特征:成员变量、属性
    name = ""
    age = 0
    height = 0.0

    #3.事物的行为:成员方法【函数】
    #注意:类中的成员方法区别于普通方法:参数部分一定包含self,而且最好self出现在参数列表的第一个
    #调用函数的时候,self不需要被传参
    #初次之外,成员方法的用法和普通方法的使用完全相同,也可以设置默认参数或者关键字参数,不定长参数

    #注意:self:自己,代表类的实例【对象】
    #此处的self可以是任意的标识符,只不过为了结合其他编程的使用,习惯上使用self
    def eat(self,food):
        print("eating",food)
    def run(self):
        print("running")
        print("self的地址:", id(self))


#对象的创建
p1 = Person()
print(p1)

p2 = Person()
print(p2)

#p1和p2被称为对象,变量名,引用,指向了真正的对象
#p1和p2在栈空间中开辟了空间,真正的对象的被存储在堆空间中

#通过对象调用类中的成员方法和访问类中的成员变量
#1.访问属性
#语法:对象.属性名
#赋值:对象.属性 = 值
per = Person()
print(per.name)
per.name = "小姐姐"
print(per.name)
per.age = 18
print(per.age)
per.height = 1.70
print(per.height)

#2.调用方法
#语法:对象.函数名(参数列表)
#注意:self不需要被传参,传参的时候注意区分参数的类型【默认参数,不定长参数,关键字参数】
per.run()
print("per的地址:",id(per))
"""
self的地址: 2687721120880
per的地址: 2687721120880
"""
per.eat("apple")

person = Person()
person.name = "张三"
person.age = 20
print(person.name,person.age)
person.run()
person.eat("")

#结论:类中的成员变量和成员方法随着对象的出现而出现

总结:

​ 访问变量采用:对象名.属性名

​ 访问方法采用:对象名.方法名(参数列表)

3.内存中的对象

per = Person()

说明:

a.程序中定义的Person类型的变量per实际上是一个变量名,它被存放在栈内存中,他指向实际的Person对象,而真正的Person对象则存放于堆内存中

b.类中的成员变量随着对象的出现而出现,随着对象的消失而消失

c.每个对象的成员变量会在堆空间中开辟一份自己的空间,相互之间互不影响

4.动态绑定属性和限制绑定
__slots__变量的作用:限制一个类中的成员变量【程序在运行的过程中,就不能随意的动态绑定属性】
语法:__slots__ = (属性的名称)

代码演示:

#1.类的定义
class MyClass():
    #2.成员变量
    """
    num1 = 0
    num2 = 10
    """
    #限制属性
    #注意:被限制的属性的名称通过字符串的方式出现在元组的元素中
    __slots__ = ("num1","num2")

    #3.成员方法
    def fun1(self):
        print("fun1")
    def fun2(self,num):
        print(num)

#4.创建对象
my = MyClass()
#5.访问类中的成员变量
my.num1 = 11
my.num2 = 22
print(my.num1,my.num2)

#6.调用类中的成员方法
my.fun1()
my.fun2(30)

#成员变量随着对象的出现而出现的
#属性的动态绑定【Python是一门动态语言】
my.n = 100
print(my.n)

my1 = MyClass()
#print(my1.n)
5.综合案例一

代码演示:

practiceDemo01.py文件【测试模块】

"""
需求:使用面向对象的思想描述下面这个情景
开学了,王老师让小明,小花,小丽分别做自我介绍
需要介绍姓名,年龄,爱好,来一段才艺展示
"""
"""
分析:
老师类
    特性:姓名
    行为:让学生做自我介绍

学生类
    特征:姓名,年龄,爱好
    行为:一段才艺展示
"""
#导入
"""
import  practice01.teacher
import  practice01.student
"""
from practice01.teacher import  Teacher
from practice01.student import Student

#1.创建一个老师的对象
wang = Teacher()
wang.name = "王老师"

#2.创建一个学生的对象
xiaohua = Student()
xiaohua.name = "小花"
xiaohua.age = 18
xiaohua.hobby = "唱歌"

#3.让老师执行自己的行为
wang.letStudentIntroduce(wang.name,xiaohua)   #stu = xiaohua

xiaoli = Student()
xiaoli.name = "小丽"
xiaoli.age = 20
xiaoli.hobby = "跳舞"
wang.letStudentIntroduce(wang.name,xiaoli)

xiaoming = Student()
xiaoming.name = "小明"
xiaoming.age = 25
xiaoming.hobby = "吹牛逼"
wang.letStudentIntroduce(wang.name,xiaoming)

teacher.py文件【实体类】

#老师类
class Teacher():
    #特征:成员变量
    name = ""

    #行为:成员方法
    def letStudentIntroduce(self,name,stu):
        #老师发出指令
        print(name + "让" + stu.name + "做自我介绍")

        #执行指令
        stu.introduce(stu.name,stu.age,stu.hobby)

        #不同的学生展示不同的才艺
        if stu.name == "小花":
            stu.singSong()
        elif stu.name == "小丽":
            stu.dance()
        else:
            stu.lie()

student.py文件【实体类】

#学生类
class Student():
    #特征:成员变量
    name = ""
    age = 0
    hobby = ""

    #行为:成员方法
    def introduce(self,name,age,hobby):
        print("大家好,我是%s,今年%d,爱好%s"%(name,age,hobby))

    #唱歌
    def singSong(self):
        print("娘子~啊哈")

    #跳舞
    def dance(self):
        print("广场舞")

    #吹牛逼
    def lie(self):
        print("我家可穷了,就养了几百头牛")

十七、构造函数和析构函数

1.构造函数【掌握】
采用上面的方式创建对象【直接给成员变量赋值】,很多的类一般倾向于创建成有初始状态的
__init__:构造函数【作用:创建对象,给对象的成员变量赋初始值】
构造函数:构造器
调用的时机:当一个对象被创建的时候,第一个被自动调用的函数
per = Person()

语法:
	def __init__(self,args1,args2....)
		函数体
说明:
	a.之前的写法中并没有显式的定义__init__函数,说明系统默认提供了一个无参的构造函数
	b.args1,args2...一般设置的形参列表和成员变量有关

代码演示:

#1.构造函数被调用的时机
class Check():
    num1 = 0
    str1 = ""

    #构造函数
    def __init__(self):
        print("jfahj")

    def show(self):
        print("show")
#注意:当创建对象的时候,默认调用了系统提供的无参的构造函数
c = Check()
c.show()

#2.给构造函数添加参数
class Check1():
    name = ""
    age = 0
    """
    def __init__(self,n,a):
        print("fajkgak")
    """
    #注意2:当使用构造函数的时候,可以使用无参的,也可以使用有参的,在Python中的解决办法:设置不定长参数
    #注意3:Python中,一个类中只能有一个构造函数
    def __init__(self, *n):
        print("fajkgak")


#注意1:当手动头添加了有参的构造函数之后,系统将不再提供无参的构造函数
c1 = Check1()
c11 = Check1("fsiugh")

#3.有参构造函数的使用
class Check2():
    name = ""
    age = 0

    #构造函数的形参列表:和成员变量有关
    def __init__(self,n,a):
       print(n,a)
       name = n
       age = a

#注意1:当手动头添加了有参的构造函数之后,系统将不再提供无参的构造函数
c2 = Check2("zhangsan",10)
print(c2.name,c2.age)   #0


#4.self的使用
class Check3():
    name = ""
    age = 0

    #构造函数的形参列表:和成员变量有关
    def __init__(self,n,a):
       print(n,a)
       #self的使用:通过self来区分成员变量和局部变量,所以self.name代表name是一个全局变量【成员变量】
       self.name = n
       self.age = a

c3 = Check3("zhangsan",10)
print(c3.name,c3.age)  #10

#5.使用self之后,可以省略成员变量的定义【掌握】
#self只是一个标识符,可以替换成任意的标识符
class Check4():

    #构造函数的形参列表:和成员变量有关
    def __init__(self,name,age):
       print(name,age)
       #self的使用:通过self来区分成员变量和局部变量,所以self.name代表name是一个全局变量【成员变量】
       self.name = name
       self.age = age

    def show(self):
        print("showing")

c4 = Check4("lisi",20)
print(c4.name,c4.age)
c4.show()
2.析构函数
与构造函数正好相反,当对象被销毁的时候自动调用的函数,被称为析构函数
__del__:

删除变量:   del  变量名,此时可以触发析构函数的调用

使用情景:清理工作,比如关闭数据库,关闭文件等

代码演示:

import  time

class Pig():
    def __init__(self,name,age):
        self.name  = name
        self.age = age
        print("构造函数被执行")


    def show(self):
        print("show")

    #析构函数
    def __del__(self):
        print("~析构函数被调用")


#析构函数被调用的时机:1:当程序运行完成的时候    2:使用del删除变量
p = Pig("abc",10)

del p

#注意:对象释放以后就不能再访问了【相当于根本未创建过这个对象】
#print(p.age)

time.sleep(5)

#在函数里定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费
#其实就是作用域的问题
def func():
    per2 = Person("aa", 1, 1, 1)

func()
3.综合案例二

practiceDemo02.py文件【测试模块】

"""
需求:富二代王思聪开着豪车,很自豪的向他的新女友炫耀

富二代类
特征:姓名
行为:开车,炫耀

汽车类
特征:品牌,颜色
行为:奔驰
"""
#测试模块
from  practice02.car import Car
from practice02.richMan import RichMan

#1.创建一个富二代的对象
wang = RichMan("王思聪")

#2.创建一个汽车的对象
c = Car("玛莎拉蒂","闷骚红")
c.run()

#3.让富二代执行自己的行为
wang.driveCar(c)
wang.showCar(c)

richMan.py文件【实体类】

class RichMan():
    #构造函数
    def __init__(self,name):
        self.name = name

    #成员函数
    def driveCar(self,car):
        print("富二代%s开着他的豪车%s"%(self.name,car.brand))
    def showCar(self,car):
        print(car.brand,car.color)

car.py文件【实体类】

class Car():
    #构造函数
    def __init__(self,brand,color):
        self.brand = brand
        self.color = color

    #成员函数
    def run(self):
        print("%s在马路上奔驰"%(self.brand))

十八、封装【private】

1.概念

广义的封装:函数和类的定义本身,就是封装的体现

狭义的封装:一个类的某些属性,在使用的过程 中,不希望被外界直接访问,而是把这个属性给作为私有的【只有当前类持有】,然后暴露给外界一个访问的方法即可【间接访问属性】

封装的本质:就是属性私有化的过程

封装的好处:提高了数据的安全性,提高了数据的复用性

说明:举例:插排,不需要关心属性在类的内部做了什么样的操作,只需要关心将值传进去,或者将结果获取出来

封装: 函数 => 类 => 模块 => 包

2.属性私有化

如果想让成员变量不被外界直接访问,则可以在属性名称的前面添加两个下划线__,成员变量则被称为私有成员变量

私有属性的特点:只能在类的内部直接被访问,在外界不能直接访问

代码演示:

#1.属性不私有化的时候
class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def myPrint(self):
        print(self.name,self.age)

#通过构造函数给属性赋值
per = Person("张三",10)
per.myPrint()   #张三 10
#通过对象直接访问属性,并且给属性赋值
per.name = "李四"
per.age = 22
per.myPrint()   #李四 22

#2.属性私有化
#写法:在属性的前面添加两个下划线
#用法:只能在类的内部被访问,外界不能直接访问
class Person1():
    def __init__(self,name,age):
        self.name = name
        self.__age = age

    def myPrint(self):
        print(self.name,self.__age)

p1 = Person1("abc",10)
p1.myPrint()   #abc 10
p1.name = "hello"
#其实动态绑定属性,age和__age其实是两个不同的变量
p1.age = 222
p1.myPrint()
print(p1.age)

#AttributeError: 'Person1' object has no attribute '__age',私有化了,在外界不能直接访问
#print(p1.__age)
3.get函数和set函数

get函数和set函数并不是系统的函数,而是自定义的,为了和封装的概念相吻合,起名为getXxx和setXxx

get函数:获取值

set函数:赋值【传值】

代码演示:

#3.get函数和set函数
class Person2():
    def __init__(self,name,age):
        self.name = name
        self.__age = age
        #特殊情况一
        self.__weight__ = 20.0
        #特殊情况二
        self._height = 155.0

    def myPrint(self):
        print(self.name,self.__age)

    # 书写私有属性age的get函数和set函数【通过自定义的函数进行私有属性的赋值和获取值,暴露给外界】
    """
    get函数和set函数并不是系统的函数,而是自定义的,为了和封装的概念相吻合,起名为getXxx和setXxx
    get函数:获取值
    set函数:赋值【传值】
    """
    #set函数:给成员变量赋值
    #命名方式:setXxx
    #特点:需要设置参数,参数和私有成员变量有关
    def setAge(self,age):
        #数据的过滤
        if age < 0:
            age = 0
        self.__age = age
    #get函数:获取成员变量的值
    #命名方式:getXxx
    #特点:需要设置返回值,将成员变量的值返回
    def getAge(self):
        return self.__age

    #注意:有几个私有属性,则书写几对get函数和set函数

p2 = Person2("abc",10)
p2.myPrint()   #abc 10
#print(p2.__age)
#间接的访问了私有的成员变量
print(p2.getAge())
p2.setAge(22)
print(p2.getAge())

p2.setAge(-20)
print(p2.getAge())

#总结:通过将属性私有化之后,然后提供get函数和set函数,外部代码就不能随意更改成员变量的值,这样在一定程度上保证了数据的安全性

#4.工作原理【了解】
#当编译器加载了程序之后,不能直接访问p2.__age,Python解释器把__age解释成_Person2__age
#p2.__age = 100
p2._Person2__age = 100
print(p2.getAge())

#5.特殊情况:尽量不要直接访问
#a.在一个变量的前后各加两个下划线,在Python中被认为特殊成员变量,将不再属于私有变量
#print(p2.__weight__)
#b.特殊变量
#print(p2._height)

#面试题:下面变量的含义
"""
xxx:普通的变量
_xxx:受保护的变量,不建议使用这种形式
__xxx:表示私有的,外界无法直接访问,只能通过暴露给外界的函数访问
__xxxx__:一般是系统的内置变量,比如:__name__,__solts__,自定义标识符的时候尽量不要使用这种形式
"""
4.@property装饰器

装饰器的作用:可以给函数动态添加功能,对于类的成员方法,装饰器一样起作用

Python内置的@property装饰器的作用:将一个函数变成属性使用

@property装饰器:简化get函数和set函数

使用:@property装饰器作用相当于get函数,同时,会生成一个新的装饰器@属性名.settter,相当于set函数的作用

作用:使用在类中的成员函数中,可以简化代码,同时可以保证对参数做校验

代码演示:

class Person1():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def myPrint(self):
        print(self.__name,self.__age)

    """
   def setAge(self,age):
        #数据的过滤
        if age < 0:
            age = 0
        self.__age = age

    def getAge(self):
        return self.__age
    """

    #注意:函数的命名方式:变量的名称
    #作用:相当于get函数,设置返回值,将成员变量的值返回
    @property
    def age(self):
        return  self.__age

    #注意:函数的命名方式:需要和@property中函数的命名保持一致
    #作用:相当于set函数,设置参数,给成员变量赋值
    @age.setter
    def age(self,age):
        if age < 0:
            age = 0
        self.__age = age

    @property
    def name(self):
        return  self.__name

    @name.setter
    def name(self,name):
        self.__name = name


p1 = Person1("abc",10)
p1.myPrint()   #abc 10
#p1.setAge(20)
#print(p1.getAge())

print(p1.age)  #10
p1.age = 18   #相当于调用了set函数,将18传值,实质调用的是@age.setter修饰的函数
print(p1.age) #相当于调用了get函数,将成员变量的值获取出来,实质调用的是@peoperty修饰的函数

p1.name = "zhangsan"
print(p1.name)
5.私有方法

如果类中的一个函数名前面添加__,则认为这个成员函数时私有化的

特点:也不能在外界直接调用,只能在类的内类调用

代码演示:

class Site():
    def __init__(self,name):
        self.name = name

    def who(self):
        print(self.name)
        self.__foo()

    #私有成员方法,只能在当前类的内部内调用
    def __foo(self):    #私有函数
        print("foo")

    def foo(self):    #公开函数
        print("foo~~~~")

    #注意:以上两个函数是两个不同的函数,不存在覆盖的问题

s = Site("千锋")
s.who()
#s.__foo()  #AttributeError: 'Site' object has no attribute 'foo'
s.foo()

十九、继承【extends】

1.概念

如果两个或者两个以上的类具有相同的属性或者成员方法,我们可以抽取一个类出来,在抽取的类中声明公共的部分

​ 被抽取出来的类:父类,基类,超类,根类

​ 两个或者两个以上的类:子类,派生类

​ 他们之间的关系:子类 继承自 父类

注意:

​ a.object是所有类的父类,如果一个类没有显式指明它的父类,则默认为object

​ b.简化代码,提高代码的复用性

2.单继承
2.1使用

简单来说,一个子类只能有一个父类,被称为单继承

语法:

父类:

class 父类类名(object):

​ 类体【所有子类公共的部分】

子类:

class 子类类名(父类类名):

​ 类体【子类特有的属性和成员方法】

说明:一般情况下,如果一个类没有显式的指明父类,则统统书写为object

代码演示:

person.py文件【父类】

#1.定义父类
class Person(object):
    #构造函数【成员变量】
    def __init__(self,name,age):
        self.name = name
        self.age = age


    #成员方法
    def show(self):
        print("show")

    def __fun(self):
        print("fun")

worker.py文件【子类1】

from  extends01.person import Person

#2.定义子类
class Worker(Person):
    #构造函数【成员变量】
    def __init__(self,name,age,job):
        """
        self.name = name
        self.age = age
        """
        self.job = job

        #6.在子类的构造函数中调用父类的构造函数【从父类中继承父类中的成员变量】
        #方式一:super(当前子类,self).__init__(属性列表)
        #super(Worker, self).__init__(name,age)
        #方式二:父类名.__init__(self,属性列表)
        Person.__init__(self,name,age)
        #方式三:super().__init__(属性列表)
        #super().__init__(name,age)


    #成员方法
    def work(self):
        print("work")

student.py文件【子类2】

from extends01.person import  Person

class Student(Person):
    # 构造函数【成员变量】
    def __init__(self, name, age, score):

        Person.__init__(self,name,age)
        self.score = score

    # 成员方法
    def study(self):
        print("study")

extendsDemo01.py文件【测试模块】

#测试模块
from extends01.person import Person
from extends01.worker import Worker
from extends01.student import Student

#3.创建父类的对象
p = Person("zhangsan",10)
p.show()
#p.__fun()

#4.创建子类的对象
w = Worker("aaa",20,"工人")
w.work()

#5.子类对象访问父类中的内容
#结论一:子类对象可以调用父类中的公开的成员方法【因为继承,私有方法除外】
w.show()
#w.__fun()
#结论二:通过在子类的构造函数中调用父类的构造函数,子类对象可以直接访问父类中的成员变量【私有变量除外】
print(w.name,w.age,w.job)

s = Student("小明",9,90)
s.study()
s.show()
2.2特殊用法

代码演示:

#6.子类中出现一个和父类同名的成员函数,则优先调用子类中的成员函数
#子类的成员函数覆盖了父类中的同名的成员函数
s = Student("小明",9,90)
s.study()
s.show()

#7.父类对象能不能访问子类中特有的成员函数和成员变量?----->不能
per = Person("gs",10)
#per.work()
#8.slots属性能否应用在子类中
#结论三:在父类中定义slots属性限制属性的定义,子类中是无法使用,除非在子类中添加自己的限制
#父类
class Student(object):
    __slots__ = ("name","age")

#子类
class SeniorStudent(Student):
    pass


s  = Student()
s.name = "zhangsan"
s.age = 10
#s.score = 90

ss = SeniorStudent()
ss.name = "lisi"
ss.age = 20
ss.score = 60

总结:

继承的特点:

​ a.子类对象可以直接访问父类中非私有化的属性

​ b.子类对象可以调用父类中非私有化的成员方法

​ c.父类对象不能访问或者调用子类 中任意的内容

继承的优缺点:

优点:

​ a.简化代码,减少代码的冗余

​ b.提高代码的复用性

​ c.提高了代码的可维护性

​ d.继承是多态的前提

缺点:

​ 通常使用耦合性来描述类与类之间的关系,耦合性越低,则说明代码的质量越高

​ 但是,在继承关系中,耦合性相对较高【如果修改父类,则子类也会随着发生改变】

3.多继承

一个子类可以有多个父类

语法:

class 子类类名(父类1,父类2,父类3.。。。):

​ 类体

代码演示:

father.py文件【父类1】

class Father(object):
    def __init__(self,money):
        self.money = money

    def play(self):
        print("playing")

    def fun(self):
        print("father中的fun")

mother.py文件【父类2】

class Mother(object):
    def __init__(self,faceValue):
        self.faceValue = faceValue

    def eat(self):
        print("eating")

    def fun(self):
        print("mother中的fun")

child.py文件【子类】

from extends02.father import Father
from extends02.mother import Mother

#定义子类,有多个父类
class Child(Mother,Father):
    def __init__(self,money,faceValue,hobby):
        #调用父类中的构造函数
        Father.__init__(self,money)
        Mother.__init__(self,faceValue)
        self.hobby = hobby

    def study(self):
        print("study")

extendsDemo03.py文件【测试模块】

from extends02.father import Father
from extends02.mother import Mother
from extends02.child import Child


f = Father(100000)
m = Mother(3.0)

#创建子类对象
c = Child(1000,3.0,"打游戏")
#子类对象调用父类中的成员方法
c.play()
c.eat()

#结论;如果多个父类中有相同的函数,通过子类的对象调用,调用的是哪个父类中的函数取决于在父类列表中出现的先后顺序
c.fun()
4.函数重写【override】

在子类中出现和父类同名的函数,则认为该函数是对父类中函数的重写

4.1系统函数重写
__str__   
__repr__

代码演示:

class Animal(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    #重写__str__函数,重写之后一般return一个字符串,有关于成员变量
    def __str__(self):
        return "name=%s age=%d"%(self.name,self.age)

    #重写__repr__,作用和str是相同的,优先使用str
    def __repr__(self):
        return "name=%s age=%d"%(self.name,self.age)

a = Animal("大黄",10)
print(a)   #<__main__.Animal object at 0x00000226A87AC240>
print(a.__str__())

#当一个类继承自object的时候,打印对象获取的是对象的地址,等同于通过子类对象调用父类中__str__
#当打印对象的时候,默认调用了__str__函数
#重写__str__的作用:为了调试程序

"""
总结:【面试题】
a.__str__和__repr__都未被重写的时候,使用对象调用的是__str__,此时__str__返回的是对象的地址
b.__str__和__repr__都被重写之后,使用对象调用的是__str__,此时__str__返回的是自定义的字符串
c.重写了__str__,但是没有重写__repr__,则使用对象调用的是__str__,此时__str__返回的是自定义的字符串
d.未重写__str__,但是重写了__repr__,则使用对象调用的是__repr__,此时,__repr__返回的是自定义的字符串
"""

#使用时机:当一个对象的属性有很多的时候,并且都需要打印,则可以重写__str__,可以简化代码,调试程序
4.2自定义函数重写

代码演示:

#函数重写的时机:在继承关系中,如果父类中函数的功能满足不了子类的需求,则在子类中需要重写
#父类
class People(object):
    def __init__(self,name):
        self.name = name

    def fun(self):
        print("fun")

#子类
class Student(People):
    def __init__(self,name,score):
        self.score = score
        super(Student,self).__init__(name)

    #重写;将函数的声明和实现重新写一遍
    def fun(self):
        #在子类函数中调用父类中的函数【1.想使用父类中的功能,2.需要添加新的功能】
        #根据具体的需求决定需不需要调用父类中的函数
        super(Student,self).fun()
        print("fajfhak")


s = Student("fhafh",10)
s.fun()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不能say的秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值