Python中的对象包含三要素:id、type、value。
id用来唯一标识一个对象,type标识对象的类型,value是对象的值。is判断的是a对象是否就是b对象,是通过id来判断的。是比较两个引用是否指向了同一个对象(引用比较)。
==判断的是a对象的值是否和b对象的值相等,是通过value来判断。是比较两个对象的值是否相等(值的比较)。
Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。
Python 对小整数的定义是 [-5, 257) 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,所有位于这个范围内的整数使用的都是同一个对象.
对象中==比较时并不是__str__返回的内容,而是两个类对象的地址的比较
python中有这样一个机制——intern(字符串驻留)机制,创建多个相同的字符串,会指向同一个内存空间比较他们的==和is都是True。靠引用计数去维护何时释放。
可变类型数据增加删除时地址不会变,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址
浅拷贝
浅拷贝是对于一个对象的顶层拷贝;通俗的理解是:拷贝了引用,并没有拷贝内容;浅拷贝只拷贝父对象,不会拷贝对象的内部的子对象。要引入模块import copy 新的=copy.copy(旧的)浅拷贝内容相同,地址不同,内容的地址是相同的(列表里存的是数据的地址)
使用了浅拷贝
• 使用切片[:]操作
• 使用工厂函数(如list/dir/set)内置模块函数
• 使用copy模块中的copy()函数
产生内容的地址(引用)是新的,里面引用的元素还是原来的元素(内容的地址是相同的)
特殊情况:不可变类型的切片,切片的地址与原地址是相同的。可变类型的切片,切片的地址与原地址是不相同的,但是里面的内容地址是相同的。
Python中对象的赋值都是进行对象引用(内存地址)传递使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
深拷贝函数copy.deepcopy()深拷贝是对于一个对象所有层次的拷贝(递归 #深度)
可变类型的数据都拷贝一份。对原数据改变不会影响copy出来的数据!!
对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有拷贝这一说
如果元祖变量只包含原子类型对象,则不能深拷贝
如果元组能不能执行深copy取决去元组中内容的类型是否可变,如果内容有可变类型的可以进行深copy
字典(可变类型)的copy方法可以拷贝一个字典 新=字典.copy()
有些内置函数可以生成拷贝(list)产生的两个地址是不相同的
二进制的负数进行加法运算要用补码计算。
原码------>补码符号为不变,其他位数取反加1补码------>原码符号为不变,其他位数取反加1
0b开头是二进制Binary;0o开头是八进制;0x开头是十六进制。
十进制转换二进制 bin(十进制)
十进制转换八进制 oct(十进制)
十进制转换十六进制 hex(十进制)
其他转十进制 int("1001",2)
& 按位与:只有对应的两个二进位均为1时,结果位才为1,否则为0
| 按位或:有1就1 只要对应的二个二进位有一个为1时,结果位就为1,否则为0
^ 按位异或:不同为1 当对应的二进位相异(不相同)时,结果为1,否则为0
~ 取反:按位取反 将反码变为原码
<< 按位左移 补码左右移动
>> 按位右移
位数左移原数乘以基数的左移位置之幂。位数右移(补位是要补符号位)原数除以基数的右移位置之幂取商
用途: 直接操作二进制,省内存,效率高
Python使用叫做命名空间的东西来记录变量的轨迹。命名空间是一个字典(dictionary) ,它的键就是变量名,它的值就是那些变量的值。
在一个 Python 程序中的任何一个地方,都存在几个可用的命名空间。1、每个函数都有着自已的命名空间,叫做局部命名空间,它记录了函数的变量,包括函数的参数和局部定义的变量。
2、每个模块拥有它自已的命名空间,叫做全局命名空间,它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
3、还有就是内置命名空间,任何模块均可访问它,它存放着内置的函数和异常。
import test test代表的是另外一个命名空间,如果想要调用里面的函数要用模块名.函数名
form test import * 通过把test模块的所有函数导入当前的命名空间后,就可以直接使用用函数名调用了
locals()记录了当前所在命名空间中的局部的变量,函数的参数也属于命名空间内的变量.
globals()记录了命名空间的全局的变量
builtins内建模块的命名空间模块中,可以使用 dir(__builtins__) 来查看。
Python 使用 LEGB 的顺序来查找一个符号对应的对象
locals -> enclosing function -> globals -> builtins
私有化
xx: 公有变量_x: 模块中单前置下划线,私有化属性或方法,from somemodule import *禁止导入
模块中的私有属性在from somemodule import *导入的时候直接直接就隐藏_属性和_方法
但是from test import num1,_num2,__num3等都正常能调用。类对象和子类可以访问
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)模块中的全局变量是私有的,在函数中可以使用,而类中不可以使用
__xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字
xx_:单后置下划线,用于避免与Python关键词的冲突
名字重整是指类中的私有属性或者方法,进行名字的重新整理。所以访问不到私有属性和方法。查看重整属性和方法名用dir
1、父类中属性名为__名字的,子类不继承,子类不能访问如果在子类中向__名字赋值,那么会在子类中定义的一个与父类相同名字的属性
2、_名的变量、函数、类在使用from xxx import *时都不会被导入;如果用import xxx可以调用
3、__加上的方法和属性,名字重整了所以访问不了了,但实际是可以访问的,只是开发中不建议这么用。
属性
私有属性添加getter和setter方法、使用property取代getter和setter方法
money = property(get_money, set_money)
注意:get方法在前面,set在后面,money这个名字任意
对象名.money=等于set设置值 对象名.money等于get输出值
@property成为属性函数,可以对属性赋值时做必要的检查,并保证代码的清晰短小,主要有2个作用将方法转换为只读重新实现一个属性的设置和读取方法,可做边界判定
Property的作用:相当于把方法进行了封装,开发者在对属性设置数据的时候更方便.
五、属性:
其实就是为私有属性 ——》set和get方法变形1:
步骤1:
def set_age(self,age):
….
def get_age(self):
…
步骤2:
age=property(get_age,set_age)
步骤3:
使用:
person= Person()
person.age = 20 ——>判断有没有“=” 就调用set_age
myage=person.age ——> 就调用的是get_age
变形2:
步骤1:通过@property声明get方法
class Person:
@property
def age(self):
return ….
步骤二:
根据步骤1的函数名定义
@age.setter
步骤三:定义函数,函数名与步骤一的函数名一致,就是多了一个参数
def age(self,age):
self.__age=age
步骤四:
使用:
person= Person()
person.age = 20 ——>判断有没有“=” 就调用set_age
myage=person.age ——> 就调用的是get_age