问题一: 我在类里面有比较多的类似下面的写法, 但感觉非常不合适, 这种情况应该怎么去处理, 这里会多次的判断获取属性
class Foo(object):
def __init__(self):
self.a = None
self.b = None
def get_a(self):
if not self.a:
self.a = xxxxx
def get_b(self):
if not self.b:
self.b = xxxxx
def do_sth1(self):
self.get_a() # 获取 self.a 属性
# 使用 self.a
def do_sth2(self):
self.get_a() # 获取 self.a 属性, 又一次
self.get_b() # 获取 self.b 属性
# 使用 self.a 和 self.b
问题二: 定义一个变量, type hint 指向一个自定义的类, 但这个变量我想为 空值(类似下面), 应该怎么写?
class Bar(object):
pass
v: Bar = None # 会警告不应该这么写
a_list: list = [] # 正确的写法
a_str: str = "" # 正确的写法
1
ClericPy 2020-12-03 23:20:07 +08:00 1
问题 1 里见过初始化 self._a 然后取的时候用 @property 来取, if not self._a: self._a = xxx 然后 return self._a
比较常见于需要惰性初始化协程相关对象, 必须等 running loop 启动的时候保证 loop 一致. 或者其他惰性初始化的情况 问题 2 的话, 我直接不让它提醒了 "python.linting.mypyPath": "mypy", "python.linting.mypyArgs": [ "--ignore-missing-imports", "--follow-imports=silent", "--show-column-numbers", "--no-strict-optional" ], |
2
Pagliacii 2020-12-03 23:30:41 +08:00 1
问题 2 可以这样写:
```python from typing import Optional v: Optional[Bar] = None ``` |
3
plko345 OP @ClericPy 谢谢指点, 还有关于问题一, 我是否从一开始类的设计上就存在问题, 因为我并没有使用到你说的 惰性初始化协程相关对象, 而且我写代码常常会这么写, 有时还会直接在 构造函数中 `self._a = self._get_a()` , 我感觉比较频繁这么使用是不对的
|
5
freakxx 2020-12-03 23:59:03 +08:00
@plko345 #3
问题一, 如果只是作为属性,并且不会经常改动,比如 set a,那么 init 就丢进去就好, 或者像 1 楼说的,你改为 property 写法 你这么写,感觉怪的地方在于你没显式返回,并且在 get 过程还做了 set 操作,显得不够清爽。 问题二, 我觉得这个写法是挺怪的,你不需要在这里声明,再赋值, 或者说,你在这里声明 v,意义其实不大,反而会造成困扰。 |
6
Pagliacii 2020-12-04 00:04:33 +08:00
@plko345 #3 `self.a = self._get_a()` 这样写的话,self.a 不就为 None 了吗?我看你的 self._get_a() 设置了 self.a 但是它没有返回值。
另外,如果你想对属性赋值或取值时作出控制,你可以使用 property 这个装饰器,如下: ![image.png]( https://i.loli.net/2020/12/04/FxiKdVtsI9mZJ3R.png) |
8
plko345 OP @Pagliacii 是我没讲清楚,`self.a = self._get_a()` 这样写的时候是有 return 的
|
9
zone10 2020-12-04 10:02:24 +08:00
前面的已经说了, @property 和 optional, 你的 get 方法都没返回值怎么 get, 风格就不对了, 不太了解你的需求, 可能看一下 attrs 和 pydantic 这两个库能有所启发
|
10
azcvcza 2020-12-04 10:04:42 +08:00
要是 JS 的话,我喜欢这么做
``` class foo{ constructor(){ this.data = {}; this.functions = {}; } get(key){ return this.data[key] ? this.data[key] : undefined; } doSomething(key, data){ if(this.functions[key]){ this.functions[key](data); } else { throw new Error('function not exists'); } } } var f = new foo(); f.data = {a : 2}; f.functions = {a: (data)=>{console.log(data)}} f.get(a); f.doSomething(a,'hello world'); ``` |
11
no1xsyzy 2020-12-04 11:14:29 +08:00
|
12
xpresslink 2020-12-04 17:53:14 +08:00
(问题一)实在理解不了你的思维。如果 self.a/b 的初始值是固定的 xxxxx,直接放__init__里面就可以了。
为什么要先在__init__赋个 None 然后再弄两个函数,在函数里面还多此一举检查有没有这个属性,分别再赋那个具体的值呢?直接写成下面这样不就行了么: class Foo(object): □□ def __init__(self): □□□□self.a = xxxxx □□□□self.b = xxxxx 问题二: >>> v:Bar = None >>> v >>> b:Bar = Bar() >>> b <__main__.Bar object at 0x000001FC1AD36448> None 表示空值,它是一个特殊 Python 对象, None 的类型是 NoneType 所以你说的这个变量我想为空值这个概念并不适合 Python 语言的变量。 在 python 中变量并不同于 C++这类的静态语言,并不是容器的概念。 在 python 中赋值过程是先执行等号右边语句创建对象,然后把对象地址赋给左边的“变量”,本质上变量只是个标签。 |
13
plko345 OP @xpresslink 问题一里,"xxxxx" 是一连串的过程,self.a 属性可能用到也可能用不到,用不到就没必要去执行 xxxxx 的过程,所以才有个 get 操作(经提醒应该改成 set),不过我也说了我觉得这么设计感觉不对。问题二我觉得二楼大大的方式比较符合我的需要,而且 Python 都有 type hint 了,也应该要考虑加入解决这个问题的方案,二楼的应该算是官方的一种解决方案了吧
|