举一个简单的例子,取一个可以返回其属性的class 椭圆,例如面积A,周长C,长轴/短轴a/b,偏心率e等.为了得到它,显然必须提供其两个参数以获得所有其他参数,虽然作为一个特殊情况,只提供一个参数应该假设一个圆圈.三个或更多一致的参数应该产生警告但是有效,否则显然会引发异常.
所以有效Ellipses的一些例子是:
Ellipse(a=5, b=2)
Ellipse(A=3)
Ellipse(a=3, e=.1)
Ellipse(a=3, b=3, A=9*math.pi) # note the consistency
Run Code Online (Sandbox Code Playgroud)
而无效的将是
Ellipse()
Ellipse(a=3, b=3, A=7)
Run Code Online (Sandbox Code Playgroud)
因此构造函数要么包含许多=None参数,
class Ellipse(object):
def __init__(self, a=None, b=None, A=None, C=None, ...):
Run Code Online (Sandbox Code Playgroud)
或者,可能更明智,一个简单的**kwargs,可能添加提供a,b作为位置参数的选项,
class Ellipse(object):
def __init__(self, a=None, b=None, **kwargs):
kwargs.update({key: value
for key, value in (('a', a), ('b', b))
if value is not None})
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但现在实际实现,即确定提供哪些参数,哪些参数不是,并根据它们确定所有其他参数,或在需要时检查一致性.
我的第一种方法是许多人的简单而乏味的组合
if 'a' in kwargs:
a = kwargs['a'] …Run Code Online (Sandbox Code Playgroud) 我知道我们可以重载类实例的行为,例如 -
class Sample(object): pass
s = Sample()
print s
<__main__.Sample object at 0x026277D0>
print Sample
<class '__main__.Sample'>
Run Code Online (Sandbox Code Playgroud)
我们可以改变结果print s:
class Sample(object):
def __str__(self):
return "Instance of Sample"
s = Sample()
print s
Instance of Sample
Run Code Online (Sandbox Code Playgroud)
我们可以改变结果print Sample吗?
这实际上源于对SO的讨论.
精简版
def meta(name, bases, class_dict)
return type(name, bases, class_dict)
class Klass(object):
__metaclass__ = meta
Run Code Online (Sandbox Code Playgroud)
meta()在Klass执行类声明时调用.
(python内部)代码的哪一部分实际调用了meta()?
长版
声明类时,某些代码必须进行适当的属性检查,并查看类型是否有__metaclass__声明.如果存在,则必须使用众所周知的(class_name, bases, class_dict)属性对该元类执行方法调用.我不清楚哪个代码负责该调用.
我已经在CPython中进行了一些挖掘(见下文),但我真的希望能有更接近确定答案的东西.
选项1:直接调用
元类调用被硬连线到类解析中.如果是的话,有没有证据证明这一点?
选项2:它被称为 type.__new__()
type_call()拨打电话type_new()中的代码_PyType_CalculateMetaclass().这表明type()在尝试找出要返回的值时,在调用期间实际完成了元类分辨率type()
这与"类"是" 可返回对象的可调用 "的概念一致.
选项3:不同的东西
当然,我所有猜测都可能是完全错误的.
我们在聊天中提出的一些示例案例:
例1:
class Meta(type):
pass
class A:
__metaclass__ = Meta
A.__class__ == Meta
Run Code Online (Sandbox Code Playgroud)
这就是Meta.__new__()回报,所以这似乎是合法的.元类使自己成为A.__class__
例2:
class Meta(type):
def __new__(cls, class_name, bases, class_dict):
return type(class_name, bases, class_dict)
class A(object): …Run Code Online (Sandbox Code Playgroud) 我想NameError通过将所需的缺失变量注入到帧中来处理异常,然后从上一次尝试的指令继续执行.
以下伪代码应说明我的需求.
def function():
return missing_var
try:
print function()
except NameError:
frame = inspect.trace()[-1][0]
# inject missing variable
frame.f_globals["missing_var"] = ...
# continue frame execution from last attempted instruction
exec frame.f_code from frame.f_lasti
Run Code Online (Sandbox Code Playgroud)
代码在从属进程中运行,该进程由父进程控制.任务(真正的功能)写在父级中,后者使用dill传递给从站.我希望一些任务(在slave进程中运行)尝试从父进程中的外部作用域访问变量,我希望slave能够动态地向父进程请求这些变量.
ps:我不希望这种魔法在生产环境中运行.
在这个众所周知的答案中解释了Python中的元类.它提到该__metaclass__属性不会被继承.
但事实上,我在Python中尝试过:
class Meta1(type):
def __new__(cls, clsname, bases, dct):
print "Using Meta1"
return type.__new__(cls, clsname, bases, dct)
# "Using Meta1" printed
class Foo1:
__metaclass__ = Meta1
# "Using Meta1" printed
class Bar1(Foo1):
pass
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,无论是Foo和Bar使用Meta1作为元类和打印字符串预期.
但是在下面的示例中,type(...)返回的是when 而不是type.__new__(...),继承了元类:
class Meta2(type):
def __new__(cls, clsname, bases, dct):
print "Using Meta2"
return type(clsname, bases, dct)
# "Using Meta2" printed
class Foo2:
__metaclass__ = Meta2
# Nothing printed
class Bar2(Foo2):
pass
Run Code Online (Sandbox Code Playgroud)
检查 …
编辑: 我不认为这是Python中什么是元类的真实副本?,即使在长评论的结尾部分回答了我的问题。
链接的问题通常针对元类。我的问题是关于特定的元类的type。而且据我所知,阅读答案后,type无法在纯Python中实现元类。因此,我的问题不仅是关于“什么是元类?”,而且还涉及type/ object关系以及元类如何创建自身,这是通过在实现级别上“作弊”来实现的。
对于不熟悉元类概念的人来说,这两个问题似乎完全无关。
初始帖子:
我对Python 3中的object和type类有些困惑。也许有人可以消除我的困惑或提供一些其他信息。
每个类(除外object)都从称为的基类继承object。但是每个类(包括object)也是该类的type一个实例,它是自身的实例,object并且也从继承object。
是否有一个原因/设计决定,为什么object是的实例type并type从中继承object?type对象的/ class 是否也可以是对象本身?
类(type)如何成为其自身的实例?
哪一个是真正的基类object或type?
我一直认为object这将是最“基础”的类,但它似乎是的实例type,这是的实例object,是的实例type,...递归在哪里结束?
是否有可能说明object和type类之间的关系?
我查找了Python标准库文档中的object和的条目type …
让我从这开始不重复
为什么__init__如果没有args调用__new__就不会被调用.我试图精心构建了一些示例代码__new__和__init__有没有解释,我可以找到.
基本参数:
__init__方法,反过来调用一个_parse方法_parse子类中的方法super以避免Python日志记录中的问题
:为什么__init__被调用两次?无论如何,__init__应该在之后调用__new__以及为什么下面的一些样本不起作用的每个解释我似乎能够指出其他有用的情况并排除解释.
class NotMine(object):
def __init__(self, *args, **kwargs):
print "NotMine __init__"
self._parse()
def _parse(self):
print "NotMine _parse"
class ABC(NotMine):
def __new__(cls,name,*args, **kwargs):
print "-"*80
print "Entered through the front door ABC.__new__(%s,%s,*%s,**%s)"%(cls,name,args,kwargs)
if name == 'AA':
obj = super(NotMine,ABC).__new__(AA,*args,**kwargs)
print "Exiting door number 1 with an instance of: %s"%type(obj)
return obj
elif …Run Code Online (Sandbox Code Playgroud) :rtype:指定这是返回对象的类型
因此,当我obj在下面的代码片段中创建对象时,我收到来自IDE的警告cls is not callable,因为IDE期望,这cls是object类型的SomeAbstractClass,我想要SomeAbstractClass自己
IDE是对的,因为这是默认行为.但是我如何指定,我正在返回课程,而不是课程的实例?
指定type而不是SomeAbstractClass帮助,但不是解决方案,因为没有进一步的内省可用.
def class_selector(data):
"""
:rtype: SomeAbstractClass
:return: Return some class based on given parameters
"""
return get_from.get(data.name)
cls = class_selector(data)
obj = cls(data.more_data)
Run Code Online (Sandbox Code Playgroud)
同时我通过""":type: SomeAbstractClass"""在创建对象后添加来解决这个问题 ,但是这并没有取消警告并且它是脏的解决方案.
顺便说一句,谈论python 2.x.
下面,base_id它_id是一个类变量,并在所有子类之间共享.
有没有办法将它们分成每个类?
from itertools import count
class Parent(object):
base_id = 0
_id = count(0)
def __init__(self):
self.id = self.base_id + self._id.next()
class Child1(Parent):
base_id = 100
def __init__(self):
Parent.__init__(self)
print 'Child1:', self.id
class Child2(Parent):
base_id = 200
def __init__(self):
Parent.__init__(self)
print 'Child2:', self.id
c1 = Child1() # 100
c2 = Child2() # 201 <- want this to be 200
c1 = Child1() # 102 <- want this to be 101
c2 = Child2() # 203 <- …Run Code Online (Sandbox Code Playgroud) 我最近在某处读过Nonepython 中的特殊值是它自己类的单例对象,具体来说NoneType.这解释了很多,因为涉及Nonepython的大多数错误产生AttributeErrors而不是某些特殊的"NoneError"或其他东西.
由于所有的这些AttributeErrors反映了属性的NoneType缺乏,我开始用什么属性感兴趣NoneType 并如有有.
我决定研究这个NoneType并了解更多相关信息.我总是发现学习新语言功能的最佳方法是使用它,所以我尝试NoneType在IDLE中实例化:
>>> n = NoneType()
Run Code Online (Sandbox Code Playgroud)
这产生了一个错误:
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
n = NoneType()
NameError: name 'NoneType' is not defined
Run Code Online (Sandbox Code Playgroud)
困惑,我检查None了我是否得到了正确的类型名称.果然,
>>> type(None)
<class 'NoneType'>
Run Code Online (Sandbox Code Playgroud)
现在非常困惑,我做了一个快速的谷歌搜索.这表明由于某些原因,在Python 3中以某种方式删除了NoneType.
好吧,不过,哈哈!我可以通过None在变量中存储类型来解决这个问题,因为类是python中的对象.这似乎有效:
>>> NoneType = type(None)
>>> n = NoneType()
Run Code Online (Sandbox Code Playgroud)
当我打印n时,我得到的是我所期待的:
>>> print(n)
None
Run Code Online (Sandbox Code Playgroud)
但后来发生这种情况:
>>> n is None …Run Code Online (Sandbox Code Playgroud) python ×10
python-3.x ×3
class ×2
metaclass ×2
oop ×2
python-2.7 ×2
arguments ×1
docstring ×1
genshi ×1
inheritance ×1
nonetype ×1
object ×1
pycharm ×1
singleton ×1