0%

python技巧(2)

[TOC]

如何在创建大量实列时节省内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#desp:如何在创建大量实例时节省内存
#author:GuiYoung
#data:9/9/2021

class Date:
__slots__ = ['year','month','day']
def __init__(self,year=0,month=0,day=0):
self.year = year
self.month = month
self.day = day

if __name__ == '__main__':
date = Date(2021,9,9)
print(date.day)

这样做的好处:这样使用的Data类内存量相当于将数据保存在元组中,而创建一个Data字典则保存在字典中

副作用:没办法再对实例添加任何新的属性,只允许使用__slots__中列出的属性名;此外,定义了__slots__属性的类不支持某些特定功能,如多重继承

使用范围:仅在程序中呗当做数据结构而频繁使用的类中采用该技法

类中的下划线之辩

  • 无下划线:一般变量
  • 前单下划线:这样命名变量表示不希望变量在类外访问,实际上,子类和对象都可以访问
  • 前置双下划线:子类也不可访问的变量
  • 后置下划线:用于命名变量时与关键字区别

isinstance函数

用于判断一个对象是否是一种已知的类型

  • isinstance():考虑继承关系,会认为子类是一种父类类型
  • type():不考虑继承关系

语法:

1
isinstance(object, classinfo)

创建可管理的属性

在对实例的设置上,增加一些额外的处理过程(如类型检查或验证)

一种方式:将其定义为property,把类中定义的函数当做一种属性来使用

示例:类型检查或验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#desp:创建可管理的属性
#author:GuiYoung
#data:9/9/2021

class Person:
def __init__(self,first_name,last_name="xixi"):
self.first_name = first_name
self.last_name = last_name

# Getter function
@property
def first_name(self):
return self._first_name

# Repeated property code, but for a different name (bad!)
@property
def last_name(self):
return self._last_name

# Setter function
@first_name.setter
def first_name(self, value):
if not isinstance(value,str):
raise TypeError("Expected a string")
self._first_name = value

@last_name.setter
def last_name(self, value):
if not isinstance(value,str):
raise TypeError("Expected a string")
self._last_name = value

# Deleter function (optional)
@first_name.deleter
def first_name(self):
raise AttributeError("Can't delete attribute")

if __name__ == '__main__':
person_1 = Person("Lily")
print(person_1.first_name) # Calls the getter
try:
person_1.last_name = 1
except Exception as error:
print(error)

try:
del person_1.first_name
except Exception as error:
print(error)

不要重复property语句,这会导致代码膨胀,丑陋。

创建一种新形式的类属性或实例属性

作为上一节不建议重复property语句的解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#desp:创建可管理的属性
#author:GuiYoung
#data:9/9/2021

#设置一个描述符类来帮助实现类型检查的功能
class Integer:
def __init__(self,name):
self.name = name

def __get__(self, instance, cls):
if instance is None:
return self
else:
return instance.__dict__[self.name]

def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('Expected an int')
instance.__dict__[self.name] = value

def __delete__(self, instance):
del instance.__dict__[self.name]

class Point:
#注意,描述符只能在类的层次上定义
x = Integer('x')
y = Integer('y')
def __init__(self,x,y):
self.x = x
self.y = y

if __name__ == "__main__":
p = Point(2, 3)
try:
p.x = 2.3
except TypeError as error:
print(error)

总结:若只是像访问某个特定的类中的一种属性,那么property会更简单;描述符适用于大量重用代码的情况,适合将其作为库使用。

调用父类中的方法

super()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#desp:创建可管理的属性
#author:GuiYoung
#data:9/9/2021

class A:
def __init__(self):
self.x = 0

def spam(self):
print("A.spam")

class B(A):
def __init__(self):
super().__init__()
self.y = 0

def spam(self):
print("B.spam")
super().spam()