Python中值得注意的点

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__

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值