Python属性和方法
关键字:Python 属性 方法
原文:http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html
Shalabh Chaturvedi
Copyright © 2005-2009 Shalabh Chaturvedi
All Rights Reserved.
About This Book
Explains the mechanics of object attribute access for new-style Python objects:
how functions become methods
how descriptors and properties work
determining method resolution order
New-style implies Python version 2.2 and upto and including 3.x. There have been some behavioral changes during these version but all the concepts covered here are valid.
This book is part of a series:
Python Attributes and Methods [you are here]
This revision:
Discuss | Latest version | Cover page
Author: shalabh@cafepy.com
Table of Contents
List of Figures
- 2.1. The Diamond Diagram
- 2.2. A Simple Hierarchy
- 2.3. Beads on Strings - Unsolvable
- 2.4. Beads on Strings - Solved
- 2.5. Multiple Solutions
List of Examples
- 1.1. Simple attribute access
- 1.2. A function is more
- 1.3. A simple descriptor
- 1.4. Using a descriptor
- 1.5. Non-data descriptors
- 1.6. Hiding a method
- 1.7. Built-in descriptors
- 1.8. More on properties
- 2.1. Usual base call technique
- 2.2. Base call technique fails
- 2.3. Making a "Who's Next" list
- 2.4. Call next method technique
- 2.5. One super technique
- 2.6. Using super with a class method
- 2.7. Another super technique
- 3.1. Special methods work on type only
- 3.2. Forwarding special method to instance
- 3.3. Subclassing <type 'list'>
- 3.4. Using
__slots__for optimization - 3.5. Customizing creation of subclasses
Before You Begin
Some points you should note:
This book covers the new-style objects (introduced a long time ago in Python 2.2). Examples are valid for Python 2.5 and all the way to Python 3.x.
This book is not for absolute beginners. It is for people who already know Python (some Python at least), and want to know more.
You should be familiar with the different kinds of objects in Python and not be confused when you come across the term type where you expected class. You can read the first part of this series for background information -Python Types and Objects.
Happy pythoneering!
Chapter 1. New Attribute Access
The Dynamic __dict__
What is an attribute? Quite simply, an attribute is a way to get from one object to another. Apply the power of the almighty dot - objectname.attributename - and voila! you now have the handle to another object. You also have the power to create attributes, by assignment: objectname.attributename = notherobject.
Which object does an attribute access return, though? And where does the object set as an attribute end up? These questions are answered in this chapter.
Example 1.1. Simple attribute access
>>> class C(object):
... classattr = "attr on class"

...
>>> cobj = C()
>>> cobj.instattr = "attr on instance"

>>>
>>> cobj.instattr

'attr on instance'
>>> cobj.classattr

'attr on class'
>>> C.__dict__['classattr']

'attr on class'
>>> cobj.__dict__['instattr']

'attr on instance'
>>>
>>> cobj.__dict__

{'instattr': 'attr on instance'}
>>> C.__dict__

{'classattr': 'attr on class', '__module__': '__main__', '__doc__': None}
|
|
Attributes can be set on a class. |
|
|
Or even on an instance of a class. |
|
|
Both, class and instance attributes are accessible from an instance. |
|
|
Attributes really sit inside a dictionary-like |
|
|
|
Ok, I admit 'user-provided attribute' is a term I made up, but I think it is useful to understand what is going on. Note that __dict__ is itself an attribute. We didn't set this attribute ourselves, but Python provides it. Our old friends__class__ and __bases__ (none which appear to be in __dict__ either) also seem to be similar. Let's call themPython-provided attributes. Whether an attribute is Python-provided or not depends on the object in question (__bases__, for example, is Python-provided only for classes).
We, however, are more interested in user-defined attributes. These are attributes provided by the user, and they usually (but not always) end up in the __dict__ of the object on which they're set.
When accessed (for e.g. print objectname.attributename), the following objects are searched in sequence for the attribute:
The object itself (
objectname.__dict__or any Python-provided attribute ofobjectname).The object's type (
objectname.__class__.__dict__). Observe that only__dict__is searched, which means only user-provided attributes of the class. In other wordsobjectname.__bases__may not return anything even thoughobjectname.__class__.__bases__does exist.The bases of the object's class, their bases, and so on. (
__dict__of each ofobjectname.__class__.__bases__). More than one base does not confuse Python, and should not concern us at the moment. The point to note is that all bases are searched until an attribute is found.
If all this hunting around fails to find a suitably named attribute, Python raises an AttributeError. The type of the type (objectname.__class__.__class__) is never searched for attribute access on an object (objectname in the example).
The built-in dir() function returns a list of all attributes of an object. Also look at the inspect module in the standard library for more functions to inspect objects.
The above section explains the general mechanism for all objects. Even for classes (for example accessingclassname.attrname), with a slight modification: the bases of the class are searched before the class of the class (which is classname.__class__ and for most types, by the way, is <type 'type'>).
Some objects, such as built-in types and their instances (lists, tuples, etc.) do not have a __dict__. Consequently user-defined attributes cannot be set on them.
We're not done yet! This was the short version of the story. There is more to what can happen when setting and getting attributes. This is explored in the following sections.
From Function to Method
Continuing our Python experiments:
Example 1.2. A function is more
>>> class C(object):
... classattr = "attr on class"
... def f(self):
... return "function f"
...
>>> C.__dict__

{'classattr': 'attr on class', '__module__': '__main__',
'__doc__': None, 'f': <function f at 0x008F6B70>}
>>> cobj = C()
>>> cobj.classattr is C.__dict__['classattr']

True
>>> cobj.f is C.__dict__['f']

False
>>> cobj.f

<bound method C.f of <__main__.C instance at 0x008F9850>>
>>> C.__dict__['f'].__get__(cobj, C)

<bound method C.f of <__main__.C instance at 0x008F9850>>
|
|
Two innocent looking class attributes, a string 'classattr' and a function 'f'. |
|
|
Accessing the string really gets it from the class's |
|
|
Not so for the function! Why? |
|
|
Hmm, it does look like a different object. (A bound method is a callable object that calls a function ( |
|
|
Here's the spoiler - this is what Python did to create the bound method. While looking for an attribute for an instance, if Python finds an object with a |
It is only the presence of the __get__() method that transforms an ordinary function into a bound method. There is nothing really special about a function object. Anyone can put objects with a __get__() method inside the class__dict__ and get away with it. Such objects are called descriptors and have many uses.
Creating Descriptors
Any object with a __get__() method, and optionally __set__() and __delete__() methods, accepting specific parameters is said to follow the descriptor protocol. Such an object qualifies as a descriptor and can be placed inside a class's __dict__ to do something special when an attribute is retrieved, set or deleted. An empty descriptor is shown below.
Example 1.3. A simple descriptor
class Desc(object):
"A descriptor example that just demonstrates the protocol" def __get__(self, obj, cls=None):

pass
def __set__(self, obj, val):

pass
def __delete__(self, obj):

pass
|
|
Called when attribute is read (eg. |
|
|
Called when attribute is set on an instance (eg. |
|
|
Called when attribute is deleted from an instance (eg. |
What we defined above is a class that can be instantiated to create a descriptor. Let's see how we can create a descriptor, attach it to a class and put it to work.
Example 1.4. Using a descriptor
class C(object):
"A class with a single descriptor"
d = Desc()

cobj = C() x = cobj.d

cobj.d = "setting a value"

cobj.__dict__['d'] = "try to force a value"

x = cobj.d

del cobj.d

x = C.d

C.d = "setting a value on class"

|
|
Now the attribute called |
|
|
Calls |
|
|
Calls |
|
|
Sticking a value directly in the instance's |
|
|
is futile. This still calls |
|
|
Calls |
|
|
Calls |
|
|
Doesn't call anything. This replaces the descriptor with a new string object. After this, accessing |
Note that when accessed from the class itself, only the __get__() method comes in the picture, setting or deleting the attribute will actually replace or remove the descriptor.
Descriptors work only when attached to classes. Sticking a descriptor in an object that is not a class gives us nothing.
Two Kinds of Descriptors
In the previous section we used a descriptor with both __get__() and __set__() methods. Such descriptors, by the way, are called data descriptors. Descriptors with only the __get__() method are somewhat weaker than their cousins, and called non-data descriptors.
Repeating our experiment, but this time with non-data descriptors, we get:
Example 1.5. Non-data descriptors
class GetonlyDesc(object):
"Another useless descriptor" def __get__(self, obj, typ=None):
pass class C(object):
"A class with a single descriptor"
d = GetonlyDesc() cobj = C() x = cobj.d

cobj.d = "setting a value"

x = cobj.d

del cobj.d

x = C.d

C.d = "setting a value on class"

|
|
Calls |
|
|
Puts |
|
|
Surprise! This now returns |
|
|
Deletes the attribute |
|
|
These function identical to a data descriptor. |
Interestingly, not having a __set__() affects not just attribute setting, but also retrieval. What is Python thinking? If on setting, the descriptor gets fired and puts the data somewhere, then it follows that the descriptor only knows how to get it back. Why even bother with the instance's __dict__?
Data descriptors are useful for providing full control over an attribute. This is what one usually wants for attributes used to store some piece of data. For example an attribute that gets transformed and saved somewhere on setting, would usually be reverse-transformed and returned when read. When you have a data descriptor, it controls all access (both read and write) to the attribute on an instance. Of course, you could still directly go to the class and replace the descriptor, but you can't do that from an instance of the class.
Non-data descriptors, in contrast, only provide a value when an instance itself does not have a value. So setting the attribute on an instance hides the descriptor. This is particularly useful in the case of functions (which are non-data descriptors) as it allows one to hide a function defined in the class by attaching one to an instance.
Example 1.6. Hiding a method
class C(object):
def f(self):
return "f defined in class" cobj = C() cobj.f()

def another_f():
return "another f" cobj.f = another_f cobj.f()

|
|
Calls the bound method returned by |
|
|
Calls |
Attribute Search Summary
This is the long version of the attribute access story, included just for the sake of completeness.
When retrieving an attribute from an object (print objectname.attrname) Python follows these steps:
If
attrnameis a special (i.e. Python-provided) attribute forobjectname, return it.Check
objectname.__class__.__dict__forattrname. If it exists and is a data-descriptor, return the descriptor result. Search all bases ofobjectname.__class__for the same case.Check
objectname.__dict__forattrname, and return if found. Ifobjectnameis a class, search its bases too. If it is a class and a descriptor exists in it or its bases, return the descriptor result.Check
objectname.__class__.__dict__forattrname. If it exists and is a non-data descriptor, return the descriptor result. If it exists, and is not a descriptor, just return it. If it exists and is a data descriptor, we shouldn't be here because we would have returned at point 2. Search all bases ofobjectname.__class__for same case.Raise
AttributeError
Note that Python first checks for a data descriptor in the class (and its bases), then for the attribute in the object__dict__, and then for a non-data descriptor in the class (and its bases). These are points 2, 3 and 4 above.
The descriptor result above implies the result of calling the __get__() method of the descriptor with appropriate arguments. Also, checking a __dict__ for attrname means checking if __dict__["attrname"] exists.
Now, the steps Python follows when setting a user-defined attribute (objectname.attrname = something):
Check
objectname.__class__.__dict__forattrname. If it exists and is a data-descriptor, use the descriptor to set the value. Search all bases ofobjectname.__class__for the same case.Insert
somethingintoobjectname.__dict__for key"attrname".Think "Wow, this was much simpler!"
What happens when setting a Python-provided attribute depends on the attribute. Python may not even allow some attributes to be set. Deletion of attributes is very similar to setting as above.
Descriptors In The Box
Before you rush to the mall and get yourself some expensive descriptors, note that Python ships with some very useful ones that can be found by simply looking in the box.
Example 1.7. Built-in descriptors
class HidesA(object):
def get_a(self):
return self.b - 1
def set_a(self, val):
self.b = val + 1
def del_a(self):
del self.b
a = property(get_a, set_a, del_a, "docstring")

def cls_method(cls):
return "You called class %s" % cls clsMethod = classmethod(cls_method)

def stc_method():
return "Unbindable!" stcMethod = staticmethod(stc_method)

|
|
A property provides an easy way to call functions whenever an attribute is retrieved, set or deleted on the instance. When the attribute is retrieved from the class, the getter method is not called but the property object itself is returned. A docstring can also be provided which is accessible as |
|
|
A classmethod is similar to a regular method, except that is passes the class (and not the instance) as the first argument to the function. The remaining arguments are passed through as usual. It can also be called directly on the class and it behaves the same way. The first argument is named |
|
|
A staticmethod is just like a function outside the class. It is never bound, which means no matter how you access it (on the class or on an instance), it gets called with exactly the same arguments you pass. No object is inserted as the first argument. |
As we saw earlier, Python functions are descriptors too. They weren't descriptors in earlier versions of Python (as there were no descriptors at all), but now they fit nicely into a more generic mechanism.
A property is always a data-descriptor, but not all arguments are required when defining it.
Example 1.8. More on properties
class VariousProperties(object):
def get_p(self):
pass
def set_p(self, val):
pass
def del_p(self):
pass
allOk = property(get_p, set_p, del_p)

unDeletable = property(get_p, set_p)

readOnly = property(get_p)

|
|
Can be set, retrieved, or deleted. |
|
|
Attempting to delete this attribute from an instance will raise |
|
|
Attempting to set or delete this attribute from an instance will raise |
The getter and setter functions need not be defined in the class itself, any function can be used. In any case, the functions will be called with the instance as the first argument. Note that where the functions are passed to the property constructor above, they are not bound functions anyway.
Another useful observation would be to note that subclassing the class and redefining the getter (or setter) functions is not going to change the property. The property object is holding on to the actual functions provided. When kicked, it is going to say "Hey, I'm holding this function I was given, I'll just call this and return the result.", and not "Hmm, let me look up the current class for a method called 'get_a' and then use that". If that is what one wants, then defining a new descriptor would be useful. How would it work? Let's say it is initialized with a string (i.e. the name of the method to call). On activation, it does a getattr() for the method name on the class, and use the method found. Simple!
Classmethods and staticmethods are non-data descriptors, and so can be hidden if an attribute with the same name is set directly on the instance. If you are rolling your own descriptor (and not using properties), it can be made read-only by giving it a __set__() method but raising AttributeError in the method. This is how a property behaves when it does not have a setter function.
Chapter 2. Method Resolution Order
The Problem (Method Resolution Disorder)
Why do we need Method Resolution Order? Let's say:
We're happily doing OO programming and building a class hierarchy.
Our usual technique to implement the
do_your_stuff()method is to first calldo_your_stuff()on the base class, and then do our stuff.Example 2.1. Usual base call technique
class A(object):
def do_your_stuff(self):
# do stuff with self for A
return class B(A):
def do_your_stuff(self):
A.do_your_stuff(self)
# do stuff with self for B
return class C(A):
def do_your_stuff(self):
A.do_your_stuff(self)
# do stuff with self for C
returnWe subclass a new class from two classes and end up having the same superclass being accessible through two paths.
Example 2.2. Base call technique fails
class D(B,C):
def do_your_stuff(self):
B.do_your_stuff(self)
C.do_your_stuff(self)
# do stuff with self for D
returnFigure 2.1. The Diamond Diagram

Now we're stuck if we want to implement
do_your_stuff(). Using our usual technique, if we want to call bothBandC, we end up callingA.do_your_stuff()twice. And we all know it might be dangerous to haveAdo its stuff twice, when it is only supposed to be done once. The other option would leave eitherB's stuff orC's stuff not done, which is not what we want either.
There are messy solutions to this problem, and clean ones. Python, obviously, implements a clean one which is explained in the next section.
The "Who's Next" List
Let's say:
For each class, we arrange all superclasses into an ordered list without repetitions, and insert the class itself at the start of the list. We put this list in an class attribute called
next_class_listfor our use later.Example 2.3. Making a "Who's Next" list
B.next_class_list = [B,A] C.next_class_list = [C,A] D.next_class_list = [D,B,C,A]
We use a different technique to implement
do_your_stuff()for our classes.Example 2.4. Call next method technique
class B(A):
def do_your_stuff(self):
next_class = self.find_out_whos_next()
next_class.do_your_stuff(self)
# do stuff with self for B def find_out_whos_next(self):
l = self.next_class_list # l depends on the actual instance
mypos = l.index(B)
# Find this class in the list
return l[mypos+1] # Return the next oneThe interesting part is how we
find_out_whos_next(), which depends on which instance we are working with. Note that:Depending on whether we passed an instance of
Dor ofB,next_classabove will resolve to eitherCorA.We have to implement
find_out_whos_next()for each class, since it has to have the class name hardcoded in it (see
above). We cannot use self.__class__here. If we have calleddo_your_stuff()on an instance ofD, and the call is traversing up the hierarchy, thenself.__class__will beDhere.
Using this technique, each method is called only once. It appears clean, but seems to require too much work. Fortunately for us, we neither have to implement find_out_whos_next() for each class, nor set the next_class_list, as Python does both of these things.
A Super Solution
Python provides a class attribute __mro__ for each class, and a type called super. The __mro__ attribute is a tuple containing the class itself and all of its superclasses without duplicates in a predictable order. A super object is used in place of the find_out_whos_next() method.
Example 2.5. One super technique
class B(A):

def do_your_stuff(self):
super(B, self).do_your_stuff()

# do stuff with self for B
|
|
The |
If we're using a class method, we don't have an instance self to pass into the super call. Fortunately for us, superworks even with a class as the second argument. Observe that above, super uses self only to get atself.__class__.__mro__. The class can be passed directly to super as shown below.
Example 2.6. Using super with a class method
class A(object):
@classmethod

def say_hello(cls):
print 'A says hello' class B(A):
@classmethod
def say_hello(cls):
super(B, cls).say_hello()

print 'B says hello' class C(A):
@classmethod
def say_hello(cls):
super(C, cls).say_hello()
print 'C says hello' class D(B, C):
@classmethod
def say_hello(cls):
super(D, cls).say_hello()
print 'D says hello' B.say_hello()

D.say_hello()

|
|
This example is for classmethods (not instance methods). |
|
|
Note we pass |
|
|
This prints out: A says hello |
|
|
This prints out (observe each method is called only once): A says hello |
There is yet another way to use super:
Example 2.7. Another super technique
class B(A):
def do_your_stuff(self):
self.__super.do_your_stuff()
# do stuff with self for B
B._B__super = super(B)

When created with only a type, the super instance behaves like a descriptor. This means (if d is an instance of D) thatsuper(B).__get__(d) returns the same thing as super(B,d). In
above, we munge an attribute name, similar to what Python does for names starting with double underscore inside the class. So this is accessible as self.__superwithin the body of the class. If we didn't use a class specific attribute name, accessing the attribute through the instance self might return an object defined in a subclass.
While using super we typically use only one super call in one method even if the class has multiple bases. Also, it is a good programming practice to use super instead of calling methods directly on a base class.
A possible pitfall appears if do_your_stuff() accepts different arguments for C and A. This is because, if we usesuper in B to call do_your_stuff() on the next class, we don't know if it is going to be called on A or C. If this scenario is unavoidable, a case specific solution might be required.
Computing the MRO
One question as of yet unanswered is how does Python determine the __mro__ for a type? A basic idea behind the algorithm is provided in this section. This is not essential for just using super, or reading following sections, so you can jump to the next section if you want.
Python determines the precedence of types (or the order in which they should be placed in any __mro__) from two kinds of constraints specified by the user:
If
Ais a superclass ofB, thenBhas precedence overA. Or,Bshould always appear beforeAin all__mro__s (that contain both). In short let's denote this asB > A.If
Cappears beforeDin the list of bases in a class statement (eg.class Z(C,D):), thenC > D.
In addition, to avoid being ambiguous, Python adheres to the following principle:
If
E > Fin one scenario (or one__mro__), then it should be thatE > Fin all scenarios (or all__mro__s).
We can satisfy the constraints if we build the __mro__ for each new class C we introduce, such that:
All superclasses of
Cappear in theC.__mro__(plusCitself, at the start), andThe precedence of types in
C.__mro__does not conflict with the precedence of types inB.__mro__for eachBinC.__bases__.
Here the same problem is translated into a game. Consider a class hierarchy as follows:
Figure 2.2. A Simple Hierarchy

Since only single inheritance is in play, it is easy to find the __mro__ of these classes. Let's say we define a new class as class N(A,B,C). To compute the __mro__, consider a game using abacus style beads over a series of strings.
Figure 2.3. Beads on Strings - Unsolvable

Beads can move freely over the strings, but the strings cannot be cut or twisted. The strings from left to right contain beads in the order of __mro__ of each of the bases. The rightmost string contains one bead for each base, in the order the bases are specified in the class statement.
The objective is to line up beads in rows, so that each row contains beads with only one label (as done with the Obead in the diagram). Each string represents an ordering constraint, and if we can reach the goal, we would have an order that satisfies all constraints. We could then just read the labels off rows from the bottom up to get the __mro__for N.
Unfortunately, we cannot solve this problem. The last two strings have C and B in different orders. However, if we change our class definition to class N(A,C,B), then we have some hope.
Figure 2.4. Beads on Strings - Solved

We just found out that N.__mro__ is (N,A,C,B,object) (note we inserted N at the head). The reader can try out this experiment in real Python (for the unsolvable case above, Python raises an exception). Observe that we even swapped the position of two strings, keeping the strings in the same order as the bases are specified in the class statement. The usefulness of this is seen later.
Sometimes, there might be more than one solution, as shown in the figure below. Consider four classes class A(object), class B(A), class C(object) and class D(C). If a new class is defined as class E(B, D), there are multiple possible solutions that satisfy all constraints.
Figure 2.5. Multiple Solutions

Possible positions for A are shown as the little beads. The order can be kept unambiguous (more correctly,monotonic) if the following policies are followed:
Arrange strings from left to right in order of appearance of bases in the class statement.
Attempt to arrange beads in rows moving from bottom up, and left to right. What this means is that the MRO of
class E(B, D)will be set to:(E,B,A,D,C,object). This is becauseA, being left ofC, will be selected first as a candidate for the second row from bottom.
This, essentially, is the idea behind the algorithm used by Python to generate the __mro__ for any new type. The formal algorithm is formally explained elsewhere [mro-algorithm].
Chapter 3. Usage Notes
This chapter includes usage notes that do not fit in other chapters.
Special Methods
In Python, we can use methods with special name like __len__(), __str__() and __add__() to make objects convenient to use (for example, with the built-in functions len(), str() or with the '+' operator, etc.)
Example 3.1. Special methods work on type only
class C(object):
def __len__(self):

return 0 cobj = C() def mylen():
return 1 cobj.__len__ = mylen

print len(cobj)

|
|
Usually we put the special methods in a class. |
|
|
We can try to put them in the instance itself, but it doesn't work. |
|
|
This goes straight to the class (calls |
The same is true for all such methods, putting them on the instance we want to use them with does not work. If it did go to the instance then even something like str(C) (str of the class C) would go to C.__str__(), which is a method defined for an instance of C, and not C itself.
A simple technique to allow defining such methods for each instance separately is shown below.
Example 3.2. Forwarding special method to instance
class C(object):
def __len__(self):
return self._mylen()

def _mylen(self):

return 0 cobj = C() def mylen():
return 1 cobj._mylen = mylen

print len(cobj)

|
|
We call another method on the instance, |
|
|
for which we provide a default implementation in the class. |
|
|
But it can be overwritten (rather hidden) by setting on the instance. |
|
|
This now calls |
Subclassing Built-in Types
Subclassing built-in types is straightforward. Actually we have been doing it all along (whenever we subclass <type 'object'>). Some built-in types (types.FunctionType, for example) are not subclassable (not yet, at least). However, here we talk about subclassing <type 'list'>, <type 'tuple'> and other basic data types.
Example 3.3. Subclassing <type 'list'>
>>> class MyList(list):

... "A list that converts appended items to ints"
... def append(self, item):

... list.append(self, int(item))

...
>>>
>>> l = MyList()
>>> l.append(1.3)

>>> l.append(444)
>>> l
[1, 444]

>>> len(l)

2
>>> l[1] = 1.2

>>> l
[1, 1.2]
>>> l.color = 'red'

|
|
A regular class statement. |
|
|
Define the method to be overridden. In this case we will convert all items passed through |
|
|
Upcall to the base if required. |
|
|
Append a float and... |
|
|
watch it automatically become an integer. |
|
|
Otherwise, it behaves like any other list. |
|
|
This doesn't go through append. We would have to define |
|
|
We can set attributes on our instance. This is because it has a |
Basic lists do not have __dict__ (and so no user-defined attributes), but ours does. This is usually not a problem and may even be what we want. If we use a very large number of MyLists, however, we could optimize our program by telling Python not to create the __dict__ for instances of MyList.
Example 3.4. Using __slots__ for optimization
class MyList(list):
"A list subclass disallowing any user-defined attributes" __slots__ = []

ml = MyList()
ml.color = 'red' # raises exception!

class MyListWithFewAttrs(list):
"A list subclass allowing specific user-defined attributes" __slots__ = ['color']

mla = MyListWithFewAttrs()
mla.color = 'red'

mla.weight = 50 # raises exception!

|
|
The |
|
|
Setting any attribute on this raises an exception. |
|
|
|
|
|
Now, if an attribute has space reserved, it can be used. |
|
|
Otherwise, it cannot. This will raise an exception. |
The purpose and recommended use of __slots__ is for optimization. After a type is defined, its slots cannot be changed. Also, every subclass must define __slots__, otherwise its instances will end up having __dict__.
We can create a list even by instantiating it like any other type: list([1,2,3]). This means list.__init__()accepts the same argument (i.e. any iterable) and initializes a list. We can customize initialization in a subclass by redefining __init__() and upcalling __init__() on the base.
Tuples are immutable and different from lists. Once an instance is created, it cannot be changed. Note that the instance of a type already exists when __init__() is called (in fact the instance is passed as the first argument). The__new__() static method of a type is called to create an instance of the type. It is passed the type itself as the first argument, and passed through other initial arguments (similar to __init__()). We use this to customize immutable types like a tuple.
Example 3.5. Customizing creation of subclasses
class MyList(list):
def __init__(self, itr):

list.__init__(self, [int(x) for x in itr])
class MyTuple(tuple):
def __new__(typ, itr):

seq = [int(x) for x in itr]
return tuple.__new__(typ, seq)

|
|
For a list, we massage the arguments and hand them over to list.__init__(). |
|
|
For a tuple, we have to override __new__(). |
|
|
A __new__() should always return. It is supposed to return an instance of the type. |
The __new__() method is not special to immutable types, it is used for all types. It is also converted to a static method automatically by Python (by virtue of its name).
Related Documentation
[descrintro] Unifying types and classes in Python 2.2. Guido van Rossum.
[pep-252] Making Types Look More Like Classes. Guido van Rossum.
[pep-253] Subclassing Built-in Types. Guido van Rossum.
[descriptors-howto] How-To Guide for Descriptors. Raymond Hettinger.
[mro-algorithm] The Python 2.3 Method Resolution Order. Michele Simionato.
Colophon
This book was written in DocBook XML. The HTML version was produced using DocBook XSL stylesheets andxsltproc. The PDF version was produced using htmldoc. The diagrams were drawn using OmniGraffe [1]. The process was automated using Paver [2].
Python属性和方法的更多相关文章
- Python 属性与方法 概念理解
属性与方法 attribute(属性)是class(类)中的成员变量,而method(方法)则是class(类)中的function(函数). 也可以理解,属性就类变量,方法就是类函数. 类中的变量就 ...
- Python属性、方法和类管理系列之----描述符类
什么是描述符类? 根据鸭子模型理论,只要具有__get__方法的类就是描述符类. 如果一个类中具有__get__和__set__两个方法,那么就是数据描述符,. 如果一个类中只有__get__方法,那 ...
- Python属性、方法和类管理系列之----属性初探
在学习dict的时候,肯定听过dict是Python中最重要的数据类型,但是不一定知道为什么.马上你就会明白原因了. Python中从模块.到函数.到类.到元类,其实主要管理方法就是靠一个一个的字典. ...
- Python属性、方法和类管理系列之----元类
元类的介绍 请看位于下面网址的一篇文章,写的相当好. http://blog.jobbole.com/21351/ 实例补充 class Meta(type): def __new__(meta, c ...
- Python属性、方法和类管理系列之----__slots__属性
一句话说明 __slots__是用来限制实例的属性的,__slots__可以规定实例是否应该有__dict__属性:__slots__不能限制类的属性. 只有__slots__列表内的这些变量名可赋值 ...
- python 类属性与方法
Python 类属性与方法 标签(空格分隔): Python Python的访问限制 Python支持面向对象,其对属性的权限控制通过属性名来实现,如果一个属性有双下划线开头(__),该属性就无法被外 ...
- python动态获取对象的属性和方法 (转载)
首先通过一个例子来看一下本文中可能用到的对象和相关概念. #coding:utf-8 import sys def foo():pass class Cat(object): def __init__ ...
- Python中类的方法属性与方法属性的动态绑定
最近在学习python,纯粹是自己的兴趣爱好,然而并没有系统地看python编程书籍,觉得上面描述过于繁琐,在网站找了一些学习的网站,发现廖雪峰老师的网站上面的学习资源很不错,而且言简意赅,提取了一些 ...
- 我的Python学习笔记(四):动态添加属性和方法
一.动态语言与静态语言 1.1 动态语言 在运行时代码可以根据某些条件改变自身结构 可以在运行时引进新的函数.对象.甚至代码,可以删除已有的函数等其他结构上的变化 常见的动态语言:Object-C.C ...
随机推荐
- thinkphp中view页面中的volist标签转化为原生php分析(多去看源代码,你会发现不仅简单,方便你理解,还节约时间)
thinkphp中view页面中的volist标签转化为原生php分析(多去看源代码,你会发现不仅简单,方便你理解,还节约时间) 一.总结 1.标签和原生php之间的关系:标签只是为了方便你使用,标签 ...
- testng并发测试与测试并发
一.testng并发测试 通过xml文件中suit结点的parallel属性指定,如 <suite name="bundle-module-testabc" parallel ...
- 结合Wireshark捕获分组深入理解TCP/IP协议之以太网帧
摘要: 本文摘抄并整理了以太网相关理论知识,包括CSMA/CD协议机制及工作.LAN互连,详细分析了Ethernet II帧格式,最后给出Ethernet II帧实例. 一.以太网[1] 1. ...
- 15、NAND FLASH驱动程序框架
驱动可以参考At91_nand.c,这个比S3c2410.c (drivers\mtd\nand)简单多了 NAND FLASH是一个存储芯片那么: 这样的操作很合理"读地址A的数据,把数据 ...
- linux下实现监控进程网络带宽
嗯,近期都在网易游戏实习,所以貌似有段时间没有上来写点东西了... 来网易游戏实习最基本的目的事实上就是想知道在游戏公司里面工作都是些什么内容,毕竟自己曾经也没有接触过游戏公司.. 还比較的好奇.. ...
- python链表的实现,有注释
class Node(): #node实现,每个node分为两部分:一部分含有链表元素,成数据域;另一部分为指针,指向下一个 __slots__=['_item' ...
- C++学习笔记8-操作符&指针
1. 重载操作符 赋值操作符的返回类型应该与内置类型赋值运算返回的类型同样.内置类型的赋值运算返回对右操作数的引用,因此,赋值操作符也返回对同一类类型的引用.比如.Sales_item的赋值操作符能 ...
- ssion机制详解
ssion机制详解 ref:http://justsee.iteye.com/blog/1570652 虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚sess ...
- 使用Html5开发Android和iOS应用:HBuilder、Html5Plus、MUI
活动主题:五一巨献,问答有礼,105QB送给IT互联网界的劳动人民活动时间:4月30日晚上10点~5月2日晚上10点网址: http://ask.jiutianniao.com 2014年的时候,就 ...
- [Node.js] Test Node RESTful API with Mocha and Chai
In this lesson, we will use Chai's request method to test our Node application's API responses.By th ...