python - Python getter、setter 和操作字段
问题描述
我正在构建一个简单的类,它有一些只属于一个实例的变量,例如一个带有纪元时间戳的“创建”字段,以及在创建实例时设置的一些其他变量。作为练习,想以最Pythonic 的方式来做这件事。此外,我想要一个将属性打印为 json 的函数,以便以后使用。到目前为止,我有这个:
import os
import uuid
import time
class Example:
def __init__(self, data=None):
self._data = data
self._id = self.id
self._environment = self.environment
self._created = self.created
@property
def data(self):
if self.environment == 'prd':
self._data
else:
return None
@data.setter
def data(self, value):
self._data = value
@property
def id(self):
return str(uuid.uuid4())
@id.setter
def id(self, value):
self._id = value
@property
def request(self):
return self._request
@request.setter
def request(self, value):
self._request = value
@property
def environment(self):
return os.getenv('environment', 'dev')
@environment.setter
def environment(self, value):
self._environment = value
@property
def created(self):
return str(int(time.time()))
@created.setter
def created(self, value):
self._created = value
def to_json(self):
return self.__dict__
输出:
from example import Example
e = Example()
print(e.to_json())
# {'_data': None, '_id': '5f946b10-0e89-4d65-9f76-b9f15a81197d', '_environment': 'dev', '_created': '1592835056'}
我有一些疑问:
- 操作属性的最佳位置是什么?例如,我在调用 self.created 时返回一个时间戳。我根据另一个属性操作数据属性。吸气剂是这种东西的正确位置吗?
- 我是否在init中正确地将私有变量分配给了自己?
- 我需要 json 中的所有变量以供以后处理,如何在没有下划线的情况下将它们输出到 json 中?
- 如何使用数据类完成同样的事情?
解决方案
关于您的问题 1. 是的,在普通 python 中,在读取或写入属性时执行代码的最佳位置是属性。或者,您可以使用所谓的描述符协议(高级)创建“类属性”对象。
对于您的问题 2。您的 init 不正确,因为您使用的某些变量在使用时未定义。此外created
,environment
和id
属性也没有正确编写,因为如果您使用 setter,将写入一个新的私有属性(例如_id
),但您没有在 getter 中使用它。使用属性的“好”方式是这样的:
class Example:
def __init__(self):
self._a = None
@property
def a(self):
if self._a is None:
return "my_default_val"
else:
return self._a
@a.setter
def a(self, value):
self._a = value
e = Example()
print(e.a)
e.a = 2
print(e.a)
产量
my_default_val
2
对于您的问题 3,最适合您的是学习如何使用列表推导、字典推导等,并使用它来动态过滤您的vars(o)
(或者o.__dict__
,相同的)
现在参考您的问题 4。根据我的个人经验,我建议不要使用数据类,这只是attrs
. 您可以使用attrs
,或者似乎更适合对象可变的用例,pyfields
. Indeedattrs
还没有在属性更改时调用验证器/处理程序,并且强加了相当严格的开发理念(即,您不能将 anattr.ib
与任何类一起使用,因为该类__init__
并且__setattr__
由attrs
.
这是您可以使用的方法pyfields
:
import os
import uuid
import time
from pyfields import field, get_field_values, make_init
class Example:
# the various fields
_data = field(default=None)
environment = field(default_factory=lambda o: os.getenv('environment', 'dev'))
id = field(default_factory=lambda o: str(uuid.uuid4()))
created = field(default_factory=lambda o: str(int(time.time())))
request = field()
# create a default constructor if you do not need a custom one
__init__ = make_init()
# 'data' is a dynamic view that depends on 'environment': still need a property
@property
def data(self):
if self.environment == 'prd':
return self._data
else:
return None
@data.setter
def data(self, value):
self._data = value
def to_json(self):
dct = get_field_values(self, public_only=True)
dct['data'] = self.data
return dct
e = Example(request='hello')
print(e.to_json())
产量
{'environment': 'dev', 'id': '8f3c2f8f-ce36-4e69-bfb9-b044db83be84', 'created': '1592897458', 'request': 'hello', 'data': None}
注意get_field_values
不返回data
属性的内容。请参阅此功能请求。
如果需要,您可以进一步简化此示例,使用autofields
它删除字段定义中的一些样板并在不存在时生成构造函数:
from pyfields import get_field_values, autofields
@autofields
class Example:
# the various fields
_data = None
environment: str = os.getenv('environment', 'dev')
id: str = str(uuid.uuid4())
created: int = str(int(time.time()))
request: str
(... all the same than previously)
最后,如果您需要它们,repr
您可以使用. 它会自动检测类上有没有,你可以使用它的参数来自动创建它们:eq
hash
dict
autoclass
fields
autofields
from autoclass import autoclass
@autoclass(autofields=True)
class Example:
# the various fields
_data = None
environment: str = os.getenv('environment', 'dev')
id: str = str(uuid.uuid4())
created: int = str(int(time.time()))
request: str
# data is a dynamic view that depends on the environment: need a property
@property
def data(self):
if self.environment == 'prd':
return self._data
else:
return None
@data.setter
def data(self, value):
self._data = value
def to_json(self):
dct = dict(self) # <--- note this: autoclass dict behaviour
dct['data'] = self.data
return dct
e = Example(request='hello')
print(repr(e))
产量:
Example(environment='dev', id='ee56cb2f-8a4a-48ac-9789-956f1eaea132', created='1592901475', request='hello', 'data': None)
注意:我是pyfields
and的作者autoclass
;)
推荐阅读
- tinymce - Tinymce 上传没有 url 的图片
- mysql - 写入远程 MySQL 服务器
- java - Tablayout 标题不出现
- postgresql - PostgreSQL 存储过程中“DECLARE”处或附近的语法错误
- javascript - 即使在 Postman 中获得成功响应,文件的内容也无法正确解码
- java - 仅使用 BitcoinJ 中的私钥获取压缩的公钥和比特币地址
- json - 解析 JSON 以获取关键字后的数据
- vba - 如何提高我的 vba 用户表单的搜索速度?
- vb.net - 如何在 vb.net 中一段时间后出现消息框?
- java - 将地图转换为嵌套地图