参考: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
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__()代表类的构造函数。
私有化
- 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)
>>>
.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.
(,)
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