I am trying to programmatically access all fields of some Python3 object using a combination of dir and getattr. Pseudocode below:
x = some_object()
for i in dir(x):
print(str(getattr(x, i)))
However, the Python docs (https://docs.python.org/2/library/functions.html#dir) on dir is VERY vague:
Note Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases.
My questions:
1) Is there a way to achieve the above more rigorously than using dir?
2) What does "interesting set of names" mean and how is it computed?
Kind of?
With custom __getattr__ and __getattribute__ implementations, an object can dynamically respond to requests for any attribute. You could have an object that has every attribute, or an object that randomly has or doesn't have the foo attribute with 50% probability every time you look at it. If you know how an object's __getattr__ and __getattribute__ work, and you know that they respond to a finite list of attribute names, then you can write your own version of dir that lists everything, but even handling the basic built-in types requires an uncomfortable number of cases. You can see the dir implementation in Objects/object.c.
The documentation gives an explanation of which attributes are considered interesting:
If the object is a module object, the list contains the names of the module’s attributes.
If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.
Otherwise, the list contains the object’s attributes’ names, the names of its class’s attributes, and recursively of the attributes of its class’s base classes.
By "attributes", this documentation is mostly referring to the keys of its __dict__. There's also some handling for __members__ and __methods__; those are deprecated, and I don't remember what they do.
Related
onvif python will create base variables from WSDL but not the optional elements. How do I add the optional variables to the existing definition?
as in a = create(sometype)
This defines the elements a.b and a.c.
I need to add elements a.c.d, a.c.e.g and a.c.e.h.
The short answer: It depends on what the existing variable is.
The longer answer: Since the existing variable is defined by a third party library with little to no visibility, run the code under a debugger that will tell you what the existing variable is, e.g, list, dict, etc. From that information look in the python documentation if you are not familiar with that type of variable.
I have a hierarchy of data that i would like to build using classes instead of hard coding it in. The structure is like so:
Unit (has name, abbreviation, subsystems[5 different types of subsystems])
Subsystem ( has type, block diagram(photo), ParameterModel[20 different sets of parameterModels])
ParameterModel (30 or so parameters that will have [parameter name, value, units, and model index])
I'm not sure how to do this using classes but what i have made kindof work so far is creating nested dictionaries.
{'Unit':{'Unit1':{'Subsystem':{'Generator':{Parameter:{'Name': param1, 'Value':1, 'Units': 'seconds'}
like this but with 10-15 units and 5-6 subsystems and 30 or so parameters per subsystem. I know using dictionaries is not the best way to go about it but i cannot figure out the class sharing structure or where to start on building the class structure.
I want to be able to create, read, update and delete, parameters in a tkinter gui that i have built as well as export/import these system parameters and do calculations on them. I can handle the calculations and the import export but i need to create classes that will build out this structure and be able to reference each individual unit/subsystem/parameter/value/etc
I know thats alot but any advice? ive been looking into the factory and abstract factory patterns in hope to try and figure out how to create the code structure but to no avail. I have experience with matlab, visual basic, c++, and various arduio projects so i know most basic programming but this inheritance class structure is something i cannot figure out how to do in an abstract way without hardcoding each parameter with giant names like Unit1_Generator_parameterName_parameter = ____ and i really dont want to do that.
Thanks,
-A
EDIT: Here is one way I've done the implementation using a dictionary but i would like to do this using a class that can take a list and make a bunch of empty attributes and have those be editable/callable generally like setParamValue(unit, susystem, param) where i can pass the unit the subsystem and then the parameter such as 'Td' and then be able to change the value of the key,value pair within this hierarchy.
def create_keys(list):
dict = {key: None for key in list}
return dict
unit_list = ['FL','ES','NN','SF','CC','HD','ND','TH'] #unit abbreviation
sub_list = ['Gen','Gov','Exc','PSS','Rel','BlkD']
params_GENROU = ["T'do","T''do","T'qo","T''qo",'H','D','Xd','Xq',"Xd'","Xq'","X''d=X''q",'Xl','S(1.0)','S(1.2)','Ra'] #parameter names
dict = create_keys(unit_list)
for key in dict:
dict[key] = create_keys(sub_list)
dict[key]['Gen'] = create_keys(params_GENROU)
and inside each dict[unit][Gen][ParamNames] there should be a dict containing Value, units(seconds,degrees,etc), description and CON(#basically in index for another program we use)
MyClass is derived from "list": MyClass(list)
I would like to document MyClass nicely.
Unfortunately, when trying help(MyClass),
I get my own documentation, but I also get a lot of stuff about "list".
Would there be a simple way to control that?
I read something about metaclasses, but I was unable to do something.
Thanks for your suggestions,
Michel
Well, that is what help does. It introspects into your class and show the name and the associated __doc__ for each callable attribute in the class, and that is not customizable.
Attributes of the superclass are considered attributes of the class, and are reached in the introspection Python's help do.
Metaclasses could even be used to customize the output one gets when he does "dir" on your class - but they do not change the output of the help text. To change "dir" output, create a metaclass implementing a __dir__ method, and return a list of what you want visible as dir's output.
class M(type):
def __dir__(self):
return [] # blank dir contents
class MyList(list, metaclass=M):
...
On the other hand, the help contents displayed for list attributes are not that verbose, and can actually be helpful - if you override any methods to do something different than described, the incorrect text won't show anyway. So you might just live with it.
Another tip is that instead of subclassing list you might prefer to subclass collections.abc.MutableSequence instead, and use an inner agregated (normal) list to keep your data: that will require you to implement a lot less methods to have your class working properly as a sequence and is preferable in most cases to subclass list. That won't change help's verbosity though.
Just wondering that when we create a namedtuple object, why we always make the new object name (on the left) as the same as the namedtuple object name (on the right)?
I have tried an experiment to make them different names as below and then add in fields data using different objects name as below:
Running Code Example
>>> latlong = namedtuple('good', 'lat long')
>>> latlong(1, 2)
good(lat=1, long=2)
>>> good(1,2)
latlong(lat=1, long=2)
So when I add fields using latlong, it returns the good(), when I use good, it return latlong. Why they return different name each time? shouldn't them always return the the original object name which is good?
Thank You!
Erik
The name passed as first parameter is the one that gets stored inside the named tuple, as its __name__ attribute - and is used when you call repr on such a tuple. (You, or, in this case, the interactive interpreter - which makes a repr call to get you what you s printed).
The name you assign the namedtuple to - that is, the name on the left side of = is just any name you choose to use in your code - like you can name any other Python object.
You can even call a single namedtuple class a lot of names, by simply doing:
N = Name = NameAndAddress = namedtuple("NameAndAddress", "name address")
You can use the same object by using any of the assigned names. Or you can store a lot of namedtuples in a list, and give no explict name to any of them - just like any other object, what variable name holds a reference to an object makes no difference.
That is a bit unfortunate, because for better readability, we like to have the namedtuple "internal" name to be the same we use to reference it. Python, has no way of cleanly creating such an assignment - unless it is made inside a class body. In other words: there is no mechanism in the language that can make the expression on the right side of = to know which name it is being assigned to (on the left side of =) - so namedtuple signature requires you to explicitly type its name as a string. But despite that, there are no mechanisms or checks to verify if assigned and internal name are the same.
Just as a side comment: if you are assigning names inside a class body, there are mechanisms in Python that allow you to "tell" the assigned object its name (which will be a class attribute). Up to Python 3.5, you have to do that on the class's metaclass - or in a class decorator. In Python 3.6, the assigned object may be itself a descriptor, whose class implements a special method named __set_name__. If so, that method is called at class instantiation and passed the class object and the attribute name - the code in the method can then set the name in the instance.
(All in ActivePython 3.1.2)
I tried to change the class (rather than instance) attributes. The __dict__ of the metaclass seemed like the perfect solution. But when I tried to modify, I got:
TypeError: 'dict_proxy' object does
not support item assignment
Why, and what can I do about it?
EDIT
I'm adding attributes inside the class definition.
setattr doesn't work because the class is not yet built, and hence I can't refer to it yet (or at least I don't know how).
The traditional assignment doesn't work because I'm adding a large number of attributes, whose names are determined by a certain rule (so I can't just type them out).
In other words, suppose I want class A to have attributes A.a001 through A.a999; and all of them have to be defined before it's fully built (since otherwise SQLAlchemy won't instrument it properly).
Note also that I made a typo in the original title: it's __dict__ of a regular class, not a metaclass, that I wanted to modify.
The creation of a large number of attributes following some rule smells like something is seriously wrong. I'd go back and see if there isn't a better way of doing that.
Having said there here is "Evil Code" (but it'll work, I think)
class A:
locals()['alpha'] = 1
print A.alpha
This works because while the class is being defined there is a dictionary that tracks the local variables you are definining. These local variables eventually become the class attributes. Be careful with locals as it won't necessarily act "correctly." You aren't really supposed to be modifying locals, but it does seem to work when I tried it.
Instead of using the declarative syntax, build the table seperately and then use mapper on it. see http://www.sqlalchemy.org/docs/05/ormtutorial.html# I think there is just no good way to add computed attributes to class while defining it.
Alternatively, I don't know whether this will work but:
class A(object):
pass
A.all_my_attributes = values
class B(declarative_base, A):
pass
might possibly work.
I'm not too familiar with how 3 treats dict but you might be able to circumvent this problem by simply inheriting the dictionary class like so:
class A(dict):
def __init__(self,dict_of_args):
self['key'] = 'myvalue'
self.update(dict_of_args)
# whatever else you need to do goes here...
A() can be referenced like so:
d = {1:2,3:4}
obj = A(mydict)
print obj['test'],obj[3] # this will print myvalue and 4
Hope this helps.