关于编程思维方式, 想请教两个问题

2020-12-03 23:08:40 +08:00
 plko345

问题一: 我在类里面有比较多的类似下面的写法, 但感觉非常不合适, 这种情况应该怎么去处理, 这里会多次的判断获取属性

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 = ""    # 正确的写法
2504 次点击
所在节点    Python
13 条回复
ClericPy
2020-12-03 23:20:07 +08:00
问题 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"
],
Pagliacii
2020-12-03 23:30:41 +08:00
问题 2 可以这样写:

```python
from typing import Optional
v: Optional[Bar] = None
```
plko345
2020-12-03 23:40:24 +08:00
@ClericPy 谢谢指点, 还有关于问题一, 我是否从一开始类的设计上就存在问题, 因为我并没有使用到你说的 惰性初始化协程相关对象, 而且我写代码常常会这么写, 有时还会直接在 构造函数中 `self._a = self._get_a()` , 我感觉比较频繁这么使用是不对的
plko345
2020-12-03 23:42:45 +08:00
@Pagliacii 感谢, 这种写法像 rust 的 Option
freakxx
2020-12-03 23:59:03 +08:00
@plko345 #3

问题一,
如果只是作为属性,并且不会经常改动,比如 set a,那么 init 就丢进去就好,
或者像 1 楼说的,你改为 property 写法

你这么写,感觉怪的地方在于你没显式返回,并且在 get 过程还做了 set 操作,显得不够清爽。

问题二,
我觉得这个写法是挺怪的,你不需要在这里声明,再赋值,
或者说,你在这里声明 v,意义其实不大,反而会造成困扰。
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)
plko345
2020-12-04 01:12:15 +08:00
@freakxx 多谢建议,问题二我主要想用在函数参数里,不过用到的情况不多
plko345
2020-12-04 01:14:29 +08:00
@Pagliacii 是我没讲清楚,`self.a = self._get_a()` 这样写的时候是有 return 的
zone10
2020-12-04 10:02:24 +08:00
前面的已经说了, @property 和 optional, 你的 get 方法都没返回值怎么 get, 风格就不对了, 不太了解你的需求, 可能看一下 attrs 和 pydantic 这两个库能有所启发
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');

```
no1xsyzy
2020-12-04 11:14:29 +08:00
functools.cached_property

Backports: <https://pypi.org/project/backports.cached-property/>
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 中赋值过程是先执行等号右边语句创建对象,然后把对象地址赋给左边的“变量”,本质上变量只是个标签。
plko345
2020-12-04 22:27:44 +08:00
@xpresslink 问题一里,"xxxxx" 是一连串的过程,self.a 属性可能用到也可能用不到,用不到就没必要去执行 xxxxx 的过程,所以才有个 get 操作(经提醒应该改成 set),不过我也说了我觉得这么设计感觉不对。问题二我觉得二楼大大的方式比较符合我的需要,而且 Python 都有 type hint 了,也应该要考虑加入解决这个问题的方案,二楼的应该算是官方的一种解决方案了吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/731930

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX