举个例子,我实现了一个过滤出字符串中所有数字的功能,函数名为filter_number
,我想要附加到 str 对象上,这样调用函数可以写成"abc123abc".filter_number()
。
我目前知道的做法就是新建对象继承 str ,但是调用前还是要手动转一遍s = CustomStr("abc123abc")
,这就有点脱裤子放屁了。
不知道这个需求能不能实现,最好还要能被 ide 感知,编写时能够提示出来。
1
abersheeran 314 天前 1
省流:做不了,IDE 感知不到。
|
2
chaleaochexist 314 天前
str 不知道
我知道 dict, 有一个 Userdict 是官方标准库提供的, 专门给用户干这事儿的. |
3
capbone 314 天前
```python
import builtins class _CustomStr(str): def filter_number(self): pass builtins.str = _CustomStr ``` 对于显示声明为 str 的对象有效,但是对字面值无效: ``` str("abc123abc").filter_number() # OK ``` ``` "abc123abc".filter_number() AttributeError: 'str' object has no attribute 'filter_number' ``` |
4
capbone 314 天前
不知道 v2 code block 的语法,抱歉……
|
5
McZoden 314 天前
同关注
C# 有 extension method 的语法糖,虽然实现方法也是类似于,新定义一个 Static Class ,包含一个 Static Method ,但调用方法就直接是用原生类型的实例去调用了 Python 可能针对 str ,这种内置的对象,不行,没有这样的语法糖 |
6
mightybruce 314 天前
在 Python 中,不能直接在 str 类型上添加自定义方法。但是,可以通过创建一个新的类来继承 str 类,并在新类中添加自定义方法。以下是一个示例:
class MyStr(str): def my_custom_method(self): # 在这里实现你的自定义方法 pass # 使用自定义类 my_str = MyStr("Hello, world!") my_str.my_custom_method() 或者修改 str 的 built-in 方法 一些常见对象的魔术方法 __len__, __getitem__, __contains__, __add__, __mul__, __mod__, __format__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __hash__, __repr__, __str__, __bytes__, __bool__, __int__, __float__, __complex__, __index__, __trunc__, __floor__, __ceil__, __round__, __enter__, __exit__, __new__, __init__, __del__, __call__, __getattr__, __setattr__, __delattr__, __dir__, __getattribute__, __setitem__, __delitem__, __iter__, __next__, __reversed__, __len__, __contains__, __add__, __mul__, __rmul__, __mod__, __format__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __hash__, __repr__, __str__, __bytes__, __bool__, __int__, __float__, __complex__, __index__, __trunc__, __floor__, __ceil__, __round__, __enter__, __exit__, __new__, __init__, __del__, __call__, __getattr__, __setattr__, __delattr__, __dir__, __getattribute__, __setitem__, __delitem__, __iter__, __next__, __reversed__, __contains__, __add__, __mul__, __rmul__, __mod__, __format__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __hash__, __repr__, __str__, __bytes__, __bool__, __int__, __float__, __complex__, __index__, __trunc__, __floor__, __ceil__, __round__, __enter__, __exit__, __new__, __init__, __del__, __call__, __getattr__, __setattr__, __delattr__, __dir__, __getattribute__, __setitem__, __delitem__, __iter__, __next__, __reversed__, __len__, |
7
CaptainD 314 天前
我自己的理解是做不到,不知道有没有什么奇淫巧技
态添加函数可以有两种方式做到 1. 继承 2. 修改对象的内置属性 而字符串是不可变的,2 做不到,只能是 1 ,也就是你说的“新建对象继承 str” 字典是可以使用 2 的,因为字典是可变对象,但 UserDict 其实也是用继承 |
8
kmyq 314 天前
昨天刚问 Chatgpt 这个问题,已声明的倒是可以
-- 在 Python 中,您可以使用 types.MethodType 将一个函数绑定到一个类的实例上。这允许您只为具体的实例添加函数,而不会更改整个类的定义。以下是一个示例: python import types class MyClass: def __init__(self, value): self.value = value # 定义一个将要绑定的函数 def print_value(self): print(self.value) # 创建一个 MyClass 的实例 obj = MyClass(10) # 将函数绑定到这个实例 obj.print_value = types.MethodType(print_value, obj) # 调用新绑定的函数 obj.print_value() 在上面的示例中,我们在 MyClass 的实例 obj 上绑定了 print_value 函数。具体细节如下: 首先,我们定义了一个 MyClass 。该类包含了一个__init__构造函数,以及我们希望将其绑定的函数。 我们定义了 print_value 函数,该函数接受一个参数 self ,它将打印 self.value 。 然后,我们创建了 MyClass 的实例 obj ,并将要绑定的函数 print_value 绑定到了这个具体的实例上。 最后,我们调用新绑定的函数:obj.print_value()。 这样,我们就通过函数式编程功能将一个函数绑定到了 MyClass 的实例上。 |
9
zzhaolei 314 天前
没有语言能无副作用的直接为内置类型添加方法。如果你为 str 添加了方法 a ,lib b 也为 str 添加了方法 a 和 b ,那么调用 str.a() 的时候是调用你的 a 还是 lib b 的 a ?而且你直接调用 str.b() 的时候是给你提示 lib b 定义的 b 还是给你报错?这复杂度直接爆炸。
现在的通用做法是,如果你要给 str 添加方法,那么你就定义一个新的类型,然后在自己定义的类型上定义方法。 python 可以 class MyStr(str) 继承 str 。 |
10
mightybruce 314 天前
|
12
c2const 313 天前
或许可以换成 C++语言 :)
|
13
Alias4ck 313 天前
xy 问题
|
14
lolizeppelin 313 天前 2
我敢打赌 楼主原来是写 js 的
|
15
msg7086 313 天前
你这 Python 怎么写得一股 Ruby 味啊(
|
16
bybyte 313 天前
修改 py 源码?
|
17
atuocn 313 天前
参考 8 楼,依稀记得 meta class 可以做到
|
18
MiketsuSmasher 313 天前 via Android
标准库里提供了一个 collections.UserString ,专门方便你干这种事情的
|
19
codehz 313 天前
https://github.com/xpodev/extype
也不是完全不行,用原生扩展包里改 |
20
bianhui 313 天前
随便定义一个类型继承 str,写个空方法
然后再使用的试试 a:自定义类型 = ""或者 typing 下 cast a = cast(a,自定义类型) 编辑器就可以自己识别了 |
21
frostming 313 天前
如 #1 所说,没用,IDE 感知不到,但你非要骚操作的话:
import gc d = gc.get_referents(str.__dict__)[0] d['show'] = lambda self: 'hello? are you okay?' 'foo'.show() # hello? are you okay? |
22
listenerri 313 天前
不要魔改基础库,你改了用着爽了,别人怎么维护
虽然此例能实现的话目前影响不大,但应该要以小见大,很多深坑都是一点点堆出来的 |
23
forgottencoast 313 天前
@zzhaolei
看#5, #14 |
24
zzhaolei 312 天前
@forgottencoast #23 学到了。突然想起来这种有 vm 的语言本身是超级动态的🤔
|
25
351994 311 天前
可以实现,aHR0cHM6Ly9ibG9nLnplYmVkeS5jb20vcG9zdC82Y2YyZTIwOS5odG1s
参考这里的,base64 |
26
351994 311 天前 1
是可以实现的,
import ctypes class PyType(ctypes.Structure): pass class PyObject(ctypes.Structure): Py_ssize_t = ( ctypes.c_int64 if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_int32 ) _fields_ = [ ("ob_refcnt", Py_ssize_t), ("ob_type", ctypes.POINTER(PyType)), ] class PyTypeObject(PyObject): _fields_ = [ ("dict", ctypes.POINTER(PyObject)) ] def inject(class_, function_name): def _(function): name_, dict_ = class_.__name__, class_.__dict__ proxy_dict = PyTypeObject.from_address(id(dict_)) namespace = {} ctypes.pythonapi.PyDict_SetItem( ctypes.py_object(namespace), ctypes.py_object(name_), proxy_dict.dict ) namespace[name_][function_name] = function return _ 可以参考#25 中的内容,发不了网址,base64 了一下 |