【发布时间】:2018-07-30 03:44:34
【问题描述】:
感谢大家迄今为止的帮助。我已经缩小了一点。如果您在脚本和类中都查看 HERE,然后运行脚本,您会看到发生了什么。
ADD 行打印“789 789”
什么时候应该打印“456 789”
似乎正在发生的事情是,在 new 中,该类正在检测传入参数的类型。但是,如果传入对象与构造函数具有相同的类型,则它似乎正在将传入对象分页到自身(在类级别)而不是返回旧对象。这是我能想到的唯一会导致 456 变得奶油的事情。
那么,如何在构造函数中检测到与类相同类型的内容并决定不将该数据分页到类内存空间中,而是返回先前构造的对象?
import sys
import math
class Foo():
# class level property
num = int(0)
#
# Python Instantiation Customs:
#
# Processing polymorphic input new() MUST return something or
# an object?, but init() cannot return anything. During runtime
# __new__ is running at the class level, while init is running
# at the instance level.
#
def __new__(self,*arg):
print ("arg type: ", type(arg[0]).__name__)
### functionally the same as isinstance() below
#
# if (type(arg[0]).__name__) == "type":
# if arg[0].__name__ == "Foo":
# print ("\tinput was a Foo")
# return arg[0] # objects of same type intercede
### HERE <-------------------------------------
#
# this creams ALL instances, because since we are a class
# the properties of the incoming object, seem to overwride
# the class, rather than exist as a separate data structure.
if (isinstance(arg[0], Foo)):
print ("\tinput was a Foo")
return arg[0] # objects of same type intercede
elif (type(arg[0]).__name__) == "int":
print ("\tinput was an int")
self.inum = int(arg[0]) # integers store
return self
elif (type(arg[0]).__name__) == "str":
print ("\tinput was a str")
self.inum = int(arg[0]) # strings become integers
return self
return self
def __init__(self,*arg):
pass
#
# because if I can do collision avoidance, I can instantiate
# inside overloaded operators:
#
def __add__(self,*arg):
print ("add operator overload")
# no argument returns self
if not arg:
return self
# add to None or zero return self
if not arg[0]:
return self
knowntype = Foo.Foo(arg[0])
# add to unknown type returns False
if not knowntype:
return knowntype
# both values are calculable, calculate and return a Foo
typedresult = (self.inum + knowntype.inum)
return Foo.Foo(typedresult)
def __str__(self): # return a stringified int or empty string
# since integers don't have character length,
# this tests the value, not the existence of:
if self.inum:
return str(self.inum)
# so the property could still be zero and we have to
# test again for no reason.
elif self.inum == 0:
return str(self.inum)
# return an empty str if nothing is defined.
return str("")
testfoo.py:
#! /usr/bin/python
import sys
import Foo
# A python class is not transparent like in perl, it is an object
# with unconditional inheritance forced on all instances that share
# the same name.
classhandle = Foo.Foo
# The distinction between the special class object, and instance
# objects is implicitly defined by whether there is a passed value at
# constructor time. The following therefore does not work.
# classhandle = Foo.Foo()
# but we can still write and print from the class, and see it propagate,
# without having any "object" memory allocated.
print ("\nclasshandle: ", classhandle)
print ("classhandle classname: ", classhandle.__name__) # print the classname
print ("class level num: ", classhandle.num) # print the default num
classhandle.classstring = "fdsa" # define an involuntary value for all instances
print ("\n")
# so now we can create some instances with passed properties.
instance1 = Foo.Foo(int(123)) #
print ("\ninstance1: ", instance1)
print ("involuntary property derived from special class memory space: ", instance1.classstring)
print ("instance property from int: ", instance1.inum)
print ("\n")
instance2 = Foo.Foo(str("456"))
print ("\ninstance2: ", instance2)
print ("instance2 property from int: ", instance2.inum)
#
# instance3 stands for (shall we assume) some math that happened a
# thousand lines ago in a class far far away. We REALLY don't
# want to go chasing around to figure out what type it could possibly
# be, because it could be polymorphic itself. Providing a black box so
# that you don't have to do that, is after all, the whole point OOP.
#
print ("\npretend instance3 is unknowningly already a Foo")
instance3 = Foo.Foo(str("789"))
## So our class should be able to handle str,int,Foo types at constructor time.
print ("\ninstance4 should be a handle to the same memory location as instance3")
instance4 = Foo.Foo(instance3) # SHOULD return instance3 on type collision
# because if it does, we should be able to hand all kinds of garbage to
# overloaded operators, and they should remain type safe.
# HERE <-----------------------------
#
# the creation of instance4, changes the instance properties of instance2:
# below, the instance properties inum, are now both "789".
print ("ADDING: ", instance2.inum, " ", instance4.inum)
# instance6 = instance2 + instance4 # also should be a Foo object
# instance5 = instance4 + int(549) # instance5 should be a Foo object.
【问题讨论】:
-
这可能是一个迂腐的观点,但我认为重要的是,“那些输入类型可能是基元或对象。” Python 中没有原始类型。一切都是对象。
-
“一切都是对象”:对我来说这似乎是不正确的。在 new 中(构造函数阶段?) type() 没有找到传递结构的命名空间,但在 init 中找到了。在 perl 术语中,这意味着数据结构在 new 中是未受祝福的,并且还不是对象。这是一种强制性的习俗。据我所知,除了让一群人从一个共同的角度看待代码之外,没有任何理由。
-
我不明白你在这里说什么,以及它与 Python 中的 everything are an object 有何关系。同样,没有原始类型。当您说“type() 未找到传递结构的名称空间”时,您的意思不清楚。通过什么结构?什么命名空间?命名空间实际上只是 Python 中的对象,通常(尽管不总是)
dict对象。您似乎正在尝试应用 Pearl 中不适用于 Python 的概念,没有“有福和无福”的对象 -
无论如何,这里有一个很好的答案来描述你对
__new__和__init__的错误。此外,(type(arg[0]).__name__) == "int"这个构造不是你应该如何在 Python 中进行类型检查。如果你想要一个特定的类型,你使用type(obj) is int,如果你想处理子类关系,使用isinstance(obj, int)。__name__属性是您所说的命名空间吗? -
@JamesAanderson 您可以在
__super__中进行操作,就像 abarnart 的回答一样。instance = super().__new__(cls); instance.inum = int(arg[0]); return instance。请记住,__new__应该返回一个实例,而不是self,它实际上是类,这就是为什么在实现__new__时按惯例将其命名为cls只是为了提醒您。
标签: python python-3.x