为什么我在创建从str继承的类(或者从int继承的类)时遇到问题?
1
2
3
4
5
6
7
8class C(str):
def __init__(self, a, b):
str.__init__(self,a)
self.b = b
C("a","B")
TypeError: str() takes at most 1 argument (2 given)
如果我尝试使用int而不是str,也会发生同样的情况,但它适用于自定义类。我需要用__new__而不是__init__?为什么?
1
2
3
4
5
6
7
8
9
10>>> class C(str):
... def __new__(cls, *args, **kw):
... return str.__new__(cls, *args, **kw)
...
>>> c = C("hello world")
>>> type(c)
>>> c.__class__.__mro__
(, , , )
号
由于在构造对象之后调用__init__,因此修改不可变类型的值为时已晚。注意,__new__是一个类方法,所以我调用了第一个参数cls。
有关详细信息,请参阅此处
1
2
3
4
5
6
7
8
9
10
11>>> class C(str):
... def __new__(cls, value, meta):
... obj = str.__new__(cls, value)
... obj.meta = meta
... return obj
...
>>> c = C("hello world","meta")
>>> c
'hello world'
>>> c.meta
'meta'
我用我自己的答案,帮助你操作系统的问题的答案在这里。好的,谢谢!
继承内置类型是非常不值得的。你必须处理好几个问题,但实际上你得不到多少好处。
使用构图几乎总是更好的。您将保留一个str对象作为属性,而不是继承str。
1
2
3class EnhancedString(object):
def __init__(self, *args, **kwargs):
self.s = str(*args, **kwargs)
。
您可以推迟任何您想在基础strself.s上使用的方法,手动或自动使用__getattr__。
也就是说,需要自己的字符串类型应该会让你暂停。有许多类应该存储一个字符串作为它们的主数据,但是您通常希望使用str或unicode(如果您表示文本,则后者)来表示字符串的一般表示。(一个常见的例外是,如果需要使用UI工具箱的字符串类型。)如果要向字符串中添加功能,请尝试使用对字符串而不是新对象操作的函数作为字符串,这样可以使代码更简单,更与其他人的程序兼容。
是的,这是我的第一个解决方案,但我有一个问题是,一些函数的字符串参数是想要(他们是从C + +函数库,I can’t修改)操作系统实现这些函数的使用与我的工作我的类的参数。你可以得到更好的解释这一结果__getattr__如何使用?
"接受维速,一个参数是一个字符串underdefined的事。我不知道你是什么样的C + +库和它是如何包装的包裹,但应该做的正确的类型的兼容工作。制作你自己的新类中所看到的那一个人,而不是利用它在Python的字符串或字符串的类的类(和它看起来像这样的工作)的工作方式,使奇异的事情。
"明智的,使用未定义的属性__getattr__推迟到其他特定的属性的组合是一对在accomplished样def __getattr__(self, name): return getattr(self.s, name))代码。请注意,此代码是不是好的建议,一定可以解决,但在一些情况下,它的更好的东西,往往要到你手动设置在组合。
我有一个c_function(char*),我可以使用它在Python中的c_function(s)s是str实例。S代表的东西,和我想要的,这有beautiful_namename,在线等。我有一个来自strC衍生类,所以我可以通一到C对象的类,例如的Cpython_functionprint c.name和呼叫c_function(c)
"inheriting >内置类型,是非常不值得。"这可能是真实的,但不总是。有时它是有用的创建省级"标记字符串"类型,如不同类型的字符串产生的令牌从一类的解析器。然而,与它的问题,那是你的(我认为)在短柱的性能优化。
@案例中,Blais,组合仍然是不多的,易错的。从strinheriting是潜在的误差源,但不是真的帮助你。
我不convinced。为什么你认为你能指出潜在的inheriting源从STR是错误的吗?因为它不是idiomatic吗?
docs.python.org / 3 /图书馆/ & hellip;"类的行为,userstring包装周围的字符串对象。需要为这个类已经由局部supplanted能力直接从乙方的子类;"这并不是说不。
"你的suppose Blais,your_subclass[:5]或your_subclass.replace(x, y)-什么回报吗?一个实例的实例的子类或一str你吗?即使这是不是确定的,但在实践中,它将返回str。有没有保证,任何方式,这是未定义行为的排序(坏的东西。
"你应该总是Blais,写的代码是可能的和平的不了解什么是可能的。是一个简单的内置程序,很难想起的,持久的,和使用。
当实例化一个类时,传入的参数将同时传递给该类的__new__方法和__init__方法。因此,如果您继承的类对实例化期间可能提供的参数数量有限制,则必须保证其__new__和__init__都不会得到比预期更多的参数。所以这就是你的问题所在。用C("a","B")实例化类。解释器在C中查找__new__方法。C没有它,所以python窥视它的基类str。因为它有一个,所以使用和提供两个参数。但是str.__new__只期望得到一个参数(除了作为第一个参数的类对象之外)。所以提出了TypeError。这就是为什么你必须在你的孩子班上扩展它,类似于你对__init__所做的。但是要记住,如果使用super函数,它必须返回类实例,并且它是一个静态方法(不管它是否用@staticmethoddecorator定义)。
要验证,请在提示下尝试:>>> str.__init__('abc', 'def')。这没用。但是,>>> str.__new__(str, 'abc', 'def')抛出了例外:TypeError: str() takes at most 1 argument (2 given)。这有点让人困惑,因为我们称str.__new__(..)为3个参数,而不是2个参数。这是否意味着str.__new__(..)接受任何数量的参数,然后调用str(..)?可能不会,因为str(..)会依次调用str.__new__(..)。
@evgeni:str类对象根本不实现__init__方法。basestring也不是(str的基类)。__init__直接从object继承而来,并且该继承人接受任何数量的论据。相反,__new__方法实际上是在str中实现的,除了第一个必须是str或其子类的参数外,它最多接受1个参数。用__new__、basestring、object等表达。
这是检查实现哪些方法的好方法。我还是有点困惑为什么我要写str.__new__(str, 'abc', 'def'),它说我提供了2个参数。我数到三。例如class C(object):
@staticmethod
def m(a): pass,如果我把它叫做C.m(1, 2),它会像预期的那样说TypeError: m() takes exactly 1 argument (2 given)。我猜__new__产生了一个混乱的消息,因为__new__是特殊的(例如,在实现它时不需要添加@staticmethod)。
对于不可变类型,使用__new__:
1
2
3
4
5
6
7
8
9class C(str):
def __new__(cls, content, b):
return str.__new__(cls, content)
def __str__(self):
return str.__str__(self)
a=C("hello","world")
print a
print返回hello。
python字符串是不可变的类型。调用函数__new__来创建对象C的新实例。python __new__函数的基本存在是为了允许从不可变类型继承。
type(C("a","B"))→NoneType
你试试你的答案吗?现在它的回报"
1?至少你可以写评论吗?
2我写的评论。
你的检查和更新的帖子?根据你的要求,这是最新的。你倒是voted后的变化。此外,在你的评论,你会从我的代码功能,这是不要求的问题(让你_ _ str()函数_ _工作在继承的类)。
在第一次执行代码后的第二NoneType归国后,""它了。它不要求功能吗?I didn’t ask a __str__函数和它是不必要的,因为从类继承的str,国有企业gnibbler回答。现在我不能修改的downvote,i需要你编辑你的答案。
仔细阅读之后,这里还有另一种尝试,试图对str进行子类化。与其他答案不同的是,使用super(TitleText, cls).__new__在正确的类中创建实例。这个函数在使用时的行为看起来像str,但允许我重写一个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class TitleText(str):
title_text=""
def __new__(cls,content,title_text):
o=super(TitleText, cls).__new__(cls,content)
o.title_text = title_text
return o
def title(self):
return self.title_text
>>> a=TitleText('name','A nice name')
>>> a
'name'
>>> a[0]
'n'
>>> a[0:2]
'na'
>>> a.title()
'A nice name'
这样可以正确地进行切片和订阅。这是干什么的?用于重命名管理索引页中的Django应用程序。
讨厌!您的repr是欺骗性的,这一事实导致我们不清楚,虽然a是TitleText,但a[0]和a[0:2]是str(现在,在当前版本中,作为实现细节)。如果您编写了一个没有继承str的类,那么您可以使一个更有用、更不容易混淆和欺骗的东西。