Python数据类型底层原理
Python是一种动态类型的编程语言,它允许我们在不指定类型的情况下为变量赋值。例如,我们可以连续地给一个变量赋值为整数和字符串,而不会报错。这种灵活性源于Python的动态数据类型设计,其中每个变量都包含了值信息和类型额外信息。
“夏のke”》 Ukoou·ㄷㅁΜ
在Python的内部实现中,每个对象都是基于C语言编写的结构体,例如整型对象。一个整型在Python中实际上是一个指向C语言结构体的指针。这个结构体定义如下:
struct _longobject {
long ob_refcnt;
PyTypeObject *ob_type;
size_t ob_size;
long ob_digit[1];
};
在这个结构体中,ob_refcnt是引用计数,用于协助Python的垃圾回收(GC)。ob_type是类型对象,它编码了变量的类型信息。ob_size表示数据成员的大小,而ob_digit则包含了实际的整数值。
由于Python的动态类型系统,存储一个整型需要额外的开销。除了实际的数值之外,还需要存储类型和引用计数等信息。这种设计虽然带来了灵活性,但也增加了内存的使用。
列表(list)是Python中的标准可变多元素容器。它的底层实现是一个包含多个Python对象的指针数组。列表的C语言结构体定义如下:
typedef struct {
PyObject_VAR_HEAD
PyObject *ob_item; // 指针数组
Py_ssize_t allocated; // 申请内存的槽个数
} PyListObject;
列表中的每个元素都是一个指向Python对象的指针。当添加或删除元素时,可能需要重新分配内存。不过,由于Python的实现细节,并不是每次操作都需要改变数组的大小。
NumPy库提供了固定类型的数组,这与Python原生的列表有所不同。NumPy数组的底层结构体中包含了头信息、数据、维度和步幅等信息,然后指向数组的第一个元素。通过步幅和维度可以快速定位到数组中的任何元素。
慕课Python全能工程师2024 字典(dict)在Python中的底层实现是基于哈希表的。只有可哈希的对象才能作为字典的键。Python使用伪随机探测的哈希表作为字典的底层结构。解决哈希碰撞的方法包括开放寻址、再hash法、链地址法、公共溢出区以及装填因子等。
集合(set)的实现与哈希表类似,它基于hash对元素进行散列,只包含对键的引用,没有对值的引用。
通过深入了解Python数据类型的底层原理,我们可以更好地理解Python的内存管理和性能特性。这对于编写高效、可维护的Python代码至关重要。
Python封装底层实现原理
慕课Python全能工程师2024 Python中的封装特性并非通过传统的访问控制修饰符(如Java中的public、private等)来实现,而是通过名称修改(name mangling)的方式。这意味着,当你试图在一个类中定义私有属性或方法时,Python会自动将这些属性或方法的名称进行修改,以防止它们被外部直接访问。
在提供的示例代码中,我们定义了一个名为CLanguage的类,其中包含了私有属性__name和__add,以及对应的setter和getter方法。此外,还有一个私有方法__display,用于打印这些私有属性的值。
class CLanguage :
def setname(self, name):
if len(name) < 3:
raise ValueError('名称长度必须大于3!')
self.__name = name
def getname(self):
return self.__name
# 为 name 配置 setter 和 getter 方法
name = property(getname, setname)
def setadd(self, add):
if add.startswith("http://"):
self.__add = add
else:
raise ValueError('地址必须以 http:// 开头')
def getadd(self):
return self.__add
# 为 add 配置 setter 和 getter 方法
add = property(getadd, setadd)
# 定义个私有方法
def __display(self):
print(self.__name,self.__add)
当我们尝试直接调用私有方法__display时,Python会抛出一个AttributeError,因为该方法的名称已经被修改,不再是__display。然而,如果我们知道了名称修改的规则,即在属性或方法名前加上_类名__,我们就可以访问到这些私有成员。例如,_CLanguage__display就是__display方法修改后的名称。
clang = CLanguage()
# 尝试调用私有的 display() 方法
clang.__display() # 这将引发错误
# 调用name的setname()方法
clang.name = "新宝库"
# 调用add的setadd()方法
clang.add = "https://www.xinbaoku.com"
# 直接调用隐藏的display()方法
clang._CLanguage__display() # 正确调用
此外,我们还可以访问和修改私有属性__name和__add,尽管这不是推荐的做法,因为它破坏了封装性。
clang = CLanguage()
clang.name = "新宝库"
clang.add = "https://www.xinbaoku.com"
# 直接调用 name 和 add 私有属性
print(clang._CLanguage__name,clang._CLanguage__add)
# 甚至于,我们还可以通过这种方式修改 clang 对象的私有属性
clang._CLanguage__name = "Python教程"
clang._CLanguage__add = "https://www.xinbaoku.com/python"
print(clang._CLanguage__name,clang._CLanguage__add)