RPi.GPIO-0.7.0 - a few questions about how it adds the PWM class

Hello all,

I'm trying to make a few changes to the PWM module of RPi.GPIO 0.7.0, and have a couple of questions:

1) Inside "PyMODINIT_FUNC PyInit__GPIO(void)" :

// Add PWM class if (PWM_init_PWMType() == NULL) ... Py_INCREF(&PWMType); PyModule_AddObject(module, "PWM", (PyObject*)&PWMType);

Is there any reason (technical or otherwise) why the last two lines are not part of the "PWM_init_PWMType()" function just above it ? Somehow I regard that function as the initialisator of the PWM class.

2) Inside "PyTypeObject *PWM_init_PWMType(void)":

PWMType.tp_new = PyType_GenericNew;

Is there a (technical or otherwise) reason to why the "PyTypeObject PWMType ={...}" structure (just above the call) does not not just contain "PyType_GenericNew" as the relevant element ?

Yes, I could just make the changes and do a few tests if the result will still work (I have the feeling it will), but I can't test everything and perhaps there are some design/readability considerations involved too. Hence the post. :-)

Regards, Rudy Wieser

Reply to
R.Wieser
Loading thread data ...

On Mon, 2 Dec 2019 13:27:12 +0100, "R.Wieser" declaimed the following:

I'm not going to crawl through the code and Python embedding/extension manuals... But I will comment that, in Python, instantiating a class object invokes two functions

__new__() __init__()

The first is responsible for allocating the space for the object (and possibly setting up special conditions), the second is responsible for initializing the allocated object.

My suspicion is that the two functions you mention are C-level equivalents of new and init (though with confusing names). The "if(...NULL)" confirms that the object space was created, then the initialization takes place.

--
	Wulfraed                 Dennis Lee Bieber         AF6VN 
	wlfraed@ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/
Reply to
Dennis Lee Bieber

PWM_init_PWMType sets up the type (someting that doesn?t need to know about any module it may end up in), PyModule_AddObject gives the type a name in a module. They?re logically quite separate operations.

There?s no technical reason. The idiom and the associated comment is widespread so I expect that whatever material the author learn the API from had it.

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

Dennis,

...

Hmmm... Those names do not make it easier for me to keep the possibility-to-instanciate and the actual instanciation initialisations apart I'm afraid.

As far as I can tell the functions I referred to are related to the first (the contents of the table (mentioned it the second part) are used at actual instanciation).

But .... as a newbie in this regard I could easily be wrong there. :-|

Regards, Rudy Wieser

Reply to
R.Wieser

Richard,

True. But somehow I have the strong urge to place both in a single function, and place it inside the PWM api sourcefile, py_pwm.c. The reason for that ? The PyModule_AddObject() function call gets two arguments, "PWM" and PWMType, which the main module, py_gpio.c, doesn't need to know anything about and should correlate with other data in the py_pwm.c file. In short, it looks cleaner to me that way.

I thought so too, but have started to doubt myself :

As far as I can (now) tell, the "PWMType.tp_new = PyType_GenericNew;" line creates a single instance and stores it, which than is referenced in all further access thru the "tp_new" field - instead of creating a new instance of it every time that that field is referenced, which is what I think would happen if the PyType_GenericNew is placed in the table itself. Does that make any sense ?

:-) That is what I assumed at first..

Regards, Rudy Wieser

Reply to
R.Wieser

You?re welcome to your opinion and your urges, but most programmers would see your version as wrong due to its mixing of separate concerns. I would reject it in a PR.

It makes no sense at all. Both approaches behave the same, ending up with the tp_new member set to PyType_GenericNew.

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

Richard,

Which is exactly what I see in the current way its done ... :-\

But yes, that "what is the custom?" is the second part of my question.

Thank you for confirming it.

Regards, Rudy Wieser

Reply to
R.Wieser

Richard,

To clarify:

That sounds quite logical.

That commands last argument reaches into the PWM module, which goes against what you mentioned above, and which is what I tried to refer to: The main module should also not need to know anything about the PWM one, but for how to call its class initialisator - which, I could imagine, might have a strictly defined name.

But as I have no reason (yet) to go against conventions I've choosen to slightly alter the main modules PWM modules initializing code:

// Add PWM class if (( pwmtype = PWM_init_PWMType()) == NULL) ... Py_INCREF(pwmtype); PyModule_AddObject(module, "PWM", (PyObject*)pwmtype);

This way the main module also doesn't know anything about the PWM modules internal data (als have removed the PWMType declaration from the PWM modules header file)

Any objections or other remarks ?

Regards, Rudy Wieser

Reply to
R.Wieser

The relevant module is RPi._GPIO. That?s what PyInit__GPIO is setting up. PyModule_AddObject gives the type defined in C by PWMType the name ?PWM? in that module. If you don?t believe me then consult the Python C API documentation. RPi._GPIO only ?knows? about its own module namespace, it doesn?t know about the internals of PWMType, so it seems to me that your preferences about who knows what are already met.

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

On Tue, 3 Dec 2019 08:01:13 +0100, "R.Wieser" declaimed the following:

Neither... cf:

formatting link
(and related) """ newfunc PyTypeObject.tp_new

An optional pointer to an instance creation function. """ """ PyObject* PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject

*kwds) Return value: New reference.

Generic handler for the tp_new slot of a type object. Create a new instance using the type?s tp_alloc slot. """

It appears to be saving "genericnew" AS the function to be used later when the instance is actually created. Somewhere (possibly in the C extension API itself) PWMType.tp_new needs to be called (with arguments) to actually make the object.

--
	Wulfraed                 Dennis Lee Bieber         AF6VN 
	wlfraed@ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/
Reply to
Dennis Lee Bieber

Richard,

That is not the part I have been talking about.

Neither is that

You're playing games, implicitily declaring the PWMType object itself as not being internal to the PWM module/sourcefile. I'm afraid that that doesn't quite work for me.

Thanks for the respons though.

Regards, Rudy Wieser

Reply to
R.Wieser

Dennis,

That part I understood (from the fields name).

My doubt was/is if the current way its done would perhaps result in a (sort of) singleton, and moving the "PyType_GenericNew" reference into the table itself would possibly cause multiple instances to be created.

Regards, Rudy Wieser

Reply to
R.Wieser

I?ve no idea what you think the game is. I?ve been assuming throughout that ?module? meant a Python module, since we?ve been talking about a Python module, rather than a C source file. If you want to use one word to mean two quite different things, without even clarifying what you mean, then I don?t think you get to tell other people that they are playing games when they don?t realise you?re being ambiguous.

Based on your last code fragment it looks like all you?re now arguing about is what name the type object should be referred to by when adding it to the module, rather than where the PyModule_AddObject call is. That falls into the ?don?t care? camp for me (which is why I didn?t respond to that bit).

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

Both strategies still have the same behavior. The choice of assignment vs initialisation does not make any difference here. It certainly isn?t going to cause the function to be called different numbers of times at some point in the future; if you think that it is then you need to revisit your mental model of what is going on here.

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

Richard,

Are you sure ?

1) The "PWMType.tp_new = PyType_GenericNew;" inside the "PWM_init_PWMType" function is called exactly /once/ when the GPIO module is loaded..

2)AFAIK the "tp_new" function is called /every time/ you instanciate the PWM class on a selected pin.

So yes, AFAIKS there are different call numbers.

That means that in the origional code I see a single PyType_GenericNew instance being created before any PWM class instanciation is done and (thus) shared between all PWM class instanciations. (with the "tp_new" call just incrementing the reference count)

Moving the "PyType_GenericNew" into the table means that every time a PWM class is instanciated (and its "tp_new" member is called) a new PyType_GenericNew is instanciated too.

I did. And the above is, after careful consideration, what I now have.

If you know where my above "mental model" goes wrong than please do tell, as I'm now in a state of confusion: my assumption/knowledge of what is going on there does not stroke with your assurance that that is not what happens - and I have no idea why.

Regards, Rudy Wieser

Reply to
R.Wieser

No function is called in that line.

Yes. tp_new, and therefore PyType_GenericNew, are called precisely as many times as you create a PWM instance. No more, no less.

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

Richard,

Re-read please. I did not say it was a function that got called, I said that its called INSIDE a function - which name I only mentioned so you could easily find it back.

Am I speaking some foreign language perhaps ? I really thought that my English/American wasn't /that/ bad. 'Cause no matter how I say it you do not seem to understand what I'm trying to explain (you just repeat the same phrase over-and-over again) :-(

According to me line "PWMType.tp_new = PyType_GenericNew;" creates a single instance, and than (one of the methods of) that instance is called thru accessing the tables "tp_new" field

But if-and-when you put the "PyType_GenericNew" into the table itself you will, as far as I can tell, create a new instance every time (yes ? no?).

Thats a BIG difference. Care to explain how that /doesn't/ happen ?

In short, the ammount of calls does not interest me in the slightest. What /does/ is the AMMOUNT OF INSTANCES that either of the described methods will result in, preferrably accompanied by some explanation pointing out where my train of thoughts goes amiss.

Regards, Rudy Wieser.

Reply to
R.Wieser

Richard,

To put it simpler:

var = PyType_GenericNew var1 = var var2 = var var3 = var

How many instances do I have ?

var1 = PyType_GenericNew var2 = PyType_GenericNew var3 = PyType_GenericNew

How many instances do I have now ?

If the above is /not/ what actually happens (as I described in "1)" and "2)" ) than please do explain.

Regards, Rudy Wieser

Reply to
R.Wieser

OK I haven't programmed C for a quarter of a century, but isn't that just assigning a function pointer to a field. As I recall C doesn't have function "objects" so it doesn't instantiate an object for a function pointer, a function pointer is just a pointer to the function.

Please ignore me if I have totally missed the point.

Reply to
Pancho

You don?t seem to be paying attention to the answers.

It doesn?t create an instance of anything. It just sets tp_new to PyType_GenericNew.

Instances of the PWM type are created by calling tp_new with &PWMType as is first argument (plus some other details). In both cases, tp_new is set to PyType_GenericNew. The number of instances of the PWM type created is the same as the number of calls.

Neither way of setting tp_new creates anything. They both just set the value of tp_new to PyType_GenericNew. I have no idea why you think it does anything else.

The number of calls through tp_new is precisely the same as the number of PWM instances created.

--
https://www.greenend.org.uk/rjk/
Reply to
Richard Kettlewell

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.