1、输入的几种方式和区别
# 第一种就是最熟悉的input函数,返回的是字符串(保留空格,没有换行符\n)
a = input()
# 读取一行数据,返回的是字符串(保留空格,保留行符\n)
import sys
b = sys.stdin.readline()
c = sys.stdin.readline().strip() # strip的作用是去除字符串中结尾的各种转义符号
d = sys.stdin.readlines() # readlines会一次性将读取到的内容封装到一个列表中
# 多行输入
import sys
for line in sys.stdin:
e = line.split()
# 多行输入
import sys
OUT = []
try:
while True:
line = sys.stdin.readline().strip()
if line == '':
break
lines = line.split()
OUT.append(lines)
except:
pass
2、几个和数字有关的题目
1)判断一个数字是否为质数
n = int(input())
for i in range(2, int(n ** 0.5)):
if n % i == 0:
print("yes")
2)判断一个数字是否为水仙花数
n = input()
MAX = int(input())
for i in range(1, MAX + 1):
SUM = 0
for j in n:
SUM += int(j) ** i
if SUM == int(n):
print(str(i) + " " + "yes")
break
3)求N个数字的最大公约数和最小公倍数
def gcd(a, b):
"""求最大公约数函数"""
if a < b:
a, b = b, a
while b != 0:
temp = a % b
a = b
b = temp
return a
def setNumber():
n = int(input('您想输入数的个数:'))
global list1
list1 = []
count = 0
while (count < n):
c = int(input('请输入:'))
while (c <= 0):
print("您输入的数有误,请重新输入:")
c = int(input('请输入:'))
list1.append(c)
count += 1
print(list1)
def compare():
list2 = list(set(list1))
list3 = list2[::] # 列表复制
# 求N个数最大公约数
while len(list2) != 1:
a1 = list2.pop()
b1 = list2.pop()
c = gcd(a1, b1)
list2.append(c)
# 求最小公倍数
while len(list3) != 1:
a2 = list3.pop()
b2 = list3.pop()
c2 = gcd(a2, b2)
d = ((a2 * b2) // c2)
list3.append(d)
print("你输入所有数的最大公约数为:", end="")
print(list2[0])
print("你输入所有数的最小公倍数为:", end="")
print(list3[0])
setNumber()
compare()
3、变量和对象的关系
对象包含:id、value、type
内存中开辟的一个空间来保存对象
也专门开辟一个空间保存变量和对象id的对应关系
当将变量的类型进行转换后,会新创建一个对象
print(123) # 123
print(id(123)) # 140201064702528
print(type(123)) # <class 'int'>
a = 123
print(a) # 123
print(id(a)) # 140201064702528
print(type(a)) # <class 'int'>
b = str(123)
print(id(b)) # 140201059708976
print(type(b)) # <class 'str'>
c = str(a)
print(id(c)) # 140201059709040
print(type(c)) # <class 'str'>
4、变量赋值和修改
1)变量赋值:本质上是创建一个变量,和已有的对象ID建立关系
a = 123 # 在内存中创建一个对象,对象的值为123,然后创建一个变量,变量和对象的ID对应起来,相当于变量指向对象
b = a # 在内存中创建一个变量,将a对应的对象ID和b对应起来,相当于a和b都指向同一个对象
# 这样123和a和b的id都是一样的
print(id(123))
print(id(a))
print(id(b))
2)对变量的修改:如果两个变量指向的是同一个对象,那么对其中一个进行修改,则另一变量也会变,因为本质是对对象的值进行了修改
a = [1, 2, 3]
b = a
print(a) # [1, 2, 3]
print(b) # [1, 2, 3]
a[0] = 999
print(a) # [999, 2, 3]
print(b) # [999, 2, 3]
5、浅复制和深复制
1)赋值是将一个对象的地址赋值给一个变量,让变量指向该地址,没有创建新的对象
2)copy浅拷贝,没有拷贝子对象,所以原始数据改变,子对象会改变
3)深拷贝,包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
import copy
a = [1,2,['LIU','CHENG'],3,4]
print(id(a))
# 直接赋值
b1 = a
print(id(b1))
# 浅拷贝
b2 = copy.copy(a)
print(id(b2))
# 深拷贝
b3 = copy.deepcopy(a)
print(id(b3))
a[0] = 999
a[2][0]=888
print(a) # [999, 2, [888, 'CHENG'], 3, 4]
print(b1) # [999, 2, [888, 'CHENG'], 3, 4]
print(b2) # [1, 2, [888, 'CHENG'], 3, 4]
print(b3) # [1, 2, ['LIU', 'CHENG'], 3, 4]
print(id(a)) # 140028931356224
print(id(b1)) # 140028931356224
print(id(b2)) # 140028931545344
print(id(b3)) # 140028931545280
6、传递对象给函数
如果形参执行的是一个对象,当我们通过形参修改对象的值时,会影响到所有指向该对象的变量
def func(a):
print(a,id(a))
a[0] = 999
print(a,id(a))
b = [1,2,3]
func(b)
print(b,id(b))
"""
最后结果如下:
[1, 2, 3] 140196792284672
[999, 2, 3] 140196792284672
[999, 2, 3] 140196792284672
"""
7、函数的不定长参数
1)一个星号的形参
在定义函数的时候,可以在形参前面加上一个星号*
这样这个参数就会获取到所有实参,并保存到一个元组中
星号参数只能有一个
星号参数不是必须写在最后,但后面的参数必须以关键字参数形式传递
def func(a,*b):
print(a)
print(b,type(b))
func(999,888,777,666)
"""
最后结果如下:
999
(888, 777, 666) <class 'tuple'>
"""
2)两个星号的形参
在形参前面加上两个星号**
这个参数可以接收所有其他的关键字参数,并保存到一个字典中
这种参数只能有一个且必须写在所有参数的最后
def func(*a,**b):
print(a)
print(b)
func(111,666,999,A = 222, B = 333)
"""
最后结果如下:
(111, 666, 999)
{'A': 222, 'B': 333}
"""
8、命名空间
命名空间用于保存变量,实际上就是一个用于保存变量的字典
使用locals()
函数可以访问所在作用域的命名空间
使用globals()
函数可以访问全局变量的命名空间
可以直接向locals返回的字典中添加键值对来添加变量
a = 10
b = 'str'
c = locals()
print(c)
c['d'] = 'd'
print(c)
9、递归
递归函数的有两个要件:基线条件、递归条件
以阶乘为题为例
首先分析阶乘的基线条件,即当n==1时结束递归
然后分析阶乘的递归条件,即当n!=1时重复n*n-1的操作
def factorial(n):
# 基线条件
if n==1:
return 1
# 递归条件
return n*factorial(n-1)
print(factorial(10))
1)练习:创建一个函数power来为任意数字做任意幂运算,即计算n**i
基线条件:当 i == 1 的时候结束递归
递归条件:当 i != 1 的时候,重复n*n的操作
def power(n,i):
# 基线条件
if i==1:
return n
# 递归条件
return n*power(n,i-1)
2)练习:创建一个函数,判断一个字符串是否为回文字符串
基线条件:当字符串长度小于2,或者字符串第1个和最后1个字符不相等时,结束递归
def hui_wen(s):
# 基线条件
if len(s) < 2:
return True
elif s[0] != s[-1]:
return False
# 递归条件
return hui_wen(s[1:-1])
10、匿名函数
很多时候lambda匿名函数和filter()和map()函数一起使用
filter()函数可以从对可迭代对象中过滤出满足条件的元素,保存到一个新的对象中
map()函数可以对可迭代对象中所有元素做指定的操作,保存到一个新的对象中
l = [1,2,3,4,5,6,7,8,9,10]
print(list(filter(lambda i : i<5, l)))
print(list(map(lambda i : i+1, l)))
print(l)
11、sort方法的小技巧
sort方法默认对列表中的元素进行比较并进行升序排序
在sort()方法中可以接收一个关键字参数key = 函数
当使用了该关键字参数时,每次以列表中的一个元素作为参数来调用函数,并使用函数返回值比较元素大小
sorted()函数可以对任意序列进行排序操作并返回一个新的对象,使用方法和sort类似
l1 = ['bbb','aa','cccccc','dd']
l2 = [1,'3',4,'2',6,5]
print(sorted(l1,key = len))
print(l1) # l1没有变化
l1.sort(key = len) # 按照字符串长度排序
print(l1)
l2.sort(key = int) # 将元素转为int之后再排序
print(l2)
l2.sort(key = str) # 将元素转为str之后再排序
print(l2)
12、闭包
将函数作为返回值的函数,称为闭包
通过闭包可以创建一些只有当前函数能访问的变量
形成闭包的要件:
1)函数嵌套
2)将内部函数作为返回值
3)内部函数要使用到外部函数中定义的变量
def func():
a = 10
def inner():
print('inner',a)
return inner
r = func()
r()
def make_averager():
nums = []
def averager(n):
nums.append(n)
return sum(nums)/len(nums)
return averager
averager = make_averager()
print(averager)
print(averager(10))
print(averager(30))
13、装饰器
在不修改源码的基础上对函数进行扩展,利用了将函数作为参数和返回值的知识
装饰器中参数的传递可以使用不定长参数
# 假设已有两个函数
def mul(a,b):
return a*b
def pp():
print("print pp")
# 如果想对函数扩展功能,可以直接找到上面的函数进行修改,但不好
# 一般使用装饰器来对函数进行扩展,即定义一个新的函数帮助我们创建一个新函数
def begin(function_name):
'''
功能:用于创建一个新的扩展函数
参数:要扩展的函数对象
'''
def new_func(*args, ** kwargs): # 使用不定长参数方便参数的传入
print("new_begin") # 要扩展的内容
result = function_name(*args, **kwargs) # 调用被扩展的函数
print("new_end") # 要扩展的内容
return result # 返回函数的结果
return new_func # 返回新函数对象
# 装饰器的使用
f = begin(mul) # f保存的是新函数的对象,可以看成f就是new_func,只是function_name变成了mul
r = f(1,22) # 执行的时候就是按照new_func的代码块执行
f2 = begin(pp)
r2 = f2()
# 一般不使用上面的方法,而是采用@符号来使用指定的装饰器装饰下面的函数
# 可以同时为一个函数指定多个装饰器
def begin2(function_name):
def new_function(*args,**kwargs):
print("begin2")
result = function_name()
print("begin2_end")
return result
return new_function
@begin2
@begin
def say_hello():
print("hello~~")
say_hello()
- property装饰器,用来将一个get方法转换为对象的属性
- 添加property装饰器后,就可以像调用属性一样使用get方法
- 利用这种方式的话,方法名必须要和目标属性名相同
class Person():
def __init__(self,name):
self._name = name
@property
def name(self):
print("get方法执行了")
return self._name
p = Person("LC")
print(p.name)
- set方法的装饰器:@属性名.setter,用来将一个set方法转换为对象的属性
- 添加set装饰器后,就可以像调用属性一样使用set方法
- 利用这种方式的话,方法名必须要和目标属性名相同
class Person():
def __init__(self,name):
self._name = name
@property
def name(self):
print("get方法执行了")
return self._name
@name.setter
def name(self,name):
print("set方法执行了")
self._name = name
p = Person("LC")
p.name = "CYP"
print(p.name)
14、类和对象的创建过程
Python中一切皆对象,包括类也是一种对象
以下面这段代码为例,解释类和对象的创建过程
class MyClass():
name = "LC"
def __init__(self,name):
self.name = name
def say_hello(self):
print("hello ",self.name)
p1 = MyClass("CYP")
p1.say_hello()
'''
最后结果是:
hello CYP
'''
1)首先定义类内部方法的时候,第一个参数一定是self,self代表创建的一个实例化对象,所以self和p1的ID是相同的
2)创建类和实例化的过程
① 创建类对象:执行完1到6行代码后,内存中会开辟一个空间来保存类对象,即下图中的东西
② 创建变量p1:执行第7行前部分,在命名空间中创建好一个变量
③ 创建实例对象:执行第7行后部分
- 如下图,内存中开辟一个空间来保存实例化的对象
- 调用__init__函数,将实参传入,修改了该对象下name的值。内存中结果如下图
- 变量和实例对象对应起来,即将对象的ID赋值给p1
15、隐藏属性的的创建和修改
用双下划线开头的属性是隐藏属性,无法通过对象来访问,只能通过对象的方法来访问
Python中隐藏属性实际上是假隐藏,只是系统自动将属性名改为_类名__属性名
用单下划线开头的属性是私有属性,可以通过对象访问,但表示的是不建议修改的属性
class Person():
def __init__(self,name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
p = Person("LC")
p.set_name("CYP")
print(p.get_name())
# 直接print(p.__name)是会报错的
print(p._Person__name)
16、Python的垃圾回收机制
程序中没有被引用的对象就是垃圾,垃圾回收就是将垃圾对象从内存中删除
Python有自动垃圾回收机制,不用手动处理
每个类默认都会有一个__del__方法,会在对象被回收前调用
17、模块的引用
每个py文件就是一个模块
每个模块内部都有一个__name__属性,通过这个属性可以获取模块的名字
__name__属性为__main__的模块是主模块,就是运行的那个py文件,一个程序只有一个主模块
假设创建了两个py文件如下
# test1.py
print("test1")
print(__name__)
# test2.py
import test1
print("test2")
print(__name__)
运行test1.py的结果是:
test1
__main__
运行test2.py的结果是:
test1
test1
test2
__main__