self.__dict__ tricks

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Fri Oct 30 00:23:03 EDT 2009


On Thu, 29 Oct 2009 21:16:37 -0500, Tim Johnson wrote:

> This is not a request for help but a request for comments: Consider the
> following code and note that 1)The initializer uses the dictionary style
> of arguments 2)The check loop executes before all of the class variables
>   are declared

Could you explain what problem you are trying to solve?


> class formLoader():

Idiomatic Python is to use CamelCase for classes.


> 	def __init__(self,**kw):
> 		self.fileName = None
> 		self.record = None
> 		self.string = None
> 		## Uncomment below to see that only fileName, record 
>               ## and string are recorded by __dict__
> 		#std.debug("self.__dict__",self.__dict__)
>               for k in kw.keys():

In recent versions of Python, this is best written as

for k in kw:

> 			if k in self.__dict__:
> 				self.__dict__[k] = kw[k]

Is your intention to ensure that the only keyword arguments allowed are 
fileName, record and string?

Perhaps the easiest way to do that is:

for k in kw:
    if k not in ('filename', 'record', 'string'):
        raise Exception()  # whatever...
    setattr(self, k) = kw[k]



> 			else:
> 				raise AttributeError(

In my opinion, AttributeError is not appropriate here. Passing an invalid 
parameter shouldn't raise the same error as failing an attribute look-up. 
That's misleading and confusing.


>                               "%s is not a class member. Use one of ('%
>                               s')" % (repr(k),"', '".join
>                               (self.__dict__.keys())))

[Aside: eight space tabs are *WAY* too big for Usenet and email. You 
should use four spaces, or even two, when posting here.]

It is idiomatic Python to use "instance attributes" to refer to 
attributes attached to instances, and "class attributes" to refer to 
those attached to classes. Talking about "class members" will confuse 
Python developers who aren't also familiar with Java or C++. (I know it 
confuses *me* -- are class members shared by all instances in a class, as 
the name implies, or are they individual to the instance, as your code 
implies?)

I also should point out that your trick will fail if you are using 
__slots__.



> 		self.tokens = 
["form","input","textarea","select","option","form"]
> 		self.inputTypes =
> 		["button","checkbox","file","hidden","image","password",
> 		                   "radio","reset","submit","text"]
> 		self.inputValTypes = ["file","hidden","password","text"] 
> self.colnames
> 		= []      ## case-insensitive column names 
> self.formIndexes = []   ##
> 		Index forms in outer list


Is any of that relevant to the trick you are asking for comments for? If 
not, why is it here?


> I'd welcome comments - such as any other applications.

Personally, I don't like it. The method signature makes it impossible to 
tell what arguments are excepted, and it forces me to use keywords even 
if I'd prefer to use positional arguments. I prefer to let the 
interpreter check the arguments for me:


class FormLoader():
    def __init__(self, fileName=None, record=None, string=None):
        self.fileName = fileName
        self.record = record
        self.string = string

That's all it takes, and you get the benefit of a method signature that 
makes it obvious what arguments it takes.



-- 
Steven



More information about the Python-list mailing list