我正在使用类set()和__hash__方法python来防止在set中添加相同的哈希对象.根据python数据模型文档,set()将相同的哈希对象视为同一个对象,只需添加一次即可.
但它的行为如下:
class MyClass(object):
def __hash__(self):
return 0
result = set()
result.add(MyClass())
result.add(MyClass())
print(len(result)) # len = 2
Run Code Online (Sandbox Code Playgroud)
在字符串值的情况下,它可以正常工作.
result.add('aida')
result.add('aida')
print(len(result)) # len = 1
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么相同的哈希对象在集合中不相同?
根据object.__eq__()文档,默认(即在object类中)实现==如下:
True if x is y else NotImplemented
Run Code Online (Sandbox Code Playgroud)
仍然遵循的文档NotImplemented,我推断这NotImplemented意味着 Python 运行时将尝试以相反的方式进行比较。y.__eq__(x)即如果x.__eq__(y)返回则尝试NotImplemented(在运算符的情况下==)。
现在,在 python 3.9 中False打印以下代码:True
class A:
pass
print(A() == A())
print(bool(NotImplemented))
Run Code Online (Sandbox Code Playgroud)
所以我的问题如下:文档在哪里提到了NotImplemented在上下文中的特殊行为__eq__?
PS:我在CPython 源代码中找到了答案,但我想这必须/应该在文档中的某个位置。
在python中,可以使用'.' 为了访问对象的字典项.例如:
class test( object ) :
def __init__( self ) :
self.b = 1
def foo( self ) :
pass
obj = test()
a = obj.foo
Run Code Online (Sandbox Code Playgroud)
从上面的示例中,拥有'a'对象,是否有可能从它引用'obj',它是'foo'方法分配的父命名空间?例如,将obj.b更改为2?
在Python中,str(),int(),float()等函数通常用于执行类型转换.但是,这些要求您在开发时了解要转换为的类型.我正在尝试编写的一些Python代码的子问题如下:
给出两个变量,foo并bar找到类型foo.(在开发时不知道,因为这是通用代码.)然后,尝试转换bar为任何类型foo.如果无法做到这一点,请抛出异常.
例如,假设您调用执行此操作的函数conv.它的签名看起来像
def conv(foo, bar) :
# Do stuff.
Run Code Online (Sandbox Code Playgroud)
它会被称为:
result = conv(3.14, "2.718") # result is now 2.718, as a float.
Run Code Online (Sandbox Code Playgroud) python reflection introspection type-conversion python-datamodel
我已经开始在我编写的代码中更广泛地使用python描述符协议.通常,默认的python查找魔法是我想要发生的,但有时我发现我想获取描述符对象本身而不是其__get__方法的结果.想知道描述符的类型,或者描述符中存储的访问状态,或者某些东西.
我编写了下面的代码,以我认为正确的顺序遍历名称空间,并返回属性raw,无论它是否是描述符.我很惊讶,虽然我无法在标准库中找到内置函数或其他内容来实现这一点 - 我认为它必须在那里,我只是没有注意到它或用Google搜索正确的搜索词.
python发行版中的某个地方是否有功能(或类似的东西)?
谢谢!
from inspect import isdatadescriptor
def namespaces(obj):
obj_dict = None
if hasattr(obj, '__dict__'):
obj_dict = object.__getattribute__(obj, '__dict__')
obj_class = type(obj)
return obj_dict, [t.__dict__ for t in obj_class.__mro__]
def getattr_raw(obj, name):
# get an attribute in the same resolution order one would normally,
# but do not call __get__ on the attribute even if it has one
obj_dict, class_dicts = namespaces(obj)
# look for a data descriptor in class hierarchy; it takes priority over …Run Code Online (Sandbox Code Playgroud) 我正在阅读Counter类的__init__方法,并看到了这个:
if not args:
TypeError("descriptor '__init__' of 'Counter' object "
"needs an argument")
Run Code Online (Sandbox Code Playgroud)
我不确定描述符是什么意思,所以我检查了python数据模型文档,发现了这个:
通常,描述符是具有"绑定行为"的对象属性,其属性访问权已被描述符协议中的方法覆盖:__ get __(),__ set __()和__delete __().如果为对象定义了任何这些方法,则称其为描述符.
这些方法似乎都没有出现在类定义中,为什么__init_被称为描述符?
如果元类没有
__prepare__属性,则将类命名空间初始化为空有序映射.
定义顺序是否也保留在模块对象中?
# foo_bar.py
def foo():
pass
def bar():
pass
Run Code Online (Sandbox Code Playgroud)
我已经尝试了上面的模块(也交换了顺序),它似乎确实可靠:
>>> import foo_bar
>>> for name in foo_bar.__dict__:
... if not name.startswith('_'):
... print(name)
...
foo
bar
Run Code Online (Sandbox Code Playgroud)
据推测,该模块命名空间还采用了紧凑字典底下,或者从一个事实,即遵循type(foo_bar)是<class 'module'>,它也必须尊重定义顺序,像任何其他类.但是,我不确定这是否是Python保证的功能,或者只是CPython实现细节. 模块中的名称是否需要遵守定义排序?
我有一个小助手班:
class AnyOf(object):
def __init__(self, *args):
self.elements = args
def __eq__(self, other):
return other in self.elements
Run Code Online (Sandbox Code Playgroud)
这让我做了甜蜜的魔术:
>>> arr = np.array([1,2,3,4,5])
>>> arr == AnyOf(2,3)
np.array([False, True, True, False, False])
Run Code Online (Sandbox Code Playgroud)
无需使用列表理解(如np.array(x in (2,3) for x in arr).
(我维护一个让(可信)用户输入任意代码的用户界面,并且a == AnyOf(1,2,3)比非技术精明用户的列表理解更加可口.)
然而!
这只适用于一种方式!例如,如果我这样做,AnyOf(2,3) == arr那么我的AnyOf类的__eq__方法永远不会被调用:相反,NumPy数组的__eq__方法被调用,在内部(我会假设)调用其__eq__所有元素的方法.
这让我想知道:为什么Python不允许右侧等效__eq__?(大致相当于像__radd__,__rmul__等等的方法.)
文档说值视图不被视为set-like,但有时它们是:
>>> d = {1: 1}
>>> d.values() | d.keys()
{1}
>>> d.values() & d.keys()
{1}
>>> d.values() - d.keys()
set()
Run Code Online (Sandbox Code Playgroud)
为什么要实现返回集合的集合语义,但随后却因实际集合而失败?
>>> d.values() - {1}
TypeError: unsupported operand type(s) for -: 'dict_values' and 'set'
Run Code Online (Sandbox Code Playgroud) 我偶然发现了这段代码,我觉得很奇怪,因为它似乎违反了 python 内置函数直接从对象的类调用 dunder 方法的事实。举__call__个例子,如果我们定义类A如下:
class A:\n @property\n def __call__(self):\n def inner():\n return 'Called.'\n return inner\n\na = A()\na() # return 'Called.'\n\ntype(a).__call__(a) # return 'property' object is not callable. \nRun Code Online (Sandbox Code Playgroud)\n然而,这种行为似乎与Python官方文档中所说的相矛盾:
\n\n\n\n
object.__call__(self[, args...])当实例\xe2\x80\x9c称为\xe2\x80\x9d\nas函数时调用;如果定义了此方法,则x(arg1, arg2, ...)大致\n转换为type(x).__call__(x, arg1, ...).
谁能解释一下这是怎么回事?
\npython ×10
python-datamodel ×10
python-3.x ×2
set ×2
descriptor ×1
dictionary ×1
hash ×1
numpy ×1
python-3.6 ×1
reflection ×1