- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
作为一个学习练习,我正在尝试实现一个模拟 python 的 complex
内置行为的类,但 __str__
和 的行为不同>__repr__
方法:我希望它们以格式打印...
(1.0,2.0)
...而不是:
(1+2j)
我首先尝试简单地从 complex
子类化并重新定义 __str__
和 __repr__
,但这有一个问题,当调用非覆盖方法时,返回一个标准的complex
,并以标准格式打印:
>>> a = ComplexWrapper(1.0,1.0)
>>> a
(1.0,1.0)
>>> b = ComplexWrapper(2.0,3.0)
>>> b
(2.0,3.0)
>>> a + b
(3+4j)
当期望的输出是(3.0,4.0)
时。
我正在阅读有关元类的内容,并认为它们可以解决我的问题。从Python Class Decorator中的答案开始,我目前的实现如下:
def complex_str(z):
return '(' + str(z.real) + ',' + str(z.imag) + ')'
def complex_repr(z):
return '(' + repr(z.real) + ',' + repr(z.imag) + ')'
class CmplxMeta(type):
def __new__(cls, name, bases, attrs):
attrs['__str__'] = complex_str
attrs['__repr__'] = complex_repr
return super(CmplxMeta, cls).__new__(cls, name, bases, attrs)
class ComplexWrapper(complex):
__metaclass__ = CmplxMeta
不幸的是,这似乎与之前的解决方案具有相同的行为(例如,当两个 ComplexWrapper
实例相互添加时)。
我承认,我并不完全理解元类。也许我的问题可以用不同的方式解决?
当然,我可以手动重新定义相关方法,如__add__
、__subtract__
等,但这样会很重复,所以我更喜欢更优雅的解决方案.
感谢任何帮助。
所以我对你的代码有很多不理解的地方:
ReturnTypeWrapper
元类的 __new__
方法从哪里获取参数?如果它们是自动传递的,我希望在这种情况下 name = "Complex", bases = (complex), dict = {}
。那是对的吗?这种自动传递类数据的方法是metaclass特有的吗?
你为什么使用 cls = type.__new__(mcs, name, bases, dct)
而不是 cls = type(mcs, name, bases, dct)
?是否只是为了避免与type()
的“其他含义”混淆?
我复制了您的代码,并在您的 ComplexWrapper
类中添加了我对 __str__
和 __repr__
的特殊实现。但它不起作用;打印任何 Complex
类型的对象只是以标准的 Python 格式打印。我不明白,因为这两个方法应该在元类的 for 循环中使用,但之后应该被我的定义覆盖。
我的代码的相关部分:
class Complex(complex):
__metaclass__ = ReturnTypeWrapper
wrapped_base = complex
def __str__(self):
return '(' + str(self.real) + ',' + str(self.imag) + ')'
def __repr__(self):
return '(' + repr(self.real) + ',' + repr(self.imag) + ')'
及其行为:
>>> type(a)
<class 'Cmplx2.Complex'>
>>> a.__str__
<bound method Complex.wrapper of (1+1j)>
>>> a.__str__()
'(1+1j)'
>>>
再次感谢您的回答,如果您在回答中提及以上内容,请随时编辑/删除它们!
最佳答案
您当前的方法行不通。你如何定义你的类不是问题 - complex
的方法在你调用它们时创建 complex
的新实例,而不是使用 type
输入对象。您将始终取回 complex
而不是 ComplexWrapper
的实例,因此不会调用您的自定义方法:
>>> type(ComplexWrapper(1.0,1.0) + ComplexWrapper(2.0,3.0))
<type 'complex'>
相反,您需要将complex
的方法返回的新complex
对象转换为返回派生类的对象。
这个元类包装了指定基类的所有方法,并将包装的方法附加到类中。包装器检查要返回的值是否是基类的实例(但不包括子类的实例),如果是,则将其转换为派生类的实例。
class ReturnTypeWrapper(type):
def __new__(mcs, name, bases, dct):
cls = type.__new__(mcs, name, bases, dct)
for attr, obj in cls.wrapped_base.__dict__.items():
# skip 'member descriptor's and overridden methods
if type(obj) == type(complex.real) or attr in dct:
continue
if getattr(obj, '__objclass__', None) is cls.wrapped_base:
setattr(cls, attr, cls.return_wrapper(obj))
return cls
def return_wrapper(cls, obj):
def convert(value):
return cls(value) if type(value) is cls.wrapped_base else value
def wrapper(*args, **kwargs):
return convert(obj(*args, **kwargs))
wrapper.__name__ = obj.__name__
return wrapper
class Complex(complex):
__metaclass__ = ReturnTypeWrapper
wrapped_base = complex
def __str__(self):
return '({0}, {1})'.format(self.real, self.imag)
def __repr__(self):
return '{0}({1!r}, {2!r})'.format(self.__class__.__name__,
self.real, self.imag)
a = Complex(1+1j)
b = Complex(2+2j)
print type(a + b)
请注意,这不会包装 __coerce__
特殊方法,因为它返回 complex
的 tuple
;如有必要,可以轻松转换包装器以查看序列内部。
未绑定(bind)方法的 __objclass__
属性似乎没有记录,但它指向定义该方法的类,所以我用它来过滤掉定义在非我们的类上的方法重新转换自。我在这里也使用它来过滤掉不是未绑定(bind)方法的属性。
关于python - 使用元类覆盖复杂内置方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10771010/
我试图在 (C) Python 源代码中找到内置 in 运算符的实现。我在内置函数源代码中搜索过,bltinmodule.c ,但找不到此运算符的实现。我在哪里可以找到这个实现? 我的目标是通过扩展此
我们正在开发一个 shell(学校项目)。我们不理解一种行为。为什么内置函数在重定向时不起作用? 喜欢 cd - | command 不改变目录。 或 export NAME=VALUE | comm
有人问有关如何对列表进行排序的问题。从基本List.Sort()到List.OrderBy()有几种方法。最可笑的是自己动手的SelectionSort。我迅速将其否决,但这使我思考。应用于列表的
我正在尝试使用 C 中内置的 qsort 函数对结构进行排序 typedef struct abc{ long long int fir; long long int sec; }abc; 在
我觉得有一些内置的东西。如果对象为空,我想要默认值(或者特别是 0,我只使用十进制/整数)。是否有编写此函数的内置方法? static int GetDecimalFromObject(object
Java 是否有用于生成和解析文档的内置 XML 库?如果不是,我应该使用哪个第三方? 最佳答案 Sun Java 运行时附带 Xerces 和 Xalan 实现,它们提供解析 XML(通过 DOM
我对 python 的“all”和生成器有以下问题: G = (a for a in [0,1]) all(list(G)) # returns False - as I expected 但是:
我有一些使用 gcc 内部函数的代码。我想包含代码以防缺少内在函数。我该怎么做? #ifdef __builtin_ctzll 不起作用。 最佳答案 使用最新版本的 clang,现在可以使用 __ha
人们常说应该在本地重新声明(某些)Lua 函数,因为这样可以减少开销。但这背后的确切规则/原则是什么?我怎么知道哪些功能应该完成,哪些是多余的?还是应该为每个功能完成,甚至是您自己的功能? 不幸的是,
我想实现以下功能: TestClass values 接受任意数量的 NewClass 对象 只有 NewClass 对象没有完全相同的属性值被添加到TestClass.values 我想出了这个:
我正在尝试编写一个存储过程(使用 SQL Server Management Studio 2008 R2)以从表中检索最大测量值。这似乎是一件容易的事,所以我写了一个简短的存储过程来获取 MAX。但
我刚写了我的第一个Electron应用程序。现在,我正在尝试通过electron-packager构建它。我的package.json看起来像这样: { "name": "pixelcast",
我正在寻找在 WPF 应用程序中使用的“安全”字体系列列表 - 应该安装在所有能够运行 WPF 的客户端机器上的字体系列。 Silverlight 有一个明确定义的列表( listed on MSDN
好吧,(在写了几次之后)发现System.Windows.Controls命名空间中已经有一个BooleanToVisibilityConverter,这真是一个惊喜。 可能还有更多这样隐藏的节省时间
在我的 gradle 构建文件中,我有以下插件 block plugins { `java-library` jacoco checkstyle } 这些都没有指定版本,但一切
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 3 年前。 Improve this ques
10 implementations String#reverse 已根据每个浏览器进行分析。 自 2011 年以来已对这些实现进行了解释。 当 ES6 出现时,有很多代码变得更加优雅和性能。 关于
在 Julia 包 BenchmarkTools 中,有一些像 @btime、@belapse 这样的宏对我来说似乎是多余的,因为 Julia 内置了@time、@elapse 宏。在我看来,这些宏服
我正在尝试编写一个简单的 LLVM 通行证,其目标如下: 查找所有 call指示。 在被调用函数中插入我编写的外部函数。 例如,考虑我有以下示例程序: #include #include int
我理解 'a) -> (rhs:'a -> 'a) -> 'a 在我感兴趣的情况下,我经常发现自己想要类似 (lhs:'a -> 'b) -> (rhs:'c -> 'b) -> 'b 的东西在侧面
我是一名优秀的程序员,十分优秀!