python inheritance and __init__ functions
I came across the folloqing type of code when 开发者_JAVA百科looking for some pyQt examples :
class DisplayPage(QWizardPage):
def __init__(self, *args):
apply(QWizardPage.__init__, (self, ) + args)
What does *args mean ?
What is the purpose of using apply for this type of code ?*args
means that __init__
takes any number of positional arguments, all of which will be stored in the list args
. For more on that, see What does *args and **kwargs mean?
This piece of code uses the deprecated apply
function. Nowadays you would write this in one of three ways:
QWizardPage.__init__(self, *args)
super(DisplayPage, self).__init__(*args)
super().__init__(*args)
The first line is a literal translation of what apply
does (don't use it in this case, unless QWizardPage
is not a new-style class). The second uses super
as defined in PEP 367. The third uses super
as defined in PEP 3135 (works only in Python 3.x).
DisplayPage
inherits from QWizardPage
. Its constructor accepts a variable amount of arguments (which is what *args means), and passes them all to the constructor of its parent, QWizardPage
It's better to say:
super(DisplayPage, self).__init__(*args)
"Variable length argument lists": http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
Basically, it's just saying, take all the arguments that were passed to DisplayPage's __init__ method and pass them to QWizardPage's __init__ method.
In a parameter list (definition of a function) *args is Python's way of representing "variable arguments" (called "varargs" in C and C like languages). In an argument list (a call to a function) *args has the complementary meaning ... it "applies" the function to the value of the variable as if they'd been unpacked and "pasted" into the function's call.
This distinction between "parameters" and "arguments" is one that's often not elucidated. A parameter is a slot into which arguments are placed. Arguments are supplied to a function call. Parameters are the names by which arguments can be referred from within the scope of the function.
So if I define a function:
def foo(x, *a):
print "First arg: ", x
print "Other args: ", ' '.join([str(x) for x in a])
I can call it thus:
foo(1, 2, 3, 4)
... and my code will see 1 as "x" (the argument is an object reference to the integer 1, bound to the parameter named "x") and the list [2,3,4] as a (the argument will be an object reference to a three item list and bound to the function's parameter named "a").
If I bind the following tuple:
bar = (1, 2, 3, 4)
... and call foo()
thus:
foo(*bar)
... it will be a call that's identical to my previous example. "bar" will be unpacked, and passed to foo()
as a sequence of 4 arguments. This particular function would bind 1 to the first parameter and pack any number of other arguments into the a parameter. However I could call some other function:
geewhiz(*bar)
... and it would be passed four arguments just as I described for foo()
. (If geewhiz()
was written to take only 3 arguments then Python will raise a TypeError for calling a function with the wrong number of arguments ... exactly as it would if you called geewhiz(1,2,3,4)
.
In general Python's support for defining functions taking defaulted arguments, variable numbers of arguments, and keyword arguments is more flexible than any other scripting language I've ever seen. However all that power and flexibility can be a bit confusing.
In Python3 they've also added some wrinkles to tuple packing assignments. Tuple packing assignments look like:
a, b = 1, 2
... and also show up frequently in code like:
for key, val in my_dict.items():
...
Each of the items is being returned by the .items()
method as a tuple, and being packed into the key, val tuple. (Tuples in Python don't require enclosing parentheses. The , is the tuple-token).
Now in Python3 it's possible to do something like this:
a, *b = 1, 2, 3, 4
... which, as you might guess, binds the first element to "a" and the rest are packed into another tuple which is bound to "b."
While this really isn't related to *args in function parameter lists I mention it because they are conceptually and syntactically similar.
精彩评论