我有这段代码:
class Singleton(type):
def __call__(cls,*args,**kwargs):
if cls.created is None :
print('called')
cls.created = super().__call__(*args,**kwargs)
return cls.created
else:
return cls.created
def __new__(cls,name,base,attr,**kwargs):
return super().__new__(cls,name,base,attr,**kwargs)
class OnlyOne(metaclass=Singleton):
created = None
def __init__(self,val):
self.val = val
class OnlyOneTwo(OnlyOne):
pass
k = OnlyOne(1)
a = OnlyOneTwo(2)
print(a.val)
print(k.val)
print('a.created: {0} - b.created: {1}'.format(id(a.created),id(k.created)))
我是Python 3的新手,所以我决定做一些小实验并玩Python的元类。
在这里,我尝试创建一个元类,它将在设置时将类严格限定为单个实例。
我不确定这是否有效,但每当我尝试这样做时:
k = OnlyOne(1)
a = OnlyOneTwo(2)
输出将是:
called
1
1
这意味着OnlyOneTwo
没有设置,但是当我尝试这样做时:
a = OnlyOneTwo(2)
k = OnlyOne(1)
输出将是:
called
called
2
1
有人可以帮我追溯吗?我有些困惑,但这是我最初的问题/想法:
OnlyOneTwo
created
属性与OnlyOne
'相同吗?因为我通过id()
获得了不同的结果,这取决于我先定义的那个。如果它是OnlyOneTwo
首先是不同的,但如果OnlyOne
首先是created
则相同。
如果我要None
运行,a = OnlyOneTwo(2)
print(OnlyOne.created)
如何仍然是12-15 11:20:37.845 10853-10853/org.androidtown.realchangdeokgunge D/AndroidRuntime: Shutting down VM
12-15 11:20:37.855 10853-10853/org.androidtown.realchangdeokgunge W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x4166bd58)
12-15 11:20:37.855 10853-10853/org.androidtown.realchangdeokgunge E/AndroidRuntime: FATAL EXCEPTION: main
Process: org.androidtown.realchangdeokgunge, PID: 10853
java.lang.NullPointerException
at org.androidtown.realchangdeokgunge.GPSActivity.getMyLocation(GPSActivity.java:118)
at org.androidtown.realchangdeokgunge.GPSActivity.access$000(GPSActivity.java:50)
at org.androidtown.realchangdeokgunge.GPSActivity$1.onClick(GPSActivity.java:135)
at android.view.View.performClick(View.java:4457)
at android.view.View$PerformClick.run(View.java:18501)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5068)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
at dalvik.system.NativeStart.main(Native Method)
?
答案 0 :(得分:1)
我会试一试。我认为症状是由cls.created = ...
中的作业__call__
引起的。
首次创建类对象时OnlyOneTwo.created
指向 OnlyOne.created
。它们都具有相同的id
,与None
相同。
>>> id(None)
506773144
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(506773144, 506773144)
如果您首先创建OnlyOne
的实例,则会将实例分配给OnlyOne.created
(它不再指向 None
),但{{1}仍然指向OnlyOneTwo.created
- 它们仍然是相同的,所以当调用OnlyOne.created
时,条件的else子句被执行。
OnlyOneTwo
当您首先创建>>> a = OnlyOne('a')
called
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(54522152, 54522152)
>>> z = OnlyOneTwo('z')
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(54522152, 54522152)
>>> id(a)
54522152
的实例时,该实例已分配给OnlyOneTwo
,它不再指向 OnlyOneTwo.created
。 OnlyOne.created
仍然指向 OnlyOne.created
。
None
现在,当您创建>>> id(None)
506773144
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(506773144, 506773144)
>>> z = OnlyOneTwo('z')
called
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(506773144, 54837544)
>>> id(z)
54837544
的实例时,if条件为True且实例已分配给OnlyOne
OnlyOne.created
我经常发现自己正在重读Binding of Names和Resolution of Names - 同时A Word About Names and Objects和Python Scopes and Namespaces
我觉得我还没有真正解释这个机制 - 我真的不明白孩子类属性 指向 < / strong>基类属性 - 它与>>> a = OnlyOne('a')
called
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(54352752, 54837544)
>>> id(a)
54352752
不同。
也许:
重新阅读触发大脑转储的文档中Standard Type Hierarchy的自定义类部分。
我觉得我以前来过这里,甚至可能在这里。希望这次能记住它,不要再想出来了。
如果你想修复你的Singleton,如果你搜索它们有很多选项。使用元类似乎实例保存在元类中,而不是类本身。 Creating a singleton in Python,SO Q&amp; A,是一个良好的开端。