python基础2(函数 内置函数 类)
函数
定义
def 关键字 -- 定义
func 函数名 -- 和变量定义规则一样
() 必须要写格式
: 声明语句结束
def my_len()
函数体
例子:
def my_len():
s = (1,2,3,4,5,6)
count = 0
for i in s:
count += 1
print(count)
def yue():
print("打开手机") # 打开手机
print("打开微信") # 打开微信
print("找到女友") # 找到女友
print("晚上约么") # 晚上约么
yue()
函数的返回值
关键字 return
print(12)
def yue():
print("打开手机")
print("打开微信")
return 111
print("找到女友")
print("晚上约么")
return "萝莉小姐姐","大妈","人妖" # return 返回
print("确实有点累")
print(yue()) #111
有return和没有return
lst = [1,2,3,4,5,6]
def func():
for i in lst:
print(i)
print(func()) # None
lst = [1,2,3,4,5]
def func():
for i in lst:
print(i)
lst.append(input(">>>"))
return lst
print(func())
'''
1
2
3
4
5
>>>9
[1, 2, 3, 4, 5, '9']
注意事项
return的内容返回给了函数的调用
return下方的代码不执行,终止这个函数
return 返回多个内容的时候还是元组形式
return 没有写返回值的时候返回的是None,不写return返回的也是None
位置传参
def yue(a,b,c): # 形参
print("打开手机")
print(f"打开{a}{c}{b}")
print("附近的人")
print("找个妹子")
print("聊一聊")
yue(True,(12,4,3),[1,2,3,4]) # 实参
def func(a,b=1): # b=1 默认参数
print(a,b)
func(3,8)
def userinfo(name,age,sex="男"): 位置参数 > 默认参数
print(name,age,sex)
count = 5
while count:
name = input("name:")
sex = input("sex:")
age = input("age")
if sex == "女":
userinfo(name,age,sex)
else:
userinfo(name,age)
count -= 1
def func(a,c,b=1): a,c位置参数 ,b=1 是默认参数
print(a,b,c)
func(1,2,5)
func(a=1,b=5,c=2) # a=1,b=5,c=2 是关键字参数
def func(a,b,c):
print(a,b,c)
func(1,2,c=5) # 混合参数
形参: 函数的定义中括号里是形参
实参: 函数的调用括号里是实参
位置传参时 形参和实参必须一一对应
传参: 将实参传递给形参的过程就是传参
总结:# 函数的参数:
# 形参: 函数定义的时候叫做形参
# 位置参数
# 默认参数
# 混合参数
# 实参: 函数调用的时候叫做实参
# 位置参数
# 关键字参数
# 混合参数
# 传参: 将实参传递给形参的过程叫做传参
1.函数的动态参数
动态参数
*args,**kwargs (能够接受动态的位置参数和动态的关键字参数)
定义阶段(*args,**kwargs) 聚合
*args - tuple
**kwargs -- dict
使用阶段args,kwargs 打散
*args - 源数据类型
*kwargs - 打散是字典的键
*args
def func(a,b,*args):
print(a,b,args)
func(1,2,3,4,5,6,7,8,9)
# 1 2 (3, 4, 5, 6, 7, 8, 9)
def func(a,b,*args):
# *args 是万能(接受任意多个)的位置参数
# *在函数定义的时候叫做聚合
print(a,b,*args)
# * 打散 1 2 3 4 5 6 7 8 9
**kwargs
def func(a,b,**kwargs):
print(a,b,kwargs)
# 字典(接受的关键字的参数)
func(1,2,c=1,d=2)
# 1 2 {'c': 1, 'd': 2}
def func(a,b,*args,c=1,d=2,**kwargs):
print(a,b,*args,c,d,kwargs)
func(1,2,3,4,c=8,d=10,e="alex",f="wusir")
#1 2 3 4 8 10 {'e': 'alex', 'f': 'wusir'}
万能传参
def func(*agrs,**kwargs):
print(agrs,kwargs)func(1,2,3,4,5,6,7,8,a=1,b=2,c=3)
# (1, 2, 3, 4, 5, 6, 7, 8) {'a': 1, 'b': 2, 'c': 3}
重点总结:
1.参数的优先级:位置参数 > 动态位置参数 > 默认参数(关键字参数) > 动态关键字参数
2.万能传参:动态位置参数,动态关键字参数(常用)
3.动态位置参数,关键字参数,动态关键字参数
2.函数的注释
def func(a,b):
""" 注释:敲六个' " ',回车
:param a:
:param b:
:return:
"""
print(a,b)
def func1(user,password):
""" 密码加密
:param user: 用户名 str
:param password: 密码 str
:return: 加密的密码 MD5
"""
print(user,password)
print(func.__doc__)
# 查看函数注释print(func.__name__)
# 查看函数命名
3.名称空间
def fun():
a = 10
print(a)fun()print(a)
# a不存在了已经..
命名空间分类:
内置空间 : print input len 全局空间 : 当前py文件需要开辟的空间存放在全局空间 局部空间 : 函数中开辟的空间就是局部空间
加载顺序:
内置空间 > 全局空间 > 局部空间
取值顺序:
局部空间 > 全局空间 > 内置空间(找不到就报错了!)
作用域:
全局作用域: 内置空间 + 全局空间
局部作用域: 局部空间
4.函数的嵌套
def func():
print(1)
def f1():
print(2)
return
f1()
func()
# 1 2
不管在什么位置,只要是函数名+() 就是在调用此函数函数调用执行后,函数体中开辟的空间就自动销毁了
示例
def func():
a = 1
def foo():
b = 2
print(b)
print(a)
def f1():
print(b)
return f1()
return foo()
print(func())
# 2 1 2 None
globle 与 nonlocal
# 报错局部空间内没有a的值
global : 修改全局空间的变量对应的值
nonlocal :在外层的函数中,修改局部空间的变量值.完全不涉及全局变量,只修改离它最近的一层,最近的一层没有变量继续向上找,直到找到最外层函数
函数名的第一类对象及使用
函数名可以当做值被赋值
def func():
print(1)print(func)a = funca()
# <function func at 0x000001A24F8E9B70> 1
函数名可以当做元素存放在容器中
def func():
print(1)
lst = [func,func,func]
for i in lst:
i()
# 1 1 1
函数名可以当做另一个函数的参数
函数名可以当做返回值
函数与方法
通过打印函数名的方式区别方法和函数
def func1():
passclass A:
def func(self):
pass
# 通过类名调用的类中的实例方法叫做函数
print(func1)
print(A.func)
# 通过对象调用的类中的实例方法叫方法
obj = A()print(obj.func)
from types import FunctionTypefrom types
import MethodTypedef
func():
passclass A:
def func(self):
passobj = A()print(isinstance(func, FunctionType))
print(isinstance(A.func, FunctionType))
print(isinstance(obj.func, FunctionType))
print(isinstance(obj.func, MethodType))
"""TrueTrueFalseTrue"""
总结
python 中一切皆对象, 类在某种意义上也是一个对象, python中自己定义的类, 以及大部分内置类, 都是由type元类(构建类)实例化得来的
python 中一切皆对象, 函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化出来的
python 中一切皆对象, 方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的
如何判断方法还是函数
函数都是显性传参, 方法都是隐性传参
特殊的双下方法
特殊的双下方法:
原本是开发python这个语言的程序员用的, 源码中使用的
双下方法: 你不知道你干了什么就触发某个双下方法
len
class B: def __init__(self, name, age):
self.name = name
self.age = age
def __len__(self):
print(self.__dict__)
return len(self.__dict__)
b = B("liye", 28)print(len(b))
"""{'name': 'liye', 'age': 28}2"""print(len({"name": "leye", "age":28}))"""2"""
# len()就会触发__len__方法
hash
class A:
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()print(hash(a))"""-855395274340638840"""
str ***
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
print(666)
return
(f"姓名:{self.name} 年龄:{self.age}")
a = A("赵海狗", 35)
b = A("李业", 56)
c = A("华丽", 18)
print(f"{a.name}{a.age}")print(f"{b.name}{b.age}")
print(f"{c.name}{c.age}")
"""赵海狗35李业56华丽18
"""
# 打印对象触发__str__方法
print(a)
print(b)
print(c)
"""666
姓名:赵海狗 年龄:35666姓名:李业 年龄:56666姓名:华丽 年龄:18"""
# 直接str转化也可以触发print(str(a))
"""666姓名:赵海狗 年龄:35"""
repr
class A: def __init__(self,name,age): self.name = name self.age =age def __repr__(self): print(666) return f'姓名: {self.name} 年龄: {self.age}'a = A('赵海狗',35)b = A('李业',56)c = A('华丽',18)print(a)print(repr(a))"""666姓名:赵海狗 年龄:35666姓名:赵海狗 年龄: 35"""# 用法同 __str__
call ***
# 对象() 自动触发对象从属于类(父类)的__call__方法
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo()obj()
"""__call__"""
eq
class A(object):
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
x = A()y = A()print(x == y)"""True"""
del
# 析构方法,当对象在内存中被释放时,自动触发执行。
# 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。class A:
def __del__(self):
print(666)
obj = A()del
obj"""666"""
new
class A(object):
def __init__(self):
self.x = 1
print("in init function")
def __new__(cls, *args, **kwargs):
print("in new function")
return object.__new__(A)a = A()
"""in new functionin init function"""
# 对象是object类的__new__方法 产生一个对象# 类名()
# 1.先触发 object 的__new__方法, 此方法在内存中开辟一个对象空间.
# 2.执行__init__方法,给对象封装属性
单例模式
class A:
__instance = None
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instanceobj = A("alex")
print(obj)
obj1 = A("李业")obj2 = A("wusir")
print(obj1.name)
print(obj.name)
print(obj2.name)
"""<__main__.A object at 0x000001E4CFC676A0>wusirwusirwusir"""
item
# __getitem__
__setitem__
__delitem__
对对象做类似于字典的 (增删改查) 触发__item__系列
# __delattr__ del
obj.属性 就会触发此方法
class Foo:
def __init__(self, name):
self.name = name
def __getitem__(self, item):
print(item)
print(666)
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
print(key)
print(value)
def __delitem__(self, key):
print("del obj[key]时, 我执行")
def __delattr__(self, item):
print(f"对象的{item}属性已经删除")
f1 = Foo("sb")print(f1["name"])
f1[1] = 2del
f1[1]del
f1.name
"""name666sb12del obj[key]时, 我执行对象的{name}属性已经删除"""
enter exit
class A:
def __init__(self, name):
self.name = name
def __enter__(self):
print(666)
def __exit__(self, exc_type, exc_val, exc_tb):
print(777)
# 第一种实例化方式obj = A("海狗")
# 第二种实例化方式, 必须基于__enter__ 和 __exit__这两个方法with A("海狗") as obj: print(obj.name)
class A:
def __init__(self, text):
self.text = text
def __enter__(self):
# 开启上下文管理器对象时触发此方法
self.text = self.text + '您来了' # 第一步
print(11111)
return self
# 必须!!!将实例化的对象返回f1
def __exit__(self, exc_type, exc_val, exc_tb):
# 执行完上下文管理器对象f1时触发此方法
print(333)
# 第三步
self.text = self.text + ',这就走了'with A('大爷') as f1: print(2222) print(f1.text)
# 第二步print(f1.text)
# 第四步"""111112222大爷您来了333大爷您来了,这就走了"""
iter
class A:
def __init__(self, name):
self.name = name
def __iter__(self):
for i in range(10):
yield i
# def __next__(self):
# passobj = A("李业")
print('__iter__' in dir(obj))
print(hasattr(obj, "__iter__"))
# 以上两行都在判断对象是否具有__iter__for i in obj: print(i)
内置函数(一)
| 函数名 | 描述 |
|---|---|
| all() | 判断可迭代参数中的所有元素是否都为 True |
| any() | 判断可迭代参数中的所有元素是否都为 False如果有一个为True则返回True |
| bytes() | 返回一个根据参数 source 生成的字节数组(bytes)对象 |
| callable() | 查看是否可调用 |
| chr() | 用一个范围在0~255整数作参数,返回一个对应的字符 |
| complex() | 创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数 |
| divmod() | 返回一个包含商和余数的元组 |
| eval() | 执行一个字符串表达式,并返回表达式的值 |
| exec() | 动态执行python代码 |
| format() | 增强字符串格式化的功能 |
| frozenset() | 返回一个冻结的集合 |
| globals() | 以字典类型返回当前位置的全部全局变量 |
| hash() | 用于获取取一个对象(字符串或者数值等)的哈希值 |
| help() | 查看函数或模块用途的详细说明 |
| id() | 获取对象的内存地址 |
| input() | 接受一个标准输入数据,返回为 str 类型 |
| int() | 将一个字符串或数字转换为整型 |
| iter() | 生成迭代器 |
| locals() | 以字典类型返回当前位置的全部局部变量 |
| next() | 返回迭代器的下一个项目 |
| oct() | 将一个整数转换成8进制字符串 |
| ord() | 以一个字符作为参数,返回对应的 ASCII 数值,或者 Unicode 数值 |
| pow() | 方法返回x的y次方的值。 |
| repr() | 将对象转化为供解释器读取的形式 |
| round() | 返回浮点数x的四舍五入值 |
eval() 执行字符串类型的代码,并返回最终结果exec() 执行字符串类型的代码以上两个函数很强大,工作中禁止使用hash() 获取一个对象(可哈希对象:int,str,bool,tuple)的哈希值help() 函数用于查看函数或模块用途的详细说明callable() 函数用于检查一个对象是否是可调用的,如果返回True,仍然可能调用失败;但如果返回False,调用对象object绝对不会成功int() 函数用于将一个字符串或数字转换为整型float() 函数用于将整数和字符串转换成浮点数complex:函数用于创建一个值为 real + imag*j 的复数.如果第一个参数为字符串,则不需要指定第二个参数bin() 将十进制转换成二进制oct() 将十进制转换成十六进制字符串并返回divmod() 计算除数与被除数的结果,返回一个包含商和余数的元组round() 保留浮点数的小数位数,默认保留整数pow() 求x**y次幂bytes() 用于不同编码之间的转化ord() 输入当前编码的位置数字找出其对应的字符repr() 返回一个对象的string形式all() 可迭代对象中,全都是True才是Trueany() 可迭代对象中,有一个True 就是True
内置函数(二)
| 函数名 | 描述 | 语法 |
|---|---|---|
| abs() | 绝对值 | abs(数字) |
| filter() | 过滤,返回一个迭代器对象的内存地址 | filter(函数名,可迭代对象) |
| map() | 指定元素操作,返回一个迭代器对象的内存地址 | map(函数名,可迭代对象) |
| zip() | 拉链,可迭代对象是字典的时候只获取键,返回一个迭代器对象的内存地址 | zip(可迭代对象,...可迭代对象) |
| sorted() | 排序,默认为升序,返回一个新列表不修改原基础,指定reverse为True 时为降序 | sorted(可迭代对象,key=函数名,reverse=True) |
| reversed() | 反转,返回一个迭代器对象的内存地址 | reversed(可迭代对象) |
| max() | 最大值,可以自定义规则 | max(可迭代对象,key=规则) |
| min() | 最小值,可以自定义规则 | min(可迭代对象,key=规则) |
| sum() | 求和,不能使用字符串 | sum(可迭代对象) |
| reduce() | 累计算,函数要有两个形参,不能使用字符串 | reduce(函数名,可迭代对象) |
| format() | 除了格式化还可以进行进制转换,b二进制 d十进制 o八进制 x16进制,>右对齐,<左对齐,^居中,可以指定位数 | format(整数."8b")format(元素,">20") |
内置函数
1.abs( ) print([abs(i) for i in lst])# 绝对值 -- 返回的都是正数
2.enumerate( )lst = [(0,1)(1,2)(2,3)]print([i for i in enumerate(lst,10)])# 枚举("可迭代对象","序号的起始值") 默认的起始值是 0
3.max( ) print(max([1,2,3,4,56,7,8]))# 求最大值print(max([1,2,-33,4,5],key=abs))# key指定查找最大值的规则
4.min( )print(min([1,2,3,4,-56,7,8]))# 求最小值
5.sum( )print(sum([1,2,3,4,5],100))# 求和
6.python3 中:range( )g = range(0,10)g.__iter__()# 范围 本身是一个可迭代对象 有__iter__()方法python2 中:range( )# 获取的是一个列表Xrange( )# 获取的是一个可迭代对象
7.open( )# 文件操作
8.print( )print(sep=" ",end="\n" )print(1,2,3,sep=" ")# sep是多个元素的连接符
9.len( )# 公共方法,求长度的函数(除数字和bool值)
10.list( )# 列表
11.dict( )print(dict([i for i in enumerate(range(20),1)]))# 字典
12.zip( )lst = [1,2,3,4,5]lst1 = ["a","b","c","d","f","e"]print(dict(list(zip(lst,lst1))))# 拉链 -- 按照最少的进行合并
13.dir( )print(dir(list))# 查看当前函数的方法
匿名函数
f = lambda x,y:(x,y)
print(f(1,2))print(f.__name__)
print((lambda x:x)(2))
# 同一行定义 同一行调用lambda
# 关键字 -- 定义函数x,y
# 形参:x+y
# 返回值 -- 只能返回一个数据类型
示例:
lst = [lambda i:i*i for i in range(10)]print(lst[2](2))
拆解
lst = []
for i in range(10):
def func(i):
return i*i
lst.append(func)
print(lst[2](2))
示例
lst = [lambda :i*i for i in range(10)]print(lst[2]())# 81#
拆解
lst = []
for i in range(10):
def func():
return i*i
lst.append(func)
print(lst[2]())
# 一行函数# 形参可以不写# 返回值必须要写,返回值只能返回一个数据类型
内置函数(重要)
1.format( )print(format(13,">20"))
# 右对齐print(format(13,"<20"))
# 左对齐print(format(13,"^20"))
# 居中print(format(13,"08b"))
# 2进制print(format(13,"08d"))
# 10进制print(format(13,"08o"))
# 8进制print(format(12,"08x"))# 16进制
2.filter( )
# 过滤
lst = [1,2,3,4,5,6]
def func(s):
return s > 3
print(list(filter(func,lst)))
# func就是自己定义一个过滤条件,lst 要迭代的对象
lst = [1,2,3,4,5,6,7]
print(list(filter(lambda x:x % 2 == 1,lst)))
3.map( )
print(list(map(lambda x:x*x,[1,2,3,8,4,5])))
# 对象映射
# 对可迭代对象中的每个元素进行加工
4.reverse( )
reversed( )
# 两者都是反转 前者在源数据上进行反转 后者开辟新空间进行反转,不影响源数据
5.sort( )sorted( )
# 两者都是排序 前者在源数据上进行排序 后者开辟新空间进行排序,不影响源数据
lst = [1,23,34,4,5,213,123,41,12,32,1]print(sorted(lst))
print(lst)# 升序lst = [1,23,34,4,5,213,123,41,12,32,1]print(sorted(lst,reverse=True))
# 降序dic = {"key":1,"key1":2,"key3":56}print(sorted(dic,key=lambda x:dic[x],reverse=True))
# 指定key的排序规则
6.reduce( )
from functools import reduceprint
(reduce(lambda x,y:x+y,[1,2,3,4,5]))# 累计算
面向对象初识
1.函数式编程 对 面向过程编程的两个特点
- 减少代码的重复性
- 增强代码的可读性
2.面向对象编程 对 面向过程编程
2.1 什么是面向对象
面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。
2.2 什么是类,什么是对象
类:就是具有相同属性和功能的一类事物。
对象:就是类的具体表现。
3.类的结构
class Human:
""" 此类主要是构建人类
""" mind = '有思想'
# 第一部分:静态属性 属性 静态变量 静态字段
dic = {}
l1 = []
def work(self):
# 第二部分:方法 函数 动态属性
print('人类会工作')
class 是关键字与def用法相同,定义一个类。Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。类的结构从大方向来说就分为两部分:静态变量。动态方法。
从类名的角度研究类
class Human:
""" 类的具体结构 """
# 第一部分:静态属性
mind = '有思想'
# 类的属性 (静态属性, 静态字段)
language = '使用语言'
# 第二部分: 动态方法
def work(self):
print('人类都会工作')
def eat(self):
print('人类都需要吃饭')
1. 类名操作类中的属性
1. 类名查看类中所有的内容print(Human.__dict__)
2. 类名操作类中的静态属性 万能的点.增:Human.body = '有头和四肢'删:del Human.mind改:Human.mind = 'liye脑残'查:print(Human.language)print(Human.__dict__)
2. 类名调用类中的方法(一般类中的(静态方法,类方法)方法不会通过类名调用)Human.work(111)总结:一般类名就是操作类中的属性.
从对象角度研究类
class Human:
""" 类的具体结构 """
# 第一部分:静态属性
mind = '有思想'
# 类的属性 (静态属性, 静态字段)
language = '使用语言'
def __init__(self):
# print(f'self---->: {self}')
# print(666)
self.name = '李业'
self.age = 18
# 第二部分: 动态方法
def work(self):
print('人类都会工作')
def eat(self):
print('人类都需要吃饭')obj = Human()
# 实例化过程得到一个返回值,这个返回值就是 对象,实例.print(f'obj---> {obj}')实例化一个对象发生了三件事:'''
1. 开辟一个对象空间.
2. 自动执行__init__方法,并且将对象地址传给self.
3. 运行__init__方法内的代码,给对象空间封装属性.'''class Human: """ 类的具体结构 """
# 第一部分:静态属性
mind = '有思想'
# 类的属性 (静态属性, 静态字段)
language = '使用语言'
def __init__(self, name, age):
# print(f'self---->: {self}')
# print(666) self.n = name
self.a = age
# 第二部分: 动态方法
def work(self):
# print(f'self---> {self}')
print(f'{self.n}都会工作')
def eat(self):
print(f'{self.n}都需要吃饭')
obj = Human('李业',18)
# 实例化过程print(obj.n)print(obj.a)print(obj.__dict__)
对象操作对象空间的属性
1. 对象查看对象的空间的所有属性
obj = Human('李业',18)
print(obj.__dict__)
2. 对象操作对象空间的属性
obj = Human('李业',18)
增:obj.sex = 'laddy_boy'
删:del obj.a
改:obj.a = 1000
查:print(obj.n)print(obj.__dict__)
对象查看类中的属性
obj = Human('李业',18)
# print(obj.mind)
obj.mind = '无脑的'
print(obj.mind)
print(Human.mind)
对象调用类中的方法
obj = Human('孙戴维', 23)
# print(f'obj---> {obj}')
obj.work()obj.eat()
一个类可以实例化多个对象
obj1 = Human('李业',18)
obj2 = Human('小可爱', 16)
obj3 = Human('怼姐', 18)
变量,函数名:
age_of_oldboy = 73Ageofoldboy
1.类的空间问题
1.1何处可以添加对象属性
class A:
def __init__(self,name):
self.name = name
def func(self,sex):
self.sex = sex
# 类外面可以:
obj = A("barry")
obj.age = 18print(obj.__dict__)
# ("name": "barry", "age": 18)
# 类内部也可以
obj = A("barry")
obj.func("男")# __init__方法可以
# func 方法也可以
总结:
对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加
1.2何处可以添加类的静态属性
class A:
def __init__(self,name):
self.name = name
def func(self,sex):
self.sex = sex
def func1(self):
A.bbb = 'ccc'
# 类的外部可以添加A.aaa = 'taibai'print(A.__dict__)
# 类的内部也可以添加。A.func1(111)print(A.__dict__)
总结:
类的属性不仅可以在类内部添加, 还可以在类的外部添加
1.3对象如何找到类的属性
总结:
对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........
上面的顺序都是单向不可逆,类名不可能找到对象的属性。
2.类与类之间的关系
2.1依赖关系
将一个类的类名或者对象传入另一个类的方法中
class Elephant:
def __init__(self, name):
self.name = name
def open(self, obj):
print(f"{self.name}开门")
obj.be_open()
def close(self):
print(f"{self.name}关门")
class Refrigerator:
def __init__(self, name):
self.name = name
def be_open(self):
print(f"{self.name}被打开")
def be_close(self):
print(f"{self.name}被关闭")
daxiang = Elephant("大象")
bingxiang = Refrigerator("冰箱")daxiang.open(bingxiang)
2.2组合关系
给一个类的对象封装一个属性,此属性为另一个类的对象
class Boy:
def __init__(self, name,girlfriend=None):
self.name = name
self.girlfriend = girlfriend
def have_a_diner(self):
if self.girlfriend:
print(f'{self.name}请他的女朋友{self.girlfriend}一起烛光晚餐')
else:
print('单身狗,吃什么吃')
liye = Boy('李业')
# 只是给李业封装了一个属性:
girlfriend 为一个字符串的数据
liye.girlfriend = '乔碧萝'
liye.have_a_diner()
class Boy:
def __init__(self, name,girlfriend=None):
self.name = name
self.girlfriend = girlfriend
def have_a_diner(self):
if self.girlfriend:
print(f'{self.name}请他的{self.girlfriend.age}岁的,{self.girlfriend.body}的女朋友{self.girlfriend.name}一起烛光晚餐')
else:
print('单身狗,吃什么吃')
def girl_skill(self):
print(f'{self.name}的女朋友的技能:')
self.girlfriend.skill()class Girl:
def __init__(self,name,age,body):
self.name = name
self.age = age
self.body=body
def skill(self):
print(f'{self.name} 会用萝莉音直播')
liye = Boy('李业')
qiao = Girl('乔碧萝', 58, '小钢炮')
# 给liye封装了另一个类中的对象
liye.girlfriend = qiao
liye.have_a_diner()
# liye.girl_skill()
组合与依赖的例子
class GameRole:
def __init__(self, name, ad, hp):
self.name = name
self.ad = ad
self.hp = hp
def attack(self, p1):
p1.hp = p1.hp - self.ad
print(f"{self.name}攻击{p1.name}, 谁掉了{self.ad}血, 还剩{p1.hp}血")
print(f"{p1.name}的血量{p1.hp}")
def equipment_wea(self, wea):
self.weapon = weaclass Weapon:
def __init__(self, name, ad):
self.name = name
self.ad = ad
def weapon_attack(self, p1, p2):
p2.hp = p2.hp - self.ad
print(f"{p1.name}利用{self.name}给了{p2.name}一下子,{p2.name}掉了{self.ad}血,还剩{p2.hp}血")gailun = GameRole("盖伦", 10, 100)
xin = GameRole("赵信", 20, 80)
sword = Weapon("大宝剑", 15)
musket = Weapon("长缨枪", 30)gailun.equipment_wea(sword)
gailun.weapon.weapon_attack(gailun, xin)
继承
1.继承初识
如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。
2.继承的优点
继承的优点也是显而易见的:
1,增加了类的耦合性(耦合性不宜多,宜精)。
2,减少了重复代码。
3,使得代码更加规范化,合理化。
3.单继承和多继承
单继承
1.类名执行父类属性方法
class Animal:
live = "有生命的"
def __init__(self, name, sex, age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print("会吃")class Human(Animal):
body = "有头有脸"
print(Human.live)
Human.eat(123)
2.对象执行父类属性方法
class Animal:
live = "有生命的"
def __init__(self, name, sex, age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print("会吃")
class Human(Animal):
live = "有思想的活着"
body = "有头有脸"
liye = Human("李业", "男", 18)
print(liye.live)
liye.eat()
3.在子类中既执行子类方法,又执行父类方法
不依赖继承的方法
class Animal:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("动物都需要吃饭")
class Human:
def __init__(self, name, sex, age, hobby):
Animal.__init__(self, name, sex, age)
self.hobby = hobby
def eat(self):
print(f"{self.name}都需要吃饭")
obj = Human("李业", "男", 23, "旅游")print(obj.hobby)
依赖继承的方法
class Animal:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("动物都需要吃饭")
class Human(Animal):
def __init__(self, name, sex, age, hobby):
super().__init__(name, sex, age)
self.hobby = hobby
def eat(self):
super().eat()
print(f"{self.name}都需要吃饭")
obj = Human("李业", "男", 23, "旅游")
print(obj.hobby)
多继承
在python2x版本中存在两种类.: ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写,就什么都不继承 ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。 python3x版本中只有一种类: python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
经典类
不继承object类, 深度优先原则
新式类
新式类:继承object类. mro(C3)算法
经典类的深度优先
class A:
passclass B(A):
passclass C(A):
passclass D(B, C):
passclass E:
passclass F(D, E):
passclass G(F, D):
passclass H:
passclass Foo(H, G): pass
三大特性
封装
把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.
继承
⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精.
多态
同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "alex", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态
类的约束
类的约束有两种:
第一种:抛出异常
提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
class Payment:
def pay(self,money):
raise Exception("子类设置pay方法")
class QQpay(Payment):
def pay(self,money):
print(f"QQ支付{money}金额")
class Alipay(Payment):
def pay(self,money):
print(f"支付宝支付{money}金额")
class Wechatpay(Payment):
def zhifu(self,money):
print(f"微信支付{money}金额")
def pay(obj,money):
obj.pay(money)
obj1 = QQpay()
pay(obj1,100)
obj2 = Alipay()
pay(obj2,200)
obj3 = Wechatpay()
pay(obj3,300)
"""QQ支付100金额
Traceback (most recent call last):支付宝支付200金额File "D:/pycharm demo/练习/代码练习.py", line 30, in <module> pay(obj3,300)File "D:/pycharm demo/练习/代码练习.py", line 20, in pay obj.pay(money)File "D:/pycharm demo/练习/代码练习.py", line 3, in pay raise Exception("子类设置pay方法")Exception: 子类设置pay方法"""
第二种:使用元类
使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
passclass QQpay(Payment):
def pay(self,money):
print(f"QQ支付{money}金额")
class Alipay(Payment):
def pay(self,money):
print(f"支付宝支付{money}金额")
class Wechatpay(Payment):
def zhifu(self,money):
print(f"微信支付{money}金额")
def pay(obj,money):
obj.pay(money)
obj1 = QQpay()
pay(obj1,100)
obj2 = Alipay()
pay(obj2,200)
obj3 = Wechatpay()
pay(obj3,300)
"""QQ支付100金额Traceback (most recent call last):支付宝支付200金额File "D:/pycharm demo/练习/代码练习.py", line 63, in <module> obj3 = Wechatpay()TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay"""
super的深度剖析
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class Foo(A):
def f1(self):
super().f2()
print('in A Foo')
obj = Foo()obj.f1()
"""'in A f2''in A Foo'"""
super可以执行下一个类的其他方法
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo,Bar):
def f1(self):
super().f1()
print('in Info f1')
obj = Info()
obj.f1()
'''in Barin Fooin Info f1'''
print(Info.mro())
# [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]super()严格按照类的mro顺序执行class A: def f1(self): print('in A')class Foo(A): def f1(self): super().f1() print('in Foo')class Bar(A): def f1(self): print('in Bar')class Info(Foo,Bar): def f1(self): super(Foo,self).f1() print('in Info f1')obj = Info()obj.f1()"""in Barin Info f1"""
类的私有成员
私有类的属性
在类的内部可以访问
class A:
name = "李业"
__name = "钢哥"
def func(self):
print(self.name)
print(self.__name)
obj = A()obj.func()"""李业钢哥"""
在类的外部不能访问
class A:
name = "李业"
__name = "钢哥"
def func(self):
passobj = A()
print(obj.name)
print(A.__name)
print(obj.__name)"""李业无法找到无法找到"""
在类的派生类不能访问
class A:
name = "李业"
__name = "钢哥"
class B(A):
def func(self):
print(self.__name)
obj = B()
print(obj.__name)
obj.func()
私有对象属性
只能在类的内部使用,不能在类外部以及派生类使用
class A:
def __init__(self, name, pwd):
self.name = name
self.__pwd = pwd
def md5(self):
self.__pwd = self.__pwd + "123"
obj = A("李业", "liyedsb")
print(obj.__pwd)"""无法找到"""
私有类的方法
class A:
def func(self):
self.__func()
print("in A func")
def __func(self):
print("in A __func")
obj = A()
obj.func()
"""in A __funcin A func"""obj.__func()"""无法找到"""
对于私有成员来说: 当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员
特殊方法(默认不使用)
class A:
name = "李业"
__name = "钢哥"
def __func(self):
print("in __func")
print(A.__dict__)
"""{'__module__': '__main__', 'name': '李业', '_A__name': '钢哥', '_A__func': <function A.__func at 0x000002F6FFB79A60>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}"""print(A._A__name)"""钢哥"""
# 类从加载时, 只要遇到类中的私有成员, 都会在私有成员前面加上 _类名
类的其他方法
类方法
class A:
def func(self):
print("实例方法")
@classmethod
def cls_func(cls):
print(f"cls---->{cls}")
obj = cls()
print(obj)
print("类方法")
print(A)
A.cls_func()
"""<class '__main__.A'>cls----><class '__main__.A'><__main__.A object at 0x000001C3B5F874E0>类方法"""obj = A()obj.cls_func"""输出为空,因为cls_func是一个类方法,传入cls的是类的内存地址,所以对象无法调用"""
# 类方法,一般就是通过类名去调用的方法,并且自动将类名地址传给cls,但是如果通过对象调用也可以,但是传的还是类名地址A.cls_func()"""cls----><class '__main__.A'><__main__.A object at 0x00000234B9C17630>类方法"""
类方法有什么用
1.得到类名可以实例化对象
2.可以操作类的属性
简单引用
创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化多少个学生
class Student:
count = 0
def __init__(self,name,id):
self.name = name
self.id = id
Student.addnum()
@classmethod
def addnum(cls):
cls.count = cls.count + 1
@classmethod
def getnum(cls):
return cls.count
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
obj1 = Student('liye', 12343243243)
print(Student.getnum())
静态方法
class A:
def func(self):
print("实例方法")
@classmethod
def cls_func(cls):
pass
@staticmethod
def static_func():
print("静态方法")
A.static_func()
"""静态方法"""
# 静态方法是不依赖于对象与类的,其实静态方法就是函数,保证代码的规范性,合理的划分,后续维护性高,但是调用依然用类名调用
# 实例import timeclass
TimeTest(object):
area = "中国"
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
def change_time(self):
print(f"你想调整的时间:{self.hour}时{self.minute}分{self.second}秒")
@staticmethod
def showTime():
return time.strftime("%H:%M:%S",time.localtime())
t = TimeTest(2, 10, 10)
t.change_time()
print(TimeTest.showTime())
# showTime函数,与类和对象没有任何关系,但是都是与时间有关,所以为了规范合理,放在一起,调用时用类名调用
属性
示例:
BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
class Bmi:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
def bmi(self):
return self.weight/self.height**2
obj = Bmi("赵嘎",1.83, 65)
# 结果虽然实现了,但是逻辑上感觉不合理,bmi应该是类似于name,age,height,等名词,但是把它当做方法使用了
property
class Bmi:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
return self.weight/self.height**2
obj = Bmi("赵嘎", 1.83, 65)
print(obj.bmi)
property 将执行一个函数需要函数名()变换成直接函数名,将动态方法 伪装 成了一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理
组合
class Foo:
@property
def bmi(self):
print("get的时候运行我")
@bmi.setter
def bmi(self, value):
print(value)
print("set的时候运行我")
@bmi.deleter
def bmi(self):
print("delete的时候运行我")
obj = Foo()
obj.bmiobj.bmi = 666
del obj.bmi
"""get的时候运行我666set的时候运行我delete的时候运行我"""
# 应用场景:
# 1.面试会考一些基本的调用,流程
# 2.工作中如果遇到了一些类似于属性的方法名,可以让其伪装成属性
设置属性的两种方式
1.利用装饰器设置属性
class Foo:
@property
def bmi(self):
print('get的时候运行我啊')
@bmi.setter
def bmi(self,value):
print(value)
print('set的时候运行我啊')
# return 111 # 无法得到返回值
@bmi.deleter
def bmi(self):
print('delete的时候运行我啊')
# return 111 # 无法得到返回值
2.利用实例化对象的方式设置属性
class Foo:
def get_AAA(self):
print('get的时候运行我啊')
def set_AAA(self,value):
print('set的时候运行我啊')
def delete_AAA(self):
print('delete的时候运行我啊')
AAA = property(get_AAA,set_AAA,delete_AAA)
#内置property三个参数与get,set,delete一一对应
f1=Foo()
f1.AAAf1.AAA='aaa'del
f1.AAA
isinstance和issubclass
isinstance
判断的对象与类的关系
class A:
passclass B(A):
passobj = B()
print(isinstance(obj,B))
print(isinstance(obj,A))
"""TrueTrue"""
# isinstance(a,b)
# 判断的是 a 是否是 b类 或者 b类派生类实例化的对象
issubclass
判断的是类与类的关系
class A:
pass
class B(A):
pass
class C(B):
pass
print(issubclass(B,A))
print(issubclass(C,A))
"""
True
True
"""
# issubclass(a,b)
# 判断的是 a类 是否是 b类 或者 b类派生类的 派生类
# 判断的是 a类 是否是 b类的子孙类

浙公网安备 33010602011771号