转自:https://pyzh./en/latest/python-questions-on-stackoverflow.html
Contents 8.1. 不能直接给对象设置属性?>>> obj = object()
>>> obj.name = "whatever"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'name'
但是为什么这样就可以呢: >>> class Object(object):pass
...
>>> Obj = Object()
>>> Obj.name = "whatever"
>>> Obj.name
'whatever'
>>>
答: 现在你给第二个代码块中的Object加上属性 >>> class Object(object):
... __slots__ = {}
...
>>> Obj = Object()
>>> Obj.name = "whatever"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Object' object has no attribute 'name'
会发现抛出了同样的异常。 拥有 对于拥有 >>> class Object(object):
... __slots__ = {"a","b"}
...
>>> Obj = Object()
>>> Obj.a = 1
>>> Obj.a
1
>>> Obj.c = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Object' object has no attribute 'c'
详细见 Python-slots-doc 8.2. 如何打印一个对象的所有属性和值的对原问题: http:///questions/1251692/how-to-enumerate-an-objects-properties-in-python 答: for property, value in vars(theObject).iteritems():
print property, ": ", value
这个做法其实就是 另一个做法: >>> import inspect
>>> for attr, value in inspect.getmembers(obj):
... print attr, value
两者不同的是, 8.3. 类的__dict__无法更新?>>> class O(object):pass
...
>>> O.__dict__["a"] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'dictproxy' object does not support item assignment
答: 是的, class的 >>> class O(object):pass
...
>>> O.__dict__
<dictproxy object at 0xb76d8ac4>
>>> O.__dict__.items()
[('__dict__', <attribute '__dict__' of 'O' objects>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'O' objects>), ('__doc__', None)]
>>> O.func = lambda: 0
>>> O.__dict__.items()
[('__dict__', <attribute '__dict__' of 'O' objects>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'O' objects>), ('__doc__', None), ('func', <function <lambda> at 0xb76de224>)]
>>> O.func
<unbound method O.<lambda>>
可以看到 那我们怎么给类设置属性呢? 用 >>> setattr(O, "a", 1)
>>> O.a
1
8.4. unbound method和bound method>>> class C(object):
... def foo(self):
... pass
...
>>> C.foo
<unbound method C.foo>
>>> C().foo
<bound method C.foo of <__main__.C object at 0xb76ddcac>>
>>>
为什么 答:这是问题 http:///questions/114214/class-method-differences-in-python-bound-unbound-and-static 来自Armin Ronacher(Flask 作者)的回答: 如果你明白python中描述器(descriptor)是怎么实现的, 方法(method) 是很容易理解的。 上例代码中可以看到,如果你用类 >>> C.__dict__['foo'].__get__(None, C)
<unbound method C.foo>
这是因为方法 >>> c = C()
>>> C.__dict__['foo'].__get__(c, C)
<bound method C.foo of <__main__.C object at 0xb76ddd8c>>
只是那个 现在我们来讨论,为什么Python要这么设计? 其实,所谓 当你不想让类把一个函数作为一个方法,可以使用装饰器 >>> class C(object):
... @staticmethod
... def foo():
... pass
...
>>> C.foo
<function foo at 0xb76d056c>
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0xb76d056c>
8.5. 那么,function,bound method 和 unbound method 的区别是什么?一个函数(function)是由 当一个函数(function)定义在了class语句的块中(或者由 所以, 8.6. 什么是metaclass这是stackoverflow投票很高的问题: http:///questions/100003/what-is-a-metaclass-in-python 回答: (最高得分的答案) 8.6.1. 什么叫做元类Metaclass是创建class的东西。 一个class是用来创建对象的是不是? 但是我们知道,Python中的类也是对象。 Metaclass就是用来创建类这些对象的,它们是类的类,你可以形象化地理解为: MyClass = MetaClass()
MyObject = MyClass()
你知道, MyClass = type('MyClass', (), {})
这是因为 现在你是不是有疑问了,为什么 我猜,大概是因为和 你可以检查下对象的 >>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo():pass
...
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
...
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
>>>
那么, >>> a = 1
>>> a.__class__.__class__
<type 'type'>
>>> name = 'bob'
>>> name.__class__.__class__
<type 'type'>
所以,元类是用来创建类的。 你可以叫元类为 类工厂
8.6.2. __metaclass__ 属性你可以在写一个类的时候加上这个属性 class Foo(object):
__metaclass__ = something...
[...]
这样的话,Python就会用这个元类(上例中为 我们首先写的是 因为Python这么做的:查找它有没有 ``__metaclass__`` 属性,有的话,用指定的类来创建 ``Foo`` ,否则(也就是一般情形下),使用 ``type`` 来创建 最好还是记住上面那句话 :) 当你这么写的时候: class Foo(Bar):
pass
Python会这么做:
现在一个问题,我们可以给 答案当然是,一个可以创建类的东西。 那么,什么才能创建一个类呢? 8.6.3. 普通的元类设计元类的主要目的就是允许我们在类创建的时候动态的修改它,这经常用在API的设计上。 让我们举一个很纯的例子,比如你想要让一个模块中的所有类都共享一些属性,有很多办法可以做到,其中一个就是 在模块中定义一个 这样,模块中所有的类都会被 幸运的是 , 所以,我们这么做,用一个函数来作为metaclass: # the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attr):
"""
Return a class object, with the list of its attribute turned
into uppercase.
"""
# pick up any attribute that doesn't start with '__'
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
# turn them into uppercase
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
# let `type` do the class creation
return type(future_class_name, future_class_parents, uppercase_attr)
__metaclass__ = upper_attr # this will affect all classes in the module
class Foo(): # global __metaclass__ won't work with "object" though
# but we can define __metaclass__ here instead to affect only this class
# and this will work with "object" children
bar = 'bip'
print hasattr(Foo, 'bar')
# Out: False
print hasattr(Foo, 'BAR')
# Out: True
f = Foo()
print f.BAR
# Out: 'bip'
现在我们用一个类来作为一个metaclass: # remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
# __new__ is the method called before __init__
# it's the method that creates the object and returns it
# while __init__ just initializes the object passed as parameter
# you rarely use __new__, except when you want to control how the object
# is created.
# here the created object is the class, and we want to customize it
# so we override __new__
# you can do some stuff in __init__ too if you wish
# some advanced use involves overriding __call__ as well, but we won't
# see this
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attr):
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return type(future_class_name, future_class_parents, uppercase_attr)
但这样并不是很 OOP , 我们可以直接调用 class UpperAttrMetaclass(type):
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attr):
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
# reuse the type.__new__ method
# this is basic OOP, nothing magic in there
return type.__new__(upperattr_metaclass, future_class_name,
future_class_parents, uppercase_attr)
你可能注意到了参数 当然,可以这么写,我上面的例子命名不那么好:) class UpperAttrMetaclass(type):
def __new__(cls, name, bases, dct):
attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return type.__new__(cls, name, bases, uppercase_attr)
我们可以使用 class UpperAttrMetaclass(type):
def __new__(cls, name, bases, dct):
attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
元类是个简单的魔术,只要:
8.6.4. 那么你为什么用类来作为metaclass而不是函数既然 几个原因:
8.6.5. 应用场景一个典型例子,Django ORM (译者注,peewee也用metaclass): class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
但是你这么做: guy = Person(name='bob', age='35')
print guy.age
并不返回一个 8.7. 为什么Python没有unzip函数众所周知, >>> a, b = [1, 2, 3], [4, 5, 6]
>>> c = zip(a, b)
>>> c
[(1, 4), (2, 5), (3, 6)]
那么为什么没有这样的 答: Python中有个很神奇的操作符 >>> zip(*c)
[(1, 2, 3), (4, 5, 6)]
8.8. Python中的新式类和老式类无论你怎么叫吧, 英文来说是 问题链接: http:///questions/54867/old-style-and-new-style-classes-in-python 新式类是继承自 class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
否则是老式类: class OldStyleClass():
pass
为什么引入新式类? > The major motivation for introducing new-style classes is to provide a unified object model with a full meta-model. Python为了提供一个更完整的元模型。(好吧,译者也不大明白,不过我知道Python中很神奇的描述器只能在新式类里用) |
|
来自: legionDataLib > 《python》