Python进阶学习知识点

参考:https://blog.csdn.net/m18903718781/article/details/78428878

参考:https://www.cnblogs.com/zzmx0/p/12735353.html

目录

可变类型和不可变类型

关键字is 和 == 的区别

深拷贝和浅拷贝

变量下划线

私有化和Property

列表生成式

生成器

迭代器

闭包

装饰器

动态语言添加属性和方法

元类

内建属性

线程


可变类型和不可变类型

(1)可变类型:

        对象的内容可变

        value值改变,id值不变

        可变(mutable):字典型(dictionary)、列表型(list)

(2)不可变类型:

        对象的内容不可变

        value值改变,id值也随之改变

        不可变(immutable):int、字符串(string)、float、(数值型number)、元组(tuple)

(3)通过id(obj)方法可获取到对应的地址

a=1
print(id(a))
a=a+1
print(id(a))
b=[1,2,3]
print(id(b))
b.append(4)
print(id(b))

>>>
1608778934576
1608778934608
1608784286720
1608784286720

关键字is 和 == 的区别

a="a"
b="a"
print(a==b)
print(a is b)

c=1
d=1
print(c==d)
print(c is d)

l1=[1,2]
l2=[1,2]
print(l1==l2)
print(l1 is l2)

>>>
True
True
True
True
True
False

注意:is 判断是否是一个ID, == 判断内容是否一致。

深拷贝和浅拷贝

import copy
a = [1,2,3,4,5]
b = a   #浅拷贝,a,b同时指向一个id,当其中一个修改时,另外一个也会被修改。
c = copy.deepcopy(a) #深拷贝,c单独开辟一个id,用来存储和a一样的内容。
d =a[:] #这样也是深拷贝。
e = copy.copy(a) #当拷贝内容是可变类型时,那么就会进行浅拷贝,如果是不可变类型时,那么就会进行深拷贝。
import copy
a=[1,2,3,[4,5]]
b=a
a[0]=0
a[3].append(0)
print("=是浅拷贝")
print(a)
print(b)

c=[1,2,3,[4,5]]
d=copy.deepcopy(c)
c[0]=0
c[3].append(0)
print("copy.deepcopy()是深拷贝")
print(c)
print(d)

>>>
=是浅拷贝
[0, 2, 3, [4, 5, 0]]
[0, 2, 3, [4, 5, 0]]
copy.deepcopy()是深拷贝
[0, 2, 3, [4, 5, 0]]
[1, 2, 3, [4, 5]]
import copy
a=[1,2,3,[4,5]]
b=a[:]
a[0]=0
a[3].append(0)
print(":复制针对不可变对象是深拷贝,可变对象是浅拷贝")
print(a)
print(b)

c=[1,2,3,[4,5]]
d=copy.copy(c)
c[0]=0
c[3].append(0)
print("copy.copy()针对不可变对象是深拷贝,可变对象是浅拷贝")
print(c)
print(d)

>>>
:复制针对不可变对象是深拷贝,可变对象是浅拷贝
[0, 2, 3, [4, 5, 0]]
[1, 2, 3, [4, 5, 0]]
copy.copy()针对不可变对象是深拷贝,可变对象是浅拷贝
[0, 2, 3, [4, 5, 0]]
[1, 2, 3, [4, 5, 0]]

注意:深拷贝会另外开辟内存来放复制的内容,浅拷贝是指向同一个内存ID

变量下划线

前导单下划线       _xxx         不能用’from module import *’导入

前后导双下划线   __xxx__   系统定义名字

前导双下划线       __xxx       类中的私有变量名

核心风格:避免用下划线作为变量名的开始。

“单下划线” 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;

“双下划线” 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。

以单下划线开头的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用from xxx import *而导入;

以双下划线开头的代表类的私有成员;

以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。

私有化和Property

私有化

  • xx: 公有变量
  • _x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问
  • __xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
  • __xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字
  • xx_:单后置下划线,用于避免与Python关键词的冲突
  • 父类中属性名为__xxx的,子类不继承,子类不能访问
  • 如果在子类中向__xxx赋值,那么会在子类中定义的一个与父类相同名字的属性
  • _xxx的变量、函数、类在使用 from xx import * 时都不会被导入

Property

class Money(object):
    def __init__(self):
        self.__money=0
    def getMoney(self):
        return self.__money
    def setMoney(self,v):
        self.__money=v
    money = property(getMoney,setMoney)
m = Money()
print(m.money)
m.money=100
print(m.money)

>>>
0
100
# property取代getter和setter方法
class Money(object):
    def __init__(self):
        self.__money=0
    @property
    def money(self):
        return self.__money
    @money.setter
    def money(self,value):
        self.__money=value
m = Money()
print(m.money)
m.money=100
print(m.money)

>>>
0
100

列表生成式

a = [i for i in range(1,10,5)] #第一个参数表示开始位,第二个参数表示结束位(不含),第三个参数表示步长,就是每5个数返回一次。
print(a)
a = [i for i in range(1,10)] #列表生成式表示返回i的值,并且返回9次,每次返回的是i的值。
print(a)
a = [2 for i in range(1,10)] #这里表示返回2,并且返回9次,但是每次的值都是2。
print(a)
a = [i for i in range(10) if i%2==0] #表示在生成式内部加入if判断,当i除以2的余数等于0的时候将数值返回。
print(a)
a = [(i,j) for i in range(2) for j in range(3)] #表示将i和j的值以元组为元素的形式返回,当i循环一次的时候j循环5次,以此类推。
print(a)
a = [ i if i%2==0 else 0 for i in range(10)] # if-else
print(a)

>>>
[1, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[2, 2, 2, 2, 2, 2, 2, 2, 2]
[0, 2, 4, 6, 8]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
[0, 0, 2, 0, 4, 0, 6, 0, 8, 0]

生成器

a = (i for i in range(1,10)) #将列表生成试外部的中括号改为小括号,就能将生成式转化为生成器。
print(next(a),a.__next__()) #生成器的取值方式只能使用next的方法。
def num():
	a,b = 0,1
	for i in range(5):
		yield b  #生成关键字yield,有yield的关键字的代码块就是yield的生成器。当运行到yield时代码就会停止,并返回运行结果,当在次运行时依旧是到yield停止,并返回结果。 切记:生成器只能使用next方法。
		a,b = b,a+b
a = num()  #将生成器赋值给变量a。
for n in a:  #生成器可以使用for循环使用,并且不会出错。
	print(n)

注意:生成器占用内存小,在使用的时候取值,降低CPU和内存空间,提高效率。并且一般都使用for循环进行取值。

迭代器

for i in '',[],(),{},{:}
#可以for循环的对象是可迭代对象。
a = (x for i in range(100))
#列表生成式,把中括号改为小括号就可以变为一个列表生成器,是可迭代对象。
from collections import Iterable #如果想验证是否是可迭代对象,可以使用isinstance()判断是否是可迭代对象。
isinstance('abc',Ierable) #判断语法
a = [1,2,3,4,5]
b = iter(a)  #使用iter()方法可以将可迭代对象转换为可迭代对象。


b = []
print('__iter__' in dir(b))

>>>
True

注意:生成器是可迭代对象,迭代器不一定是生成器。并且迭代器无法回取,只能向前取值。
注意:一个对象具有 iter 方法的才能称为可迭代对象,使用yield生成的迭代器函数,也有iter方法。凡是没有iter方法的对象不是可迭代对象,凡是没有__next__()方法的不是是生成器。这里的方法都是魔法方法,是内置方法,可以使用dir(obj)查看。

闭包

def num(v1): #定义函数
	def num_in(v2): #定义函数
		return v1 + v2 #返回两个参数的和。
	return num_in #返回内部函数的引用。(变量名)

a = num(100) #将参数为100的函数num接收,并赋值给a,只不过这个返回值是一个函数的引用。等于 a = num_in,注意这里接收的不光是函数本身,还有已经传递的参数。
b = a(100) #调用函数a,即num_in,并传递一个参数100,返回值给b。
c = a(200)
print(a)
print(b)
print(c)

>>>
<function num.<locals>.num_in at 0x000001A1B26AB0D0>
200
300

注意:当一个函数定义在另一个函数内,且使用到了外部函数的参数。整个代码块称为闭包。当外部参数确定时,内部函数参数可以反复调用。

装饰器

#!/usr/bin/env python
def trace_func(func):
    def tmp(*args, **kargs):
        print('Start %s(%s, %s)' % (func.__name__, args, kargs))
        return func(*args, **kargs)
    return tmp
@trace_func
def log_test_with_empty_parameter():
    print(1)
@trace_func
def log_test_with_many_parameter(a_int, b_string, c_list, d_dict):
    print(2)
@trace_func
def log_test_with_key_parameter(a = 'www', b = 1, c = [1,2]):
    pass
if __name__ == '__main__':
    log_test_with_empty_parameter()
    log_test_with_many_parameter(1, 'wwww', [1,2,'c'], {1: 'a', 2 : 'ww'})
    log_test_with_key_parameter(1, 'wwww', c = [3, 4])

>>>
Start log_test_with_empty_parameter((), {})
1
Start log_test_with_many_parameter((1, 'wwww', [1, 2, 'c'], {1: 'a', 2: 'ww'}), {})
2
Start log_test_with_key_parameter((1, 'wwww'), {'c': [3, 4]})

动态语言添加属性和方法

from types import MethodType
class Human:
    def __init__(self,name):
        self.name=name
h = Human('lc')
print(h.name)
h.age=18 #动态语言的特性
print(h.age)


# 创建一个空类
class Person(object):
    __slots__ = ("name", "age", "speak", "height")
per = Person()
# 动态添加属性,这体现了动态语言的特点(灵活)
per.name = "tom"
print(per.name)
'''
#动态添加方法
def say(self):
    print("my name is "+self.name)
per.speak = say
per.speak()
'''
def say(self):
    print("my name is " + self.name)


per.speak = MethodType(say, per)
per.speak()
# 思考:如果我们想要限制实力的属性怎么办
# 比如:只允许给对象添加 name,age,height,weight属性
# 解决:定义类的时候,定义一个特殊的属性(__slots__)
# 可以限制动态添加的属性
per.height = 100
print(per.height)

元类

Test = type('Test',(object,),{'num':0} )
# 元类是只使用type创建的类
# 使用type会有3个参数
# 第一个是类名
# 第二个小括号内是父类名,需要使用元组
# 第三个字典中是类属性,使用type能够快速的动态创建一个类。
# 创建一个类,等价于上边
# class Test(object):
# 	num = 0
t = Test()
print(t.num)

# 创建带方法的元类
def eat(self):  #定义一个函数,self作为第一个参数。
	print ('%s'%self.name)
Person = type('Person',(object,), {'eat':eat,'name':None})
p = Person()
p.name = 'Tom'
p.eat()

内建属性

通过help(obj)方法可以查看到obj的使用手册

通过dir(obj)方法可以查看到内置方法

__init__ #构造初始化函数,__new__之后运行
__new__ #创建实例所需的属性
__class__ #实例所在的类,实例.__class__
__str__ #实例的字符串表示,可读性高
__repr__ #实例的字符串表示,准确性高
__del__ #删除实例引用
__dict__ #实例自定义属性,vars(实例.__dict__)
__doc__ #类文档,help(类或者实例)
__bases__ #当前类的所有父类
__getattribute__ #属性访问拦截器。

Test = type('Test',(object,),{'num':0} )
help(Test.__init__)
help(Test.__new__)
print(Test.__class__)
print(Test.__bases__)
>>>
Help on wrapper_descriptor:

__init__(self, /, *args, **kwargs)
    Initialize self.  See help(type(self)) for accurate signature.

Help on built-in function __new__:

__new__(*args, **kwargs) method of builtins.type instance
    Create and return a new object.  See help(type) for accurate signature.

<class 'type'>
(<class 'object'>,)

线程

import threading
from threading import current_thread
class Mythread(threading.Thread):
    def run(self):
        print(current_thread().getName(), "111111111111")
        print('222222222222')
        print(current_thread().getName(), "333333333333")
t1 = Mythread()
t1.start()  # 子进程
#t1.join()  # 线程同步
print(current_thread().getName(), '4444444444444')

>>>
Thread-1MainThread  1111111111114444444444444

222222222222
Thread-1 333333333333

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值